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