| /* |
| * Copyright (C) 2020 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define TRACE_TAG TRANSPORT |
| |
| #include "transport.h" |
| |
| #ifdef _WIN32 |
| #include <winsock2.h> |
| #else |
| #include <arpa/inet.h> |
| #endif |
| |
| #include <memory> |
| #include <thread> |
| #include <vector> |
| |
| #include <android-base/stringprintf.h> |
| #include <android-base/strings.h> |
| #include <dns_sd.h> |
| |
| #include "adb_client.h" |
| #include "adb_mdns.h" |
| #include "adb_trace.h" |
| #include "adb_utils.h" |
| #include "adb_wifi.h" |
| #include "client/mdns_utils.h" |
| #include "fdevent/fdevent.h" |
| #include "sysdeps.h" |
| |
| // TODO: Remove this file once openscreen has bonjour client APIs implemented. |
| namespace { |
| |
| DNSServiceRef g_service_refs[kNumADBDNSServices]; |
| fdevent* g_service_ref_fdes[kNumADBDNSServices]; |
| |
| // Use adb_DNSServiceRefSockFD() instead of calling DNSServiceRefSockFD() |
| // directly so that the socket is put through the appropriate compatibility |
| // layers to work with the rest of ADB's internal APIs. |
| int adb_DNSServiceRefSockFD(DNSServiceRef ref) { |
| return adb_register_socket(DNSServiceRefSockFD(ref)); |
| } |
| #define DNSServiceRefSockFD ___xxx_DNSServiceRefSockFD |
| |
| void DNSSD_API register_service_ip(DNSServiceRef sdref, DNSServiceFlags flags, |
| uint32_t interface_index, DNSServiceErrorType error_code, |
| const char* hostname, const sockaddr* address, uint32_t ttl, |
| void* context); |
| |
| void pump_service_ref(int /*fd*/, unsigned ev, void* data) { |
| DNSServiceRef* ref = reinterpret_cast<DNSServiceRef*>(data); |
| |
| if (ev & FDE_READ) DNSServiceProcessResult(*ref); |
| } |
| |
| class AsyncServiceRef { |
| public: |
| bool Initialized() const { return initialized_; } |
| |
| void DestroyServiceRef() { |
| if (!initialized_) { |
| return; |
| } |
| |
| // Order matters here! Must destroy the fdevent first since it has a |
| // reference to |sdref_|. |
| fdevent_destroy(fde_); |
| D("DNSServiceRefDeallocate(sdref=%p)", sdref_); |
| DNSServiceRefDeallocate(sdref_); |
| initialized_ = false; |
| } |
| |
| virtual ~AsyncServiceRef() { DestroyServiceRef(); } |
| |
| protected: |
| DNSServiceRef sdref_; |
| |
| void Initialize() { |
| fde_ = fdevent_create(adb_DNSServiceRefSockFD(sdref_), pump_service_ref, &sdref_); |
| if (fde_ == nullptr) { |
| D("Unable to create fdevent"); |
| return; |
| } |
| fdevent_set(fde_, FDE_READ); |
| initialized_ = true; |
| } |
| |
| private: |
| bool initialized_ = false; |
| fdevent* fde_; |
| }; |
| |
| class ResolvedService : public AsyncServiceRef { |
| public: |
| virtual ~ResolvedService() = default; |
| |
| ResolvedService(const std::string& service_name, const std::string& reg_type, |
| uint32_t interface_index, const std::string& host_target, uint16_t port, |
| int version) |
| : service_name_(service_name), |
| reg_type_(reg_type), |
| host_target_(host_target), |
| port_(port), |
| sa_family_(0), |
| service_version_(version) { |
| /* TODO: We should be able to get IPv6 support by adding |
| * kDNSServiceProtocol_IPv6 to the flags below. However, when we do |
| * this, we get served link-local addresses that are usually useless to |
| * connect to. What's more, we seem to /only/ get those and nothing else. |
| * If we want IPv6 in the future we'll have to figure out why. |
| */ |
| DNSServiceErrorType ret = DNSServiceGetAddrInfo( |
| &sdref_, 0, interface_index, kDNSServiceProtocol_IPv4, host_target_.c_str(), |
| register_service_ip, reinterpret_cast<void*>(this)); |
| |
| if (ret != kDNSServiceErr_NoError) { |
| D("Got %d from DNSServiceGetAddrInfo.", ret); |
| } else { |
| D("DNSServiceGetAddrInfo(sdref=%p, host_target=%s)", sdref_, host_target_.c_str()); |
| Initialize(); |
| } |
| |
| D("Client version: %d Service version: %d\n", clientVersion_, service_version_); |
| } |
| |
| bool ConnectSecureWifiDevice() { |
| if (!adb_wifi_is_known_host(service_name_)) { |
| LOG(INFO) << "service_name=" << service_name_ << " not in keystore"; |
| return false; |
| } |
| |
| std::string response; |
| connect_device( |
| android::base::StringPrintf("%s.%s", service_name_.c_str(), reg_type_.c_str()), |
| &response); |
| D("Secure connect to %s regtype %s (%s:%hu) : %s", service_name_.c_str(), reg_type_.c_str(), |
| ip_addr_.c_str(), port_, response.c_str()); |
| return true; |
| } |
| |
| bool RegisterIpAddress(const sockaddr* address) { |
| sa_family_ = address->sa_family; |
| |
| const void* ip_addr_data; |
| if (sa_family_ == AF_INET) { |
| ip_addr_data = &reinterpret_cast<const sockaddr_in*>(address)->sin_addr; |
| addr_format_ = "%s:%hu"; |
| } else if (sa_family_ == AF_INET6) { |
| ip_addr_data = &reinterpret_cast<const sockaddr_in6*>(address)->sin6_addr; |
| addr_format_ = "[%s]:%hu"; |
| } else { // Should be impossible |
| D("mDNS resolved non-IP address."); |
| return false; |
| } |
| |
| // Winsock version requires the const cast mingw defines inet_ntop differently from msvc. |
| char ip_addr[INET6_ADDRSTRLEN] = {}; |
| if (!inet_ntop(sa_family_, const_cast<void*>(ip_addr_data), ip_addr, sizeof(ip_addr))) { |
| D("Could not convert IP address to string."); |
| return false; |
| } |
| ip_addr_ = ip_addr; |
| |
| return true; |
| } |
| |
| static void AddToServiceRegistry(std::unique_ptr<ResolvedService> service) { |
| // Add to the service registry before trying to auto-connect, since socket_spec_connect will |
| // check these registries for the ip address when connecting via mdns instance name. |
| auto service_index = service->service_index(); |
| if (!service_index) { |
| return; |
| } |
| |
| // Remove any services with the same instance name, as it may be a stale registration. |
| RemoveDNSService(service->reg_type(), service->service_name()); |
| |
| ServiceRegistry* services = nullptr; |
| switch (*service_index) { |
| case kADBTransportServiceRefIndex: |
| services = sAdbTransportServices; |
| break; |
| case kADBSecurePairingServiceRefIndex: |
| services = sAdbSecurePairingServices; |
| break; |
| case kADBSecureConnectServiceRefIndex: |
| services = sAdbSecureConnectServices; |
| break; |
| default: |
| LOG(WARNING) << "No registry available for reg_type=[" << service->reg_type() |
| << "]"; |
| return; |
| } |
| |
| services->push_back(std::move(service)); |
| const auto& s = services->back(); |
| |
| auto reg_type = s->reg_type(); |
| auto service_name = s->service_name(); |
| |
| auto ip_addr = s->ip_address(); |
| auto port = s->port(); |
| if (adb_DNSServiceShouldAutoConnect(reg_type, service_name)) { |
| std::string response; |
| D("Attempting to connect service_name=[%s], regtype=[%s] ip_addr=(%s:%hu)", |
| service_name.c_str(), reg_type.c_str(), ip_addr.c_str(), port); |
| |
| if (*service_index == kADBSecureConnectServiceRefIndex) { |
| s->ConnectSecureWifiDevice(); |
| } else { |
| connect_device(android::base::StringPrintf("%s.%s", service_name.c_str(), |
| reg_type.c_str()), |
| &response); |
| D("Connect to %s regtype %s (%s:%hu) : %s", service_name.c_str(), reg_type.c_str(), |
| ip_addr.c_str(), port, response.c_str()); |
| } |
| } else { |
| D("Not immediately connecting to service_name=[%s], regtype=[%s] ip_addr=(%s:%hu)", |
| service_name.c_str(), reg_type.c_str(), ip_addr.c_str(), port); |
| } |
| } |
| |
| std::optional<int> service_index() const { |
| return adb_DNSServiceIndexByName(reg_type_.c_str()); |
| } |
| |
| const std::string& host_target() const { return host_target_; } |
| |
| const std::string& service_name() const { return service_name_; } |
| |
| const std::string& reg_type() const { return reg_type_; } |
| |
| const std::string& ip_address() const { return ip_addr_; } |
| |
| uint16_t port() const { return port_; } |
| |
| using ServiceRegistry = std::vector<std::unique_ptr<ResolvedService>>; |
| |
| // unencrypted tcp connections |
| static ServiceRegistry* sAdbTransportServices; |
| |
| static ServiceRegistry* sAdbSecurePairingServices; |
| static ServiceRegistry* sAdbSecureConnectServices; |
| |
| static void InitAdbServiceRegistries(); |
| |
| static void ForEachService(const ServiceRegistry& services, const std::string& hostname, |
| adb_secure_foreach_service_callback cb); |
| |
| static bool ConnectByServiceName(const ServiceRegistry& services, |
| const std::string& service_name); |
| |
| static void RemoveDNSService(const std::string& reg_type, const std::string& service_name); |
| |
| private: |
| int clientVersion_ = ADB_SECURE_CLIENT_VERSION; |
| std::string addr_format_; |
| std::string service_name_; |
| std::string reg_type_; |
| std::string host_target_; |
| const uint16_t port_; |
| int sa_family_; |
| std::string ip_addr_; |
| int service_version_; |
| }; |
| |
| // static |
| ResolvedService::ServiceRegistry* ResolvedService::sAdbTransportServices = NULL; |
| |
| // static |
| ResolvedService::ServiceRegistry* ResolvedService::sAdbSecurePairingServices = NULL; |
| |
| // static |
| ResolvedService::ServiceRegistry* ResolvedService::sAdbSecureConnectServices = NULL; |
| |
| // static |
| void ResolvedService::InitAdbServiceRegistries() { |
| if (!sAdbTransportServices) { |
| sAdbTransportServices = new ServiceRegistry; |
| } |
| if (!sAdbSecurePairingServices) { |
| sAdbSecurePairingServices = new ServiceRegistry; |
| } |
| if (!sAdbSecureConnectServices) { |
| sAdbSecureConnectServices = new ServiceRegistry; |
| } |
| } |
| |
| // static |
| void ResolvedService::ForEachService(const ServiceRegistry& services, |
| const std::string& wanted_service_name, |
| adb_secure_foreach_service_callback cb) { |
| InitAdbServiceRegistries(); |
| |
| for (const auto& service : services) { |
| auto service_name = service->service_name(); |
| auto reg_type = service->reg_type(); |
| auto ip = service->ip_address(); |
| auto port = service->port(); |
| |
| if (wanted_service_name.empty()) { |
| cb(service_name.c_str(), reg_type.c_str(), ip.c_str(), port); |
| } else if (service_name == wanted_service_name) { |
| cb(service_name.c_str(), reg_type.c_str(), ip.c_str(), port); |
| } |
| } |
| } |
| |
| // static |
| bool ResolvedService::ConnectByServiceName(const ServiceRegistry& services, |
| const std::string& service_name) { |
| InitAdbServiceRegistries(); |
| for (const auto& service : services) { |
| auto wanted_name = service->service_name(); |
| if (wanted_name == service_name) { |
| D("Got service_name match [%s]", wanted_name.c_str()); |
| return service->ConnectSecureWifiDevice(); |
| } |
| } |
| D("No registered service_names matched [%s]", service_name.c_str()); |
| return false; |
| } |
| |
| // static |
| void ResolvedService::RemoveDNSService(const std::string& reg_type, |
| const std::string& service_name) { |
| D("%s: reg_type=[%s] service_name=[%s]", __func__, reg_type.c_str(), service_name.c_str()); |
| auto index = adb_DNSServiceIndexByName(reg_type); |
| if (!index) { |
| return; |
| } |
| ServiceRegistry* services; |
| switch (*index) { |
| case kADBTransportServiceRefIndex: |
| services = sAdbTransportServices; |
| break; |
| case kADBSecurePairingServiceRefIndex: |
| services = sAdbSecurePairingServices; |
| break; |
| case kADBSecureConnectServiceRefIndex: |
| services = sAdbSecureConnectServices; |
| break; |
| default: |
| return; |
| } |
| |
| if (services->empty()) { |
| return; |
| } |
| |
| services->erase(std::remove_if(services->begin(), services->end(), |
| [&service_name](std::unique_ptr<ResolvedService>& service) { |
| return (service_name == service->service_name()); |
| }), |
| services->end()); |
| } |
| |
| void DNSSD_API register_service_ip(DNSServiceRef sdref, DNSServiceFlags flags, |
| uint32_t /*interface_index*/, DNSServiceErrorType error_code, |
| const char* hostname, const sockaddr* address, uint32_t ttl, |
| void* context) { |
| D("%s: sdref=%p flags=0x%08x error_code=%u ttl=%u", __func__, sdref, flags, error_code, ttl); |
| std::unique_ptr<ResolvedService> data(static_cast<ResolvedService*>(context)); |
| // Only resolve the address once. If the address or port changes, we'll just get another |
| // registration. |
| data->DestroyServiceRef(); |
| |
| if (error_code != kDNSServiceErr_NoError) { |
| D("Got error while looking up ip_addr [%u]", error_code); |
| return; |
| } |
| |
| if (flags & kDNSServiceFlagsAdd) { |
| if (data->RegisterIpAddress(address)) { |
| D("Resolved IP address for [%s]. Adding to service registry.", hostname); |
| ResolvedService::AddToServiceRegistry(std::move(data)); |
| } |
| } |
| } |
| |
| void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdref, DNSServiceFlags flags, |
| uint32_t interface_index, |
| DNSServiceErrorType error_code, const char* fullname, |
| const char* host_target, uint16_t port, |
| uint16_t txt_len, const unsigned char* txt_record, |
| void* context); |
| |
| class DiscoveredService : public AsyncServiceRef { |
| public: |
| DiscoveredService(uint32_t interface_index, const char* service_name, const char* regtype, |
| const char* domain) |
| : service_name_(service_name), reg_type_(regtype) { |
| DNSServiceErrorType ret = |
| DNSServiceResolve(&sdref_, 0, interface_index, service_name, regtype, domain, |
| register_resolved_mdns_service, reinterpret_cast<void*>(this)); |
| |
| D("DNSServiceResolve for " |
| "interface_index %u " |
| "service_name %s " |
| "regtype %s " |
| "domain %s " |
| ": %d", |
| interface_index, service_name, regtype, domain, ret); |
| |
| if (ret == kDNSServiceErr_NoError) { |
| Initialize(); |
| } |
| } |
| |
| const std::string& service_name() { return service_name_; } |
| |
| const std::string& reg_type() { return reg_type_; } |
| |
| private: |
| std::string service_name_; |
| std::string reg_type_; |
| }; |
| |
| // Returns the version the device wanted to advertise, |
| // or -1 if parsing fails. |
| int ParseVersionFromTxtRecord(uint16_t txt_len, const unsigned char* txt_record) { |
| if (!txt_len) return -1; |
| if (!txt_record) return -1; |
| |
| // https://tools.ietf.org/html/rfc6763 |
| // """ |
| // 6.1. General Format Rules for DNS TXT Records |
| // |
| // A DNS TXT record can be up to 65535 (0xFFFF) bytes long. The total |
| // length is indicated by the length given in the resource record header |
| // in the DNS message. There is no way to tell directly from the data |
| // alone how long it is (e.g., there is no length count at the start, or |
| // terminating NULL byte at the end). |
| // """ |
| |
| // Let's trust the TXT record's length byte |
| // Worst case, it wastes 255 bytes |
| std::vector<char> record_str(txt_len + 1, '\0'); |
| char* str = record_str.data(); |
| |
| memcpy(str, txt_record + 1 /* skip the length byte */, txt_len); |
| |
| // Check if it's the version key |
| static const char* version_key = "v="; |
| size_t version_key_len = strlen(version_key); |
| |
| if (strncmp(version_key, str, version_key_len)) return -1; |
| |
| auto value_start = str + version_key_len; |
| |
| long parsed_number = strtol(value_start, 0, 10); |
| |
| // No valid conversion. Also, 0 |
| // is not a valid version. |
| if (!parsed_number) return -1; |
| |
| // Outside bounds of int. |
| if (parsed_number < INT_MIN || parsed_number > INT_MAX) return -1; |
| |
| // Possibly valid version |
| return static_cast<int>(parsed_number); |
| } |
| |
| void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdref, DNSServiceFlags flags, |
| uint32_t interface_index, |
| DNSServiceErrorType error_code, const char* fullname, |
| const char* host_target, uint16_t port, |
| uint16_t txt_len, const unsigned char* txt_record, |
| void* context) { |
| D("Resolved a service."); |
| std::unique_ptr<DiscoveredService> discovered(reinterpret_cast<DiscoveredService*>(context)); |
| |
| if (error_code != kDNSServiceErr_NoError) { |
| D("Got error %d resolving service.", error_code); |
| return; |
| } |
| |
| // TODO: Reject certain combinations of invalid or mismatched client and |
| // service versions here before creating anything. |
| // At the moment, there is nothing to reject, so accept everything |
| // as an optimistic default. |
| auto service_version = ParseVersionFromTxtRecord(txt_len, txt_record); |
| |
| auto resolved = new ResolvedService(discovered->service_name(), discovered->reg_type(), |
| interface_index, host_target, ntohs(port), service_version); |
| |
| if (!resolved->Initialized()) { |
| D("Unable to init resolved service"); |
| delete resolved; |
| } |
| |
| if (flags) { /* Only ever equals MoreComing or 0 */ |
| D("releasing discovered service"); |
| discovered.release(); |
| } |
| } |
| |
| void DNSSD_API on_service_browsed(DNSServiceRef sdref, DNSServiceFlags flags, |
| uint32_t interface_index, DNSServiceErrorType error_code, |
| const char* service_name, const char* regtype, const char* domain, |
| void* /*context*/) { |
| if (error_code != kDNSServiceErr_NoError) { |
| D("Got error %d during mDNS browse.", error_code); |
| DNSServiceRefDeallocate(sdref); |
| auto service_index = adb_DNSServiceIndexByName(regtype); |
| if (service_index) { |
| fdevent_destroy(g_service_ref_fdes[*service_index]); |
| } |
| return; |
| } |
| |
| if (flags & kDNSServiceFlagsAdd) { |
| D("%s: Discover found new service_name=[%s] regtype=[%s] domain=[%s]", __func__, |
| service_name, regtype, domain); |
| auto discovered = new DiscoveredService(interface_index, service_name, regtype, domain); |
| if (!discovered->Initialized()) { |
| delete discovered; |
| } |
| } else { |
| D("%s: Discover lost service_name=[%s] regtype=[%s] domain=[%s]", __func__, service_name, |
| regtype, domain); |
| ResolvedService::RemoveDNSService(regtype, service_name); |
| } |
| } |
| |
| void init_mdns_transport_discovery_thread(void) { |
| int error_codes[kNumADBDNSServices]; |
| for (int i = 0; i < kNumADBDNSServices; ++i) { |
| error_codes[i] = DNSServiceBrowse(&g_service_refs[i], 0, 0, kADBDNSServices[i], nullptr, |
| on_service_browsed, nullptr); |
| |
| if (error_codes[i] != kDNSServiceErr_NoError) { |
| D("Got %d browsing for mDNS service %s.", error_codes[i], kADBDNSServices[i]); |
| } else { |
| fdevent_run_on_main_thread([i]() { |
| g_service_ref_fdes[i] = fdevent_create(adb_DNSServiceRefSockFD(g_service_refs[i]), |
| pump_service_ref, &g_service_refs[i]); |
| fdevent_set(g_service_ref_fdes[i], FDE_READ); |
| }); |
| } |
| } |
| } |
| |
| namespace MdnsResponder { |
| |
| bool adb_secure_connect_by_service_name(const std::string& instance_name) { |
| return ResolvedService::ConnectByServiceName(*ResolvedService::sAdbSecureConnectServices, |
| instance_name); |
| } |
| |
| std::string mdns_check() { |
| uint32_t daemon_version; |
| uint32_t sz = sizeof(daemon_version); |
| |
| auto dnserr = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &daemon_version, &sz); |
| if (dnserr != kDNSServiceErr_NoError) { |
| return "ERROR: mdns daemon unavailable"; |
| } |
| |
| return android::base::StringPrintf("mdns daemon version [%u]", daemon_version); |
| } |
| |
| std::string mdns_list_discovered_services() { |
| std::string result; |
| auto cb = [&](const std::string& service_name, const std::string& reg_type, |
| const std::string& ip_addr, uint16_t port) { |
| result += android::base::StringPrintf("%s\t%s\t%s:%u\n", service_name.c_str(), |
| reg_type.c_str(), ip_addr.c_str(), port); |
| }; |
| |
| ResolvedService::ForEachService(*ResolvedService::sAdbTransportServices, "", cb); |
| ResolvedService::ForEachService(*ResolvedService::sAdbSecureConnectServices, "", cb); |
| ResolvedService::ForEachService(*ResolvedService::sAdbSecurePairingServices, "", cb); |
| return result; |
| } |
| |
| std::optional<MdnsInfo> mdns_get_connect_service_info(const std::string& name) { |
| CHECK(!name.empty()); |
| |
| // only adb server creates these registries |
| if (!ResolvedService::sAdbTransportServices && !ResolvedService::sAdbSecureConnectServices) { |
| return std::nullopt; |
| } |
| CHECK(ResolvedService::sAdbTransportServices); |
| CHECK(ResolvedService::sAdbSecureConnectServices); |
| |
| auto mdns_instance = mdns::mdns_parse_instance_name(name); |
| if (!mdns_instance.has_value()) { |
| D("Failed to parse mDNS name [%s]", name.c_str()); |
| return std::nullopt; |
| } |
| |
| std::optional<MdnsInfo> info; |
| auto cb = [&](const std::string& service_name, const std::string& reg_type, |
| const std::string& ip_addr, |
| uint16_t port) { info.emplace(service_name, reg_type, ip_addr, port); }; |
| |
| std::string reg_type; |
| if (!mdns_instance->service_name.empty()) { |
| reg_type = android::base::StringPrintf("%s.%s", mdns_instance->service_name.c_str(), |
| mdns_instance->transport_type.c_str()); |
| auto index = adb_DNSServiceIndexByName(reg_type); |
| if (!index) { |
| return std::nullopt; |
| } |
| switch (*index) { |
| case kADBTransportServiceRefIndex: |
| ResolvedService::ForEachService(*ResolvedService::sAdbTransportServices, |
| mdns_instance->instance_name, cb); |
| break; |
| case kADBSecureConnectServiceRefIndex: |
| ResolvedService::ForEachService(*ResolvedService::sAdbSecureConnectServices, |
| mdns_instance->instance_name, cb); |
| break; |
| default: |
| D("Unknown reg_type [%s]", reg_type.c_str()); |
| return std::nullopt; |
| } |
| return info; |
| } |
| |
| for (const auto& service : |
| {ResolvedService::sAdbTransportServices, ResolvedService::sAdbSecureConnectServices}) { |
| ResolvedService::ForEachService(*service, name, cb); |
| if (info.has_value()) { |
| return info; |
| } |
| } |
| |
| return std::nullopt; |
| } |
| |
| std::optional<MdnsInfo> mdns_get_pairing_service_info(const std::string& name) { |
| CHECK(!name.empty()); |
| |
| auto mdns_instance = mdns::mdns_parse_instance_name(name); |
| if (!mdns_instance.has_value()) { |
| D("Failed to parse mDNS pairing name [%s]", name.c_str()); |
| return std::nullopt; |
| } |
| |
| std::optional<MdnsInfo> info; |
| auto cb = [&](const std::string& service_name, const std::string& reg_type, |
| const std::string& ip_addr, |
| uint16_t port) { info.emplace(service_name, reg_type, ip_addr, port); }; |
| |
| // Verify it's a pairing service if user explicitly inputs it. |
| if (!mdns_instance->service_name.empty()) { |
| auto reg_type = android::base::StringPrintf("%s.%s", mdns_instance->service_name.c_str(), |
| mdns_instance->transport_type.c_str()); |
| auto index = adb_DNSServiceIndexByName(reg_type); |
| if (!index) { |
| return std::nullopt; |
| } |
| switch (*index) { |
| case kADBSecurePairingServiceRefIndex: |
| break; |
| default: |
| D("Not an adb pairing reg_type [%s]", reg_type.c_str()); |
| return std::nullopt; |
| } |
| } |
| |
| ResolvedService::ForEachService(*ResolvedService::sAdbSecurePairingServices, name, cb); |
| return info; |
| } |
| |
| void mdns_cleanup() {} |
| |
| } // namespace MdnsResponder |
| } // namespace |
| |
| AdbMdnsResponderFuncs StartMdnsResponderDiscovery() { |
| ResolvedService::InitAdbServiceRegistries(); |
| std::thread(init_mdns_transport_discovery_thread).detach(); |
| AdbMdnsResponderFuncs f = { |
| .mdns_check = MdnsResponder::mdns_check, |
| .mdns_list_discovered_services = MdnsResponder::mdns_list_discovered_services, |
| .mdns_get_connect_service_info = MdnsResponder::mdns_get_connect_service_info, |
| .mdns_get_pairing_service_info = MdnsResponder::mdns_get_pairing_service_info, |
| .mdns_cleanup = MdnsResponder::mdns_cleanup, |
| .adb_secure_connect_by_service_name = MdnsResponder::adb_secure_connect_by_service_name, |
| }; |
| return f; |
| } |