Merge changes from topic "adb-mdns-cmdline" am: 8cab9b6b24 am: d9c0176f1f
Change-Id: Ic290b50817b53ba09f24c5aaae9e92605afcedcc
This commit is contained in:
commit
f751d65fdd
6 changed files with 201 additions and 9 deletions
23
adb/adb.cpp
23
adb/adb.cpp
|
|
@ -1076,6 +1076,25 @@ void adb_set_reject_kill_server(bool value) {
|
||||||
g_reject_kill_server = value;
|
g_reject_kill_server = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool handle_mdns_request(std::string_view service, int reply_fd) {
|
||||||
|
if (!android::base::ConsumePrefix(&service, "mdns:")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service == "check") {
|
||||||
|
std::string check = mdns_check();
|
||||||
|
SendOkay(reply_fd, check);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (service == "services") {
|
||||||
|
std::string services_list = mdns_list_discovered_services();
|
||||||
|
SendOkay(reply_fd, services_list);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
HostRequestResult handle_host_request(std::string_view service, TransportType type,
|
HostRequestResult handle_host_request(std::string_view service, TransportType type,
|
||||||
const char* serial, TransportId transport_id, int reply_fd,
|
const char* serial, TransportId transport_id, int reply_fd,
|
||||||
asocket* s) {
|
asocket* s) {
|
||||||
|
|
@ -1320,6 +1339,10 @@ HostRequestResult handle_host_request(std::string_view service, TransportType ty
|
||||||
return HostRequestResult::Handled;
|
return HostRequestResult::Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (handle_mdns_request(service, reply_fd)) {
|
||||||
|
return HostRequestResult::Handled;
|
||||||
|
}
|
||||||
|
|
||||||
return HostRequestResult::Unhandled;
|
return HostRequestResult::Unhandled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,9 @@ void adb_wifi_pair_device(const std::string& host, const std::string& password,
|
||||||
std::string& response);
|
std::string& response);
|
||||||
bool adb_wifi_is_known_host(const std::string& host);
|
bool adb_wifi_is_known_host(const std::string& host);
|
||||||
|
|
||||||
|
std::string mdns_check();
|
||||||
|
std::string mdns_list_discovered_services();
|
||||||
|
|
||||||
#else // !ADB_HOST
|
#else // !ADB_HOST
|
||||||
|
|
||||||
struct AdbdAuthContext;
|
struct AdbdAuthContext;
|
||||||
|
|
|
||||||
|
|
@ -90,8 +90,9 @@ extern const char* _Nullable * _Nullable __adb_envp;
|
||||||
|
|
||||||
// ADB Secure DNS service interface. Used to query what ADB Secure DNS services have been
|
// ADB Secure DNS service interface. Used to query what ADB Secure DNS services have been
|
||||||
// resolved, and to run some kind of callback for each one.
|
// resolved, and to run some kind of callback for each one.
|
||||||
using adb_secure_foreach_service_callback = std::function<void(
|
using adb_secure_foreach_service_callback =
|
||||||
const char* _Nonnull service_name, const char* _Nonnull ip_address, uint16_t port)>;
|
std::function<void(const char* _Nonnull service_name, const char* _Nonnull reg_type,
|
||||||
|
const char* _Nonnull ip_address, uint16_t port)>;
|
||||||
|
|
||||||
// Queries pairing/connect services that have been discovered and resolved.
|
// Queries pairing/connect services that have been discovered and resolved.
|
||||||
// If |host_name| is not null, run |cb| only for services
|
// If |host_name| is not null, run |cb| only for services
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,8 @@ static void help() {
|
||||||
" localfilesystem:<unix domain socket name>\n"
|
" localfilesystem:<unix domain socket name>\n"
|
||||||
" reverse --remove REMOTE remove specific reverse socket connection\n"
|
" reverse --remove REMOTE remove specific reverse socket connection\n"
|
||||||
" reverse --remove-all remove all reverse socket connections from device\n"
|
" reverse --remove-all remove all reverse socket connections from device\n"
|
||||||
|
" mdns check check if mdns discovery is available\n"
|
||||||
|
" mdns services list all discovered services\n"
|
||||||
"\n"
|
"\n"
|
||||||
"file transfer:\n"
|
"file transfer:\n"
|
||||||
" push [--sync] [-z ALGORITHM] [-Z] LOCAL... REMOTE\n"
|
" push [--sync] [-z ALGORITHM] [-Z] LOCAL... REMOTE\n"
|
||||||
|
|
@ -1910,6 +1912,29 @@ int adb_commandline(int argc, const char** argv) {
|
||||||
|
|
||||||
ReadOrderlyShutdown(fd);
|
ReadOrderlyShutdown(fd);
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (!strcmp(argv[0], "mdns")) {
|
||||||
|
--argc;
|
||||||
|
if (argc < 1) error_exit("mdns requires an argument");
|
||||||
|
++argv;
|
||||||
|
|
||||||
|
std::string error;
|
||||||
|
if (!adb_check_server_version(&error)) {
|
||||||
|
error_exit("failed to check server version: %s", error.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string query = "host:mdns:";
|
||||||
|
if (!strcmp(argv[0], "check")) {
|
||||||
|
if (argc != 1) error_exit("mdns %s doesn't take any arguments", argv[0]);
|
||||||
|
query += "check";
|
||||||
|
} else if (!strcmp(argv[0], "services")) {
|
||||||
|
if (argc != 1) error_exit("mdns %s doesn't take any arguments", argv[0]);
|
||||||
|
query += "services";
|
||||||
|
printf("List of discovered mdns services\n");
|
||||||
|
} else {
|
||||||
|
error_exit("unknown mdns command [%s]", argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return adb_query_command(query);
|
||||||
}
|
}
|
||||||
/* do_sync_*() commands */
|
/* do_sync_*() commands */
|
||||||
else if (!strcmp(argv[0], "ls")) {
|
else if (!strcmp(argv[0], "ls")) {
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,9 @@ class ResolvedService : public AsyncServiceRef {
|
||||||
|
|
||||||
int adbSecureServiceType = serviceIndex();
|
int adbSecureServiceType = serviceIndex();
|
||||||
switch (adbSecureServiceType) {
|
switch (adbSecureServiceType) {
|
||||||
|
case kADBTransportServiceRefIndex:
|
||||||
|
sAdbTransportServices->push_back(this);
|
||||||
|
break;
|
||||||
case kADBSecurePairingServiceRefIndex:
|
case kADBSecurePairingServiceRefIndex:
|
||||||
sAdbSecurePairingServices->push_back(this);
|
sAdbSecurePairingServices->push_back(this);
|
||||||
break;
|
break;
|
||||||
|
|
@ -233,16 +236,21 @@ class ResolvedService : public AsyncServiceRef {
|
||||||
|
|
||||||
std::string serviceName() const { return serviceName_; }
|
std::string serviceName() const { return serviceName_; }
|
||||||
|
|
||||||
|
std::string regType() const { return regType_; }
|
||||||
|
|
||||||
std::string ipAddress() const { return ip_addr_; }
|
std::string ipAddress() const { return ip_addr_; }
|
||||||
|
|
||||||
uint16_t port() const { return port_; }
|
uint16_t port() const { return port_; }
|
||||||
|
|
||||||
using ServiceRegistry = std::vector<ResolvedService*>;
|
using ServiceRegistry = std::vector<ResolvedService*>;
|
||||||
|
|
||||||
|
// unencrypted tcp connections
|
||||||
|
static ServiceRegistry* sAdbTransportServices;
|
||||||
|
|
||||||
static ServiceRegistry* sAdbSecurePairingServices;
|
static ServiceRegistry* sAdbSecurePairingServices;
|
||||||
static ServiceRegistry* sAdbSecureConnectServices;
|
static ServiceRegistry* sAdbSecureConnectServices;
|
||||||
|
|
||||||
static void initAdbSecure();
|
static void initAdbServiceRegistries();
|
||||||
|
|
||||||
static void forEachService(const ServiceRegistry& services, const std::string& hostname,
|
static void forEachService(const ServiceRegistry& services, const std::string& hostname,
|
||||||
adb_secure_foreach_service_callback cb);
|
adb_secure_foreach_service_callback cb);
|
||||||
|
|
@ -263,6 +271,9 @@ class ResolvedService : public AsyncServiceRef {
|
||||||
int serviceVersion_;
|
int serviceVersion_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// static
|
||||||
|
std::vector<ResolvedService*>* ResolvedService::sAdbTransportServices = NULL;
|
||||||
|
|
||||||
// static
|
// static
|
||||||
std::vector<ResolvedService*>* ResolvedService::sAdbSecurePairingServices = NULL;
|
std::vector<ResolvedService*>* ResolvedService::sAdbSecurePairingServices = NULL;
|
||||||
|
|
||||||
|
|
@ -270,7 +281,10 @@ std::vector<ResolvedService*>* ResolvedService::sAdbSecurePairingServices = NULL
|
||||||
std::vector<ResolvedService*>* ResolvedService::sAdbSecureConnectServices = NULL;
|
std::vector<ResolvedService*>* ResolvedService::sAdbSecureConnectServices = NULL;
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void ResolvedService::initAdbSecure() {
|
void ResolvedService::initAdbServiceRegistries() {
|
||||||
|
if (!sAdbTransportServices) {
|
||||||
|
sAdbTransportServices = new ServiceRegistry;
|
||||||
|
}
|
||||||
if (!sAdbSecurePairingServices) {
|
if (!sAdbSecurePairingServices) {
|
||||||
sAdbSecurePairingServices = new ServiceRegistry;
|
sAdbSecurePairingServices = new ServiceRegistry;
|
||||||
}
|
}
|
||||||
|
|
@ -283,17 +297,18 @@ void ResolvedService::initAdbSecure() {
|
||||||
void ResolvedService::forEachService(const ServiceRegistry& services,
|
void ResolvedService::forEachService(const ServiceRegistry& services,
|
||||||
const std::string& wanted_service_name,
|
const std::string& wanted_service_name,
|
||||||
adb_secure_foreach_service_callback cb) {
|
adb_secure_foreach_service_callback cb) {
|
||||||
initAdbSecure();
|
initAdbServiceRegistries();
|
||||||
|
|
||||||
for (auto service : services) {
|
for (auto service : services) {
|
||||||
auto service_name = service->serviceName();
|
auto service_name = service->serviceName();
|
||||||
|
auto reg_type = service->regType();
|
||||||
auto ip = service->ipAddress();
|
auto ip = service->ipAddress();
|
||||||
auto port = service->port();
|
auto port = service->port();
|
||||||
|
|
||||||
if (wanted_service_name == "") {
|
if (wanted_service_name == "") {
|
||||||
cb(service_name.c_str(), ip.c_str(), port);
|
cb(service_name.c_str(), reg_type.c_str(), ip.c_str(), port);
|
||||||
} else if (service_name == wanted_service_name) {
|
} else if (service_name == wanted_service_name) {
|
||||||
cb(service_name.c_str(), ip.c_str(), port);
|
cb(service_name.c_str(), reg_type.c_str(), ip.c_str(), port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -301,7 +316,7 @@ void ResolvedService::forEachService(const ServiceRegistry& services,
|
||||||
// static
|
// static
|
||||||
bool ResolvedService::connectByServiceName(const ServiceRegistry& services,
|
bool ResolvedService::connectByServiceName(const ServiceRegistry& services,
|
||||||
const std::string& service_name) {
|
const std::string& service_name) {
|
||||||
initAdbSecure();
|
initAdbServiceRegistries();
|
||||||
for (auto service : services) {
|
for (auto service : services) {
|
||||||
if (service_name == service->serviceName()) {
|
if (service_name == service->serviceName()) {
|
||||||
D("Got service_name match [%s]", service->serviceName().c_str());
|
D("Got service_name match [%s]", service->serviceName().c_str());
|
||||||
|
|
@ -398,6 +413,9 @@ static void adb_RemoveDNSService(const char* regType, const char* serviceName) {
|
||||||
int index = adb_DNSServiceIndexByName(regType);
|
int index = adb_DNSServiceIndexByName(regType);
|
||||||
ResolvedService::ServiceRegistry* services;
|
ResolvedService::ServiceRegistry* services;
|
||||||
switch (index) {
|
switch (index) {
|
||||||
|
case kADBTransportServiceRefIndex:
|
||||||
|
services = ResolvedService::sAdbTransportServices;
|
||||||
|
break;
|
||||||
case kADBSecurePairingServiceRefIndex:
|
case kADBSecurePairingServiceRefIndex:
|
||||||
services = ResolvedService::sAdbSecurePairingServices;
|
services = ResolvedService::sAdbSecurePairingServices;
|
||||||
break;
|
break;
|
||||||
|
|
@ -542,6 +560,34 @@ void init_mdns_transport_discovery_thread(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_mdns_transport_discovery(void) {
|
void init_mdns_transport_discovery(void) {
|
||||||
ResolvedService::initAdbSecure();
|
ResolvedService::initAdbServiceRegistries();
|
||||||
std::thread(init_mdns_transport_discovery_thread).detach();
|
std::thread(init_mdns_transport_discovery_thread).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string mdns_check() {
|
||||||
|
uint32_t daemon_version;
|
||||||
|
uint32_t sz = sizeof(daemon_version);
|
||||||
|
|
||||||
|
auto dnserr = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &daemon_version, &sz);
|
||||||
|
std::string result = "ERROR: mdns daemon unavailable";
|
||||||
|
if (dnserr != kDNSServiceErr_NoError) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = android::base::StringPrintf("mdns daemon version [%u]", daemon_version);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string mdns_list_discovered_services() {
|
||||||
|
std::string result;
|
||||||
|
auto cb = [&](const char* service_name, const char* reg_type, const char* ip_addr,
|
||||||
|
uint16_t port) {
|
||||||
|
result += android::base::StringPrintf("%s\t%s\t%s:%u\n", service_name, reg_type, ip_addr,
|
||||||
|
port);
|
||||||
|
};
|
||||||
|
|
||||||
|
ResolvedService::forEachService(*ResolvedService::sAdbTransportServices, "", cb);
|
||||||
|
ResolvedService::forEachService(*ResolvedService::sAdbSecureConnectServices, "", cb);
|
||||||
|
ResolvedService::forEachService(*ResolvedService::sAdbSecurePairingServices, "", cb);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ import threading
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
import warnings
|
import warnings
|
||||||
|
from importlib import util
|
||||||
|
from parameterized import parameterized_class
|
||||||
|
|
||||||
def find_open_port():
|
def find_open_port():
|
||||||
# Find an open port.
|
# Find an open port.
|
||||||
|
|
@ -576,6 +578,98 @@ class PowerTest(unittest.TestCase):
|
||||||
# If the power event was detected, the adb shell command should be broken very quickly.
|
# If the power event was detected, the adb shell command should be broken very quickly.
|
||||||
self.assertLess(end - start, 2)
|
self.assertLess(end - start, 2)
|
||||||
|
|
||||||
|
"""Use 'adb mdns check' to see if mdns discovery is available."""
|
||||||
|
def is_adb_mdns_available():
|
||||||
|
with adb_server() as server_port:
|
||||||
|
output = subprocess.check_output(["adb", "-P", str(server_port),
|
||||||
|
"mdns", "check"]).strip()
|
||||||
|
return output.startswith(b"mdns daemon version")
|
||||||
|
|
||||||
|
"""Check if we have zeroconf python library installed"""
|
||||||
|
def is_zeroconf_installed():
|
||||||
|
zeroconf_spec = util.find_spec("zeroconf")
|
||||||
|
return zeroconf_spec is not None
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def zeroconf_context(ipversion):
|
||||||
|
from zeroconf import Zeroconf
|
||||||
|
"""Context manager for a zeroconf instance
|
||||||
|
|
||||||
|
This creates a zeroconf instance and returns it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
zeroconf = Zeroconf(ip_version=ipversion)
|
||||||
|
yield zeroconf
|
||||||
|
finally:
|
||||||
|
zeroconf.close()
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def zeroconf_register_service(zeroconf_ctx, info):
|
||||||
|
"""Context manager for a zeroconf service
|
||||||
|
|
||||||
|
Registers a service and unregisters it on cleanup. Returns the ServiceInfo
|
||||||
|
supplied.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
zeroconf_ctx.register_service(info)
|
||||||
|
yield info
|
||||||
|
finally:
|
||||||
|
zeroconf_ctx.unregister_service(info)
|
||||||
|
|
||||||
|
"""Should match the service names listed in adb_mdns.h"""
|
||||||
|
@parameterized_class(('service_name',), [
|
||||||
|
("adb",),
|
||||||
|
("adb-tls-connect",),
|
||||||
|
("adb-tls-pairing",),
|
||||||
|
])
|
||||||
|
@unittest.skipIf(not is_adb_mdns_available(), "mdns feature not available")
|
||||||
|
class MdnsTest(unittest.TestCase):
|
||||||
|
"""Tests for adb mdns."""
|
||||||
|
|
||||||
|
@unittest.skipIf(not is_zeroconf_installed(), "zeroconf library not installed")
|
||||||
|
def test_mdns_services_register_unregister(self):
|
||||||
|
"""Ensure that `adb mdns services` correctly adds and removes a service
|
||||||
|
"""
|
||||||
|
from zeroconf import IPVersion, ServiceInfo
|
||||||
|
|
||||||
|
def _mdns_services(port):
|
||||||
|
output = subprocess.check_output(["adb", "-P", str(port), "mdns", "services"])
|
||||||
|
return [x.split("\t") for x in output.decode("utf8").strip().splitlines()[1:]]
|
||||||
|
|
||||||
|
with adb_server() as server_port:
|
||||||
|
output = subprocess.check_output(["adb", "-P", str(server_port),
|
||||||
|
"mdns", "services"]).strip()
|
||||||
|
self.assertTrue(output.startswith(b"List of discovered mdns services"))
|
||||||
|
print(f"services={_mdns_services(server_port)}")
|
||||||
|
|
||||||
|
"""TODO(joshuaduong): Add ipv6 tests once we have it working in adb"""
|
||||||
|
"""Register/Unregister a service"""
|
||||||
|
with zeroconf_context(IPVersion.V4Only) as zc:
|
||||||
|
serv_instance = "my_fake_test_service"
|
||||||
|
serv_type = "_" + self.service_name + "._tcp."
|
||||||
|
serv_ipaddr = socket.inet_aton("1.2.3.4")
|
||||||
|
serv_port = 12345
|
||||||
|
service_info = ServiceInfo(
|
||||||
|
serv_type + "local.",
|
||||||
|
name=serv_instance + "." + serv_type + "local.",
|
||||||
|
addresses=[serv_ipaddr],
|
||||||
|
port=serv_port)
|
||||||
|
print(f"Registering {serv_instance}.{serv_type} ...")
|
||||||
|
with zeroconf_register_service(zc, service_info) as info:
|
||||||
|
"""Give adb some time to register the service"""
|
||||||
|
time.sleep(0.25)
|
||||||
|
print(f"services={_mdns_services(server_port)}")
|
||||||
|
self.assertTrue(any((serv_instance in line and serv_type in line)
|
||||||
|
for line in _mdns_services(server_port)))
|
||||||
|
|
||||||
|
"""Give adb some time to unregister the service"""
|
||||||
|
print("Unregistering mdns service...")
|
||||||
|
time.sleep(0.25)
|
||||||
|
print(f"services={_mdns_services(server_port)}")
|
||||||
|
self.assertFalse(any((serv_instance in line and serv_type in line)
|
||||||
|
for line in _mdns_services(server_port)))
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Main entrypoint."""
|
"""Main entrypoint."""
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue