699 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			699 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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;
 | |
| }
 |