blob: b63fc83b403ed1a7aac2a5495f517e7436680464 [file] [log] [blame]
Casey Dahlin13a269e2016-06-23 14:19:37 -07001/*
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#include <arpa/inet.h>
22
23#include <android-base/stringprintf.h>
24#include <dns_sd.h>
25
26#include "adb_mdns.h"
27#include "adb_trace.h"
28#include "fdevent.h"
29#include "sysdeps.h"
30
31static DNSServiceRef service_ref;
32static fdevent service_ref_fde;
33
34static void register_service_ip(DNSServiceRef sdRef,
35 DNSServiceFlags flags,
36 uint32_t interfaceIndex,
37 DNSServiceErrorType errorCode,
38 const char* hostname,
39 const sockaddr* address,
40 uint32_t ttl,
41 void* context);
42
43static void pump_service_ref(int /*fd*/, unsigned ev, void* data) {
44 DNSServiceRef* ref = reinterpret_cast<DNSServiceRef*>(data);
45
46 if (ev & FDE_READ)
47 DNSServiceProcessResult(*ref);
48}
49
50class AsyncServiceRef {
51 public:
52 bool Initialized() {
53 return initialized_;
54 }
55
56 virtual ~AsyncServiceRef() {
57 if (! initialized_) {
58 return;
59 }
60
61 DNSServiceRefDeallocate(sdRef_);
62 fdevent_remove(&fde_);
63 }
64
65 protected:
66 DNSServiceRef sdRef_;
67
68 void Initialize() {
69 fdevent_install(&fde_, DNSServiceRefSockFD(sdRef_),
70 pump_service_ref, &sdRef_);
71 fdevent_set(&fde_, FDE_READ);
72 initialized_ = true;
73 }
74
75 private:
76 bool initialized_;
77 fdevent fde_;
78};
79
80class ResolvedService : public AsyncServiceRef {
81 public:
82 virtual ~ResolvedService() = default;
83
84 ResolvedService(std::string name, uint32_t interfaceIndex,
85 const char* hosttarget, uint16_t port) :
86 name_(name),
87 port_(port) {
88 DNSServiceErrorType ret =
89 DNSServiceGetAddrInfo(
90 &sdRef_, 0, interfaceIndex,
91 kDNSServiceProtocol_IPv6|kDNSServiceProtocol_IPv4, hosttarget,
92 register_service_ip, reinterpret_cast<void*>(this));
93
94 if (ret != kDNSServiceErr_NoError) {
95 D("Got %d from DNSServiceGetAddrInfo.", ret);
96 } else {
97 Initialize();
98 }
99 }
100
101 void Connect(const sockaddr* address) {
102 char ip_addr[INET6_ADDRSTRLEN];
103 const void* ip_addr_data;
104 const char* addr_format;
105
106 if (address->sa_family == AF_INET) {
107 ip_addr_data =
108 &reinterpret_cast<const sockaddr_in*>(address)->sin_addr;
109 addr_format = "%s:%hu";
110 } else if (address->sa_family == AF_INET6) {
111 ip_addr_data =
112 &reinterpret_cast<const sockaddr_in6*>(address)->sin6_addr;
113 addr_format = "[%s]:%hu";
114 } else { // Should be impossible
115 D("mDNS resolved non-IP address.");
116 return;
117 }
118
119 if (!inet_ntop(address->sa_family, ip_addr_data, ip_addr,
120 INET6_ADDRSTRLEN)) {
121 D("Could not convert IP address to string.");
122 return;
123 }
124
125 std::string response;
126 connect_device(android::base::StringPrintf(addr_format, ip_addr, port_),
127 &response);
128 D("Connect to %s (%s:%hu) : %s", name_.c_str(), ip_addr, port_,
129 response.c_str());
130 }
131
132 private:
133 std::string name_;
134 const uint16_t port_;
135};
136
137static void register_service_ip(DNSServiceRef /*sdRef*/,
138 DNSServiceFlags /*flags*/,
139 uint32_t /*interfaceIndex*/,
140 DNSServiceErrorType /*errorCode*/,
141 const char* /*hostname*/,
142 const sockaddr* address,
143 uint32_t /*ttl*/,
144 void* context) {
145 std::unique_ptr<ResolvedService> data(
146 reinterpret_cast<ResolvedService*>(context));
147 data->Connect(address);
148}
149
150static void register_resolved_mdns_service(DNSServiceRef sdRef,
151 DNSServiceFlags flags,
152 uint32_t interfaceIndex,
153 DNSServiceErrorType errorCode,
154 const char* fullname,
155 const char* hosttarget,
156 uint16_t port,
157 uint16_t txtLen,
158 const unsigned char* txtRecord,
159 void* context);
160
161class DiscoveredService : public AsyncServiceRef {
162 public:
163 DiscoveredService(uint32_t interfaceIndex, const char* serviceName,
164 const char* regtype, const char* domain)
165 : serviceName_(serviceName) {
166
167 DNSServiceErrorType ret =
168 DNSServiceResolve(&sdRef_, 0, interfaceIndex, serviceName, regtype,
169 domain, register_resolved_mdns_service,
170 reinterpret_cast<void*>(this));
171
172 if (ret != kDNSServiceErr_NoError) {
173 D("Got %d from DNSServiceResolve.", ret);
174 } else {
175 Initialize();
176 }
177 }
178
179 const char* ServiceName() {
180 return serviceName_.c_str();
181 }
182
183 private:
184 std::string serviceName_;
185};
186
187static void register_resolved_mdns_service(DNSServiceRef sdRef,
188 DNSServiceFlags flags,
189 uint32_t interfaceIndex,
190 DNSServiceErrorType errorCode,
191 const char* fullname,
192 const char* hosttarget,
193 uint16_t port,
194 uint16_t /*txtLen*/,
195 const unsigned char* /*txtRecord*/,
196 void* context) {
197 std::unique_ptr<DiscoveredService> discovered(
198 reinterpret_cast<DiscoveredService*>(context));
199
200 if (errorCode != kDNSServiceErr_NoError) {
201 D("Got error %d resolving service.", errorCode);
202 return;
203 }
204
205
206 auto resolved =
207 new ResolvedService(discovered->ServiceName(),
208 interfaceIndex, hosttarget, ntohs(port));
209
210 if (! resolved->Initialized()) {
211 delete resolved;
212 }
213
214 if (flags) { /* Only ever equals MoreComing or 0 */
215 discovered.release();
216 }
217}
218
219static void register_mdns_transport(DNSServiceRef sdRef,
220 DNSServiceFlags flags,
221 uint32_t interfaceIndex,
222 DNSServiceErrorType errorCode,
223 const char* serviceName,
224 const char* regtype,
225 const char* domain,
226 void* /*context*/) {
227 if (errorCode != kDNSServiceErr_NoError) {
228 D("Got error %d during mDNS browse.", errorCode);
229 DNSServiceRefDeallocate(sdRef);
230 fdevent_remove(&service_ref_fde);
231 return;
232 }
233
234 auto discovered = new DiscoveredService(interfaceIndex, serviceName,
235 regtype, domain);
236
237 if (! discovered->Initialized()) {
238 delete discovered;
239 }
240}
241
242void init_mdns_transport_discovery(void) {
243 DNSServiceErrorType errorCode =
244 DNSServiceBrowse(&service_ref, 0, 0, kADBServiceType, nullptr,
245 register_mdns_transport, nullptr);
246
247 if (errorCode != kDNSServiceErr_NoError) {
248 D("Got %d initiating mDNS browse.", errorCode);
249 return;
250 }
251
252 fdevent_install(&service_ref_fde,
253 DNSServiceRefSockFD(service_ref),
254 pump_service_ref,
255 &service_ref);
256 fdevent_set(&service_ref_fde, FDE_READ);
257}