Home | History | Annotate | Download | only in adb
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define TRACE_TAG TRANSPORT
     18 
     19 #include "transport.h"
     20 
     21 #ifdef _WIN32
     22 #include <winsock2.h>
     23 #else
     24 #include <arpa/inet.h>
     25 #endif
     26 
     27 #include <thread>
     28 
     29 #include <android-base/stringprintf.h>
     30 #include <dns_sd.h>
     31 
     32 #include "adb_mdns.h"
     33 #include "adb_trace.h"
     34 #include "fdevent.h"
     35 #include "sysdeps.h"
     36 
     37 static DNSServiceRef service_ref;
     38 static fdevent service_ref_fde;
     39 
     40 // Use adb_DNSServiceRefSockFD() instead of calling DNSServiceRefSockFD()
     41 // directly so that the socket is put through the appropriate compatibility
     42 // layers to work with the rest of ADB's internal APIs.
     43 static inline int adb_DNSServiceRefSockFD(DNSServiceRef ref) {
     44     return adb_register_socket(DNSServiceRefSockFD(ref));
     45 }
     46 #define DNSServiceRefSockFD ___xxx_DNSServiceRefSockFD
     47 
     48 static void DNSSD_API register_service_ip(DNSServiceRef sdRef,
     49                                           DNSServiceFlags flags,
     50                                           uint32_t interfaceIndex,
     51                                           DNSServiceErrorType errorCode,
     52                                           const char* hostname,
     53                                           const sockaddr* address,
     54                                           uint32_t ttl,
     55                                           void* context);
     56 
     57 static void pump_service_ref(int /*fd*/, unsigned ev, void* data) {
     58     DNSServiceRef* ref = reinterpret_cast<DNSServiceRef*>(data);
     59 
     60     if (ev & FDE_READ)
     61         DNSServiceProcessResult(*ref);
     62 }
     63 
     64 class AsyncServiceRef {
     65   public:
     66     bool Initialized() {
     67         return initialized_;
     68     }
     69 
     70     virtual ~AsyncServiceRef() {
     71         if (! initialized_) {
     72             return;
     73         }
     74 
     75         DNSServiceRefDeallocate(sdRef_);
     76         fdevent_remove(&fde_);
     77     }
     78 
     79   protected:
     80     DNSServiceRef sdRef_;
     81 
     82     void Initialize() {
     83         fdevent_install(&fde_, adb_DNSServiceRefSockFD(sdRef_),
     84                         pump_service_ref, &sdRef_);
     85         fdevent_set(&fde_, FDE_READ);
     86         initialized_ = true;
     87     }
     88 
     89   private:
     90     bool initialized_;
     91     fdevent fde_;
     92 };
     93 
     94 class ResolvedService : public AsyncServiceRef {
     95   public:
     96     virtual ~ResolvedService() = default;
     97 
     98     ResolvedService(std::string name, uint32_t interfaceIndex,
     99                     const char* hosttarget, uint16_t port) :
    100             name_(name),
    101             port_(port) {
    102 
    103         /* TODO: We should be able to get IPv6 support by adding
    104          * kDNSServiceProtocol_IPv6 to the flags below. However, when we do
    105          * this, we get served link-local addresses that are usually useless to
    106          * connect to. What's more, we seem to /only/ get those and nothing else.
    107          * If we want IPv6 in the future we'll have to figure out why.
    108          */
    109         DNSServiceErrorType ret =
    110             DNSServiceGetAddrInfo(
    111                 &sdRef_, 0, interfaceIndex,
    112                 kDNSServiceProtocol_IPv4, hosttarget,
    113                 register_service_ip, reinterpret_cast<void*>(this));
    114 
    115         if (ret != kDNSServiceErr_NoError) {
    116             D("Got %d from DNSServiceGetAddrInfo.", ret);
    117         } else {
    118             Initialize();
    119         }
    120     }
    121 
    122     void Connect(const sockaddr* address) {
    123         char ip_addr[INET6_ADDRSTRLEN];
    124         const void* ip_addr_data;
    125         const char* addr_format;
    126 
    127         if (address->sa_family == AF_INET) {
    128             ip_addr_data =
    129                 &reinterpret_cast<const sockaddr_in*>(address)->sin_addr;
    130             addr_format = "%s:%hu";
    131         } else if (address->sa_family == AF_INET6) {
    132             ip_addr_data =
    133                 &reinterpret_cast<const sockaddr_in6*>(address)->sin6_addr;
    134             addr_format = "[%s]:%hu";
    135         } else { // Should be impossible
    136             D("mDNS resolved non-IP address.");
    137             return;
    138         }
    139 
    140         // Winsock version requires the const cast Because Microsoft.
    141         if (!inet_ntop(address->sa_family, const_cast<void*>(ip_addr_data),
    142                        ip_addr, INET6_ADDRSTRLEN)) {
    143             D("Could not convert IP address to string.");
    144             return;
    145         }
    146 
    147         std::string response;
    148         connect_device(android::base::StringPrintf(addr_format, ip_addr, port_),
    149                        &response);
    150         D("Connect to %s (%s:%hu) : %s", name_.c_str(), ip_addr, port_,
    151           response.c_str());
    152     }
    153 
    154   private:
    155     std::string name_;
    156     const uint16_t port_;
    157 };
    158 
    159 static void DNSSD_API register_service_ip(DNSServiceRef /*sdRef*/,
    160                                           DNSServiceFlags /*flags*/,
    161                                           uint32_t /*interfaceIndex*/,
    162                                           DNSServiceErrorType /*errorCode*/,
    163                                           const char* /*hostname*/,
    164                                           const sockaddr* address,
    165                                           uint32_t /*ttl*/,
    166                                           void* context) {
    167     D("Got IP for service.");
    168     std::unique_ptr<ResolvedService> data(
    169         reinterpret_cast<ResolvedService*>(context));
    170     data->Connect(address);
    171 }
    172 
    173 static void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,
    174                                                      DNSServiceFlags flags,
    175                                                      uint32_t interfaceIndex,
    176                                                      DNSServiceErrorType errorCode,
    177                                                      const char* fullname,
    178                                                      const char* hosttarget,
    179                                                      uint16_t port,
    180                                                      uint16_t txtLen,
    181                                                      const unsigned char* txtRecord,
    182                                                      void* context);
    183 
    184 class DiscoveredService : public AsyncServiceRef {
    185   public:
    186     DiscoveredService(uint32_t interfaceIndex, const char* serviceName,
    187                       const char* regtype, const char* domain)
    188         : serviceName_(serviceName) {
    189 
    190         DNSServiceErrorType ret =
    191             DNSServiceResolve(&sdRef_, 0, interfaceIndex, serviceName, regtype,
    192                               domain, register_resolved_mdns_service,
    193                               reinterpret_cast<void*>(this));
    194 
    195         if (ret != kDNSServiceErr_NoError) {
    196             D("Got %d from DNSServiceResolve.", ret);
    197         } else {
    198             Initialize();
    199         }
    200     }
    201 
    202     const char* ServiceName() {
    203         return serviceName_.c_str();
    204     }
    205 
    206   private:
    207     std::string serviceName_;
    208 };
    209 
    210 static void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,
    211                                                      DNSServiceFlags flags,
    212                                                      uint32_t interfaceIndex,
    213                                                      DNSServiceErrorType errorCode,
    214                                                      const char* fullname,
    215                                                      const char* hosttarget,
    216                                                      uint16_t port,
    217                                                      uint16_t /*txtLen*/,
    218                                                      const unsigned char* /*txtRecord*/,
    219                                                      void* context) {
    220     D("Resolved a service.");
    221     std::unique_ptr<DiscoveredService> discovered(
    222         reinterpret_cast<DiscoveredService*>(context));
    223 
    224     if (errorCode != kDNSServiceErr_NoError) {
    225         D("Got error %d resolving service.", errorCode);
    226         return;
    227     }
    228 
    229 
    230     auto resolved =
    231         new ResolvedService(discovered->ServiceName(),
    232                             interfaceIndex, hosttarget, ntohs(port));
    233 
    234     if (! resolved->Initialized()) {
    235         delete resolved;
    236     }
    237 
    238     if (flags) { /* Only ever equals MoreComing or 0 */
    239         discovered.release();
    240     }
    241 }
    242 
    243 static void DNSSD_API register_mdns_transport(DNSServiceRef sdRef,
    244                                               DNSServiceFlags flags,
    245                                               uint32_t interfaceIndex,
    246                                               DNSServiceErrorType errorCode,
    247                                               const char* serviceName,
    248                                               const char* regtype,
    249                                               const char* domain,
    250                                               void*  /*context*/) {
    251     D("Registering a transport.");
    252     if (errorCode != kDNSServiceErr_NoError) {
    253         D("Got error %d during mDNS browse.", errorCode);
    254         DNSServiceRefDeallocate(sdRef);
    255         fdevent_remove(&service_ref_fde);
    256         return;
    257     }
    258 
    259     auto discovered = new DiscoveredService(interfaceIndex, serviceName,
    260                                             regtype, domain);
    261 
    262     if (! discovered->Initialized()) {
    263         delete discovered;
    264     }
    265 }
    266 
    267 void init_mdns_transport_discovery_thread(void) {
    268     DNSServiceErrorType errorCode = DNSServiceBrowse(&service_ref, 0, 0, kADBServiceType, nullptr,
    269                                                      register_mdns_transport, nullptr);
    270 
    271     if (errorCode != kDNSServiceErr_NoError) {
    272         D("Got %d initiating mDNS browse.", errorCode);
    273         return;
    274     }
    275 
    276     fdevent_run_on_main_thread([]() {
    277         fdevent_install(&service_ref_fde, adb_DNSServiceRefSockFD(service_ref), pump_service_ref,
    278                         &service_ref);
    279         fdevent_set(&service_ref_fde, FDE_READ);
    280     });
    281 }
    282 
    283 void init_mdns_transport_discovery(void) {
    284     std::thread(init_mdns_transport_discovery_thread).detach();
    285 }
    286