Merge "Combine tcp_connect and socket_spec_connect."
This commit is contained in:
commit
539c4d427b
6 changed files with 79 additions and 83 deletions
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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 true;
|
||||||
}
|
}
|
||||||
return result;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@
|
||||||
#include "adb_io.h"
|
#include "adb_io.h"
|
||||||
#include "adb_unique_fd.h"
|
#include "adb_unique_fd.h"
|
||||||
#include "adb_utils.h"
|
#include "adb_utils.h"
|
||||||
|
#include "socket_spec.h"
|
||||||
#include "sysdeps/chrono.h"
|
#include "sysdeps/chrono.h"
|
||||||
|
|
||||||
#if ADB_HOST
|
#if ADB_HOST
|
||||||
|
|
@ -70,32 +71,17 @@ bool local_connect(int port) {
|
||||||
|
|
||||||
std::tuple<unique_fd, int, std::string> tcp_connect(const std::string& address,
|
std::tuple<unique_fd, int, std::string> tcp_connect(const std::string& address,
|
||||||
std::string* response) {
|
std::string* response) {
|
||||||
std::string serial;
|
unique_fd fd;
|
||||||
std::string host;
|
|
||||||
int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
|
int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
|
||||||
if (!android::base::ParseNetAddress(address, &host, &port, &serial, response)) {
|
std::string serial;
|
||||||
D("failed to parse address: '%s'", address.c_str());
|
if (socket_spec_connect(&fd, "tcp:" + address, &port, &serial, response)) {
|
||||||
return std::make_tuple(unique_fd(), port, serial);
|
close_on_exec(fd);
|
||||||
}
|
if (!set_tcp_keepalive(fd, 1)) {
|
||||||
|
D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
|
||||||
std::string error;
|
}
|
||||||
unique_fd fd(network_connect(host.c_str(), port, SOCK_STREAM, 10, &error));
|
|
||||||
if (fd == -1) {
|
|
||||||
*response = android::base::StringPrintf("unable to connect to %s: %s",
|
|
||||||
serial.c_str(), error.c_str());
|
|
||||||
return std::make_tuple(std::move(fd), port, serial);
|
return std::make_tuple(std::move(fd), port, serial);
|
||||||
}
|
}
|
||||||
|
return std::make_tuple(unique_fd(), 0, "");
|
||||||
D("client: connected %s remote on fd %d", serial.c_str(), fd.get());
|
|
||||||
close_on_exec(fd);
|
|
||||||
disable_tcp_nagle(fd);
|
|
||||||
|
|
||||||
// Send a TCP keepalive ping to the device every second so we can detect disconnects.
|
|
||||||
if (!set_tcp_keepalive(fd, 1)) {
|
|
||||||
D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_tuple(std::move(fd), port, serial);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void connect_device(const std::string& address, std::string* response) {
|
void connect_device(const std::string& address, std::string* response) {
|
||||||
|
|
@ -251,8 +237,9 @@ static void server_socket_thread(int port) {
|
||||||
adb_thread_setname("server socket");
|
adb_thread_setname("server socket");
|
||||||
D("transport: server_socket_thread() starting");
|
D("transport: server_socket_thread() starting");
|
||||||
while (serverfd == -1) {
|
while (serverfd == -1) {
|
||||||
|
std::string spec = android::base::StringPrintf("tcp:%d", port);
|
||||||
std::string error;
|
std::string error;
|
||||||
serverfd.reset(network_inaddr_any_server(port, SOCK_STREAM, &error));
|
serverfd.reset(socket_spec_listen(spec, &error));
|
||||||
if (serverfd < 0) {
|
if (serverfd < 0) {
|
||||||
D("server: cannot bind socket yet: %s", error.c_str());
|
D("server: cannot bind socket yet: %s", error.c_str());
|
||||||
std::this_thread::sleep_for(1s);
|
std::this_thread::sleep_for(1s);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue