blob: 073bbbf7c9fa7eea4ae16a97a88ef5bdc8da3122 [file] [log] [blame]
Casey Dahlin3122cdf2016-06-23 14:19:37 -07001/*
Joshua Duongf4ba8d72021-01-13 12:18:15 -08002 * Copyright (C) 2020 The Android Open Source Project
Casey Dahlin3122cdf2016-06-23 14:19:37 -07003 *
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
Casey Dahlin20238f22016-09-21 14:03:39 -070021#ifdef _WIN32
22#include <winsock2.h>
23#else
Casey Dahlin3122cdf2016-06-23 14:19:37 -070024#include <arpa/inet.h>
Casey Dahlin20238f22016-09-21 14:03:39 -070025#endif
Casey Dahlin3122cdf2016-06-23 14:19:37 -070026
Joshua Duong290ccb52019-11-20 14:18:43 -080027#include <memory>
Josh Gaoa7430f32017-05-03 14:23:09 -070028#include <thread>
Joshua Duong2ed15ac2020-04-23 09:46:12 -070029#include <unordered_set>
Lingfeng Yang9f4fff32018-11-26 17:31:39 -080030#include <vector>
Josh Gaoa7430f32017-05-03 14:23:09 -070031
Casey Dahlin3122cdf2016-06-23 14:19:37 -070032#include <android-base/stringprintf.h>
Joshua Duong290ccb52019-11-20 14:18:43 -080033#include <android-base/strings.h>
Joshua Duongf4ba8d72021-01-13 12:18:15 -080034
35#include <discovery/common/config.h>
36#include <discovery/common/reporting_client.h>
37#include <discovery/public/dns_sd_service_factory.h>
38#include <platform/api/network_interface.h>
39#include <platform/api/serial_delete_ptr.h>
40#include <platform/base/error.h>
41#include <platform/base/interface_info.h>
Casey Dahlin3122cdf2016-06-23 14:19:37 -070042
Lingfeng Yang9f4fff32018-11-26 17:31:39 -080043#include "adb_client.h"
Casey Dahlin3122cdf2016-06-23 14:19:37 -070044#include "adb_mdns.h"
45#include "adb_trace.h"
Joshua Duong290ccb52019-11-20 14:18:43 -080046#include "adb_utils.h"
47#include "adb_wifi.h"
Joshua Duong7ea62d82020-05-01 09:25:12 -070048#include "client/mdns_utils.h"
Joshua Duongf4ba8d72021-01-13 12:18:15 -080049#include "client/openscreen/mdns_service_watcher.h"
50#include "client/openscreen/platform/task_runner.h"
Josh Gaob51193a2019-06-28 13:50:37 -070051#include "fdevent/fdevent.h"
Casey Dahlin3122cdf2016-06-23 14:19:37 -070052#include "sysdeps.h"
53
Joshua Duongf4ba8d72021-01-13 12:18:15 -080054namespace {
Lingfeng Yang8f217102018-11-26 14:19:55 -080055
Joshua Duongf4ba8d72021-01-13 12:18:15 -080056using namespace mdns;
57using namespace openscreen;
58using ServicesUpdatedState = mdns::ServiceReceiver::ServicesUpdatedState;
Lingfeng Yang8f217102018-11-26 14:19:55 -080059
Joshua Duongf4ba8d72021-01-13 12:18:15 -080060struct DiscoveryState;
61DiscoveryState* g_state = nullptr;
62// TODO: remove once openscreen has bonjour client APIs.
63bool g_using_bonjour = false;
64AdbMdnsResponderFuncs g_adb_mdnsresponder_funcs;
65
66class DiscoveryReportingClient : public discovery::ReportingClient {
67 public:
68 void OnFatalError(Error error) override {
69 // The multicast port 5353 may fail to bind because of another process already binding
70 // to it (bonjour). So let's fallback to bonjour client APIs.
71 // TODO: Remove this once openscreen implements the bonjour client APIs.
72 LOG(ERROR) << "Encountered fatal discovery error: " << error;
73 got_fatal_ = true;
Joshua Duong2ed15ac2020-04-23 09:46:12 -070074 }
75
Joshua Duongf4ba8d72021-01-13 12:18:15 -080076 void OnRecoverableError(Error error) override {
77 LOG(ERROR) << "Encountered recoverable discovery error: " << error;
Joshua Duong2ed15ac2020-04-23 09:46:12 -070078 }
79
Joshua Duongf4ba8d72021-01-13 12:18:15 -080080 bool GotFatalError() const { return got_fatal_; }
Joshua Duong2ed15ac2020-04-23 09:46:12 -070081
Joshua Duongf4ba8d72021-01-13 12:18:15 -080082 private:
83 std::atomic<bool> got_fatal_{false};
84};
Joshua Duong2ed15ac2020-04-23 09:46:12 -070085
Joshua Duongf4ba8d72021-01-13 12:18:15 -080086struct DiscoveryState {
87 SerialDeletePtr<discovery::DnsSdService> service;
88 std::unique_ptr<DiscoveryReportingClient> reporting_client;
89 std::unique_ptr<AdbOspTaskRunner> task_runner;
90 std::vector<std::unique_ptr<ServiceReceiver>> receivers;
91 InterfaceInfo interface_info;
92};
93
94// Callback provided to service receiver for updates.
95void OnServiceReceiverResult(std::vector<std::reference_wrapper<const ServiceInfo>> infos,
96 std::reference_wrapper<const ServiceInfo> info,
97 ServicesUpdatedState state) {
98 LOG(INFO) << "Endpoint state=" << static_cast<int>(state)
99 << " instance_name=" << info.get().instance_name
100 << " service_name=" << info.get().service_name << " addr=" << info.get().v4_address
101 << " addrv6=" << info.get().v6_address << " total_serv=" << infos.size();
102
103 switch (state) {
104 case ServicesUpdatedState::EndpointCreated:
105 case ServicesUpdatedState::EndpointUpdated:
106 if (adb_DNSServiceShouldAutoConnect(info.get().service_name,
107 info.get().instance_name) &&
108 info.get().v4_address) {
109 auto index = adb_DNSServiceIndexByName(info.get().service_name);
110 if (!index) {
111 return;
112 }
113
114 // Don't try to auto-connect if not in the keystore.
115 if (*index == kADBSecureConnectServiceRefIndex &&
116 !adb_wifi_is_known_host(info.get().instance_name)) {
117 LOG(INFO) << "instance_name=" << info.get().instance_name << " not in keystore";
118 return;
119 }
120 std::string response;
121 LOG(INFO) << "Attempting to auto-connect to instance=" << info.get().instance_name
122 << " service=" << info.get().service_name << " addr4=%s"
123 << info.get().v4_address << ":" << info.get().port;
124 connect_device(
125 android::base::StringPrintf("%s.%s", info.get().instance_name.c_str(),
126 info.get().service_name.c_str()),
127 &response);
128 }
129 break;
130 default:
131 break;
Joshua Duong2ed15ac2020-04-23 09:46:12 -0700132 }
133}
134
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800135std::optional<discovery::Config> GetConfigForAllInterfaces() {
136 auto interface_infos = GetNetworkInterfaces();
137
138 discovery::Config config;
139 for (const auto interface : interface_infos) {
Colin Cross434c85d2021-08-26 12:00:31 -0700140 config.network_info.push_back({interface});
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800141 LOG(VERBOSE) << "Listening on interface [" << interface << "]";
142 }
143
144 if (config.network_info.empty()) {
145 LOG(INFO) << "No available network interfaces for mDNS discovery";
146 return std::nullopt;
147 }
148
149 return config;
150}
151
152void StartDiscovery() {
153 CHECK(!g_state);
154 g_state = new DiscoveryState();
155 g_state->task_runner = std::make_unique<AdbOspTaskRunner>();
156 g_state->reporting_client = std::make_unique<DiscoveryReportingClient>();
157
158 g_state->task_runner->PostTask([]() {
159 auto config = GetConfigForAllInterfaces();
160 if (!config) {
161 return;
162 }
163
164 g_state->service = discovery::CreateDnsSdService(g_state->task_runner.get(),
165 g_state->reporting_client.get(), *config);
166 // Register a receiver for each service type
167 for (int i = 0; i < kNumADBDNSServices; ++i) {
168 auto receiver = std::make_unique<ServiceReceiver>(
169 g_state->service.get(), kADBDNSServices[i], OnServiceReceiverResult);
170 receiver->StartDiscovery();
171 g_state->receivers.push_back(std::move(receiver));
172
173 if (g_state->reporting_client->GotFatalError()) {
174 for (auto& r : g_state->receivers) {
175 if (r->is_running()) {
176 r->StopDiscovery();
177 }
178 }
179 g_using_bonjour = true;
180 break;
181 }
182 }
183
184 if (g_using_bonjour) {
185 LOG(INFO) << "Fallback to MdnsResponder client for discovery";
186 g_adb_mdnsresponder_funcs = StartMdnsResponderDiscovery();
187 }
188 });
189}
190
191void ForEachService(const std::unique_ptr<ServiceReceiver>& receiver,
192 std::string_view wanted_instance_name, adb_secure_foreach_service_callback cb) {
193 if (!receiver->is_running()) {
194 return;
195 }
196 auto services = receiver->GetServices();
197 for (const auto& s : services) {
198 if (wanted_instance_name.empty() || s.get().instance_name == wanted_instance_name) {
199 std::stringstream ss;
200 ss << s.get().v4_address;
201 cb(s.get().instance_name.c_str(), s.get().service_name.c_str(), ss.str().c_str(),
202 s.get().port);
203 }
204 }
205}
206
207bool ConnectAdbSecureDevice(const MdnsInfo& info) {
208 if (!adb_wifi_is_known_host(info.service_name)) {
209 LOG(INFO) << "serviceName=" << info.service_name << " not in keystore";
Joshua Duong2ed15ac2020-04-23 09:46:12 -0700210 return false;
211 }
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800212
213 std::string response;
214 connect_device(android::base::StringPrintf("%s.%s", info.service_name.c_str(),
215 info.service_type.c_str()),
216 &response);
217 D("Secure connect to %s regtype %s (%s:%hu) : %s", info.service_name.c_str(),
218 info.service_type.c_str(), info.addr.c_str(), info.port, response.c_str());
Joshua Duong2ed15ac2020-04-23 09:46:12 -0700219 return true;
Lingfeng Yang8f217102018-11-26 14:19:55 -0800220}
Casey Dahlin3122cdf2016-06-23 14:19:37 -0700221
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800222} // namespace
Casey Dahlin20238f22016-09-21 14:03:39 -0700223
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800224/////////////////////////////////////////////////////////////////////////////////
225void mdns_cleanup() {
226 if (g_using_bonjour) {
227 return g_adb_mdnsresponder_funcs.mdns_cleanup();
Lingfeng Yangb90156e2018-11-17 10:14:29 -0800228 }
Josh Gaoa7430f32017-05-03 14:23:09 -0700229}
230
231void init_mdns_transport_discovery(void) {
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800232 // TODO(joshuaduong): Use openscreen discovery by default for all platforms.
233 const char* mdns_osp = getenv("ADB_MDNS_OPENSCREEN");
234 if (mdns_osp && strcmp(mdns_osp, "1") == 0) {
235 LOG(INFO) << "Openscreen mdns discovery enabled";
236 StartDiscovery();
237 } else {
238 // Original behavior is to use Bonjour client.
239 g_using_bonjour = true;
240 g_adb_mdnsresponder_funcs = StartMdnsResponderDiscovery();
241 }
242}
243
244bool adb_secure_connect_by_service_name(const std::string& instance_name) {
245 if (g_using_bonjour) {
246 return g_adb_mdnsresponder_funcs.adb_secure_connect_by_service_name(instance_name);
247 }
248
249 if (!g_state || g_state->receivers.empty()) {
250 LOG(INFO) << "Mdns not enabled";
251 return false;
252 }
253
254 std::optional<MdnsInfo> info;
255 auto cb = [&](const std::string& instance_name, const std::string& service_name,
256 const std::string& ip_addr,
257 uint16_t port) { info.emplace(instance_name, service_name, ip_addr, port); };
258 ForEachService(g_state->receivers[kADBSecureConnectServiceRefIndex], instance_name, cb);
259 if (info.has_value()) {
260 return ConnectAdbSecureDevice(*info);
261 }
262 return false;
Casey Dahlin3122cdf2016-06-23 14:19:37 -0700263}
Joshua Duonge22e1612020-03-31 10:58:50 -0700264
265std::string mdns_check() {
Joshua Duongcdc9c6a2021-05-03 12:57:07 -0700266 if (!g_state && !g_using_bonjour) {
267 return "ERROR: mdns discovery disabled";
268 }
269
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800270 if (g_using_bonjour) {
271 return g_adb_mdnsresponder_funcs.mdns_check();
Joshua Duonge22e1612020-03-31 10:58:50 -0700272 }
273
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800274 return "mdns daemon version [Openscreen discovery 0.0.0]";
Joshua Duonge22e1612020-03-31 10:58:50 -0700275}
Joshua Duong5f63d112020-03-31 08:39:24 -0700276
277std::string mdns_list_discovered_services() {
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800278 if (g_using_bonjour) {
279 return g_adb_mdnsresponder_funcs.mdns_list_discovered_services();
280 }
281
282 if (!g_state || g_state->receivers.empty()) {
283 return "";
284 }
285
Joshua Duong5f63d112020-03-31 08:39:24 -0700286 std::string result;
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800287 auto cb = [&](const std::string& instance_name, const std::string& service_name,
288 const std::string& ip_addr, uint16_t port) {
289 result += android::base::StringPrintf("%s\t%s\t%s:%u\n", instance_name.data(),
290 service_name.data(), ip_addr.data(), port);
Joshua Duong5f63d112020-03-31 08:39:24 -0700291 };
292
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800293 for (const auto& receiver : g_state->receivers) {
294 ForEachService(receiver, "", cb);
295 }
Joshua Duong5f63d112020-03-31 08:39:24 -0700296 return result;
297}
Joshua Duong7ea62d82020-05-01 09:25:12 -0700298
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800299std::optional<MdnsInfo> mdns_get_connect_service_info(const std::string& name) {
Joshua Duong7ea62d82020-05-01 09:25:12 -0700300 CHECK(!name.empty());
301
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800302 if (g_using_bonjour) {
303 return g_adb_mdnsresponder_funcs.mdns_get_connect_service_info(name);
304 }
305
306 if (!g_state || g_state->receivers.empty()) {
Joshua Duong31451f22020-06-16 15:04:51 -0700307 return std::nullopt;
308 }
Joshua Duong31451f22020-06-16 15:04:51 -0700309
Joshua Duong7ea62d82020-05-01 09:25:12 -0700310 auto mdns_instance = mdns::mdns_parse_instance_name(name);
311 if (!mdns_instance.has_value()) {
312 D("Failed to parse mDNS name [%s]", name.data());
313 return std::nullopt;
314 }
315
316 std::optional<MdnsInfo> info;
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800317 auto cb = [&](const std::string& instance_name, const std::string& service_name,
318 const std::string& ip_addr,
319 uint16_t port) { info.emplace(instance_name, service_name, ip_addr, port); };
Joshua Duong7ea62d82020-05-01 09:25:12 -0700320
321 std::string reg_type;
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800322 // Service name was provided.
Joshua Duong7ea62d82020-05-01 09:25:12 -0700323 if (!mdns_instance->service_name.empty()) {
324 reg_type = android::base::StringPrintf("%s.%s", mdns_instance->service_name.data(),
325 mdns_instance->transport_type.data());
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800326 const auto index = adb_DNSServiceIndexByName(reg_type);
327 if (!index) {
328 return std::nullopt;
329 }
330 switch (*index) {
Joshua Duong7ea62d82020-05-01 09:25:12 -0700331 case kADBTransportServiceRefIndex:
Joshua Duong7ea62d82020-05-01 09:25:12 -0700332 case kADBSecureConnectServiceRefIndex:
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800333 ForEachService(g_state->receivers[*index], mdns_instance->instance_name, cb);
Joshua Duong7ea62d82020-05-01 09:25:12 -0700334 break;
335 default:
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800336 D("Not a connectable service name [%s]", reg_type.data());
Joshua Duong7ea62d82020-05-01 09:25:12 -0700337 return std::nullopt;
338 }
339 return info;
340 }
341
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800342 // No mdns service name provided. Just search for the instance name in all adb connect services.
343 // Prefer the secured connect service over the other.
344 ForEachService(g_state->receivers[kADBSecureConnectServiceRefIndex], name, cb);
345 if (!info.has_value()) {
346 ForEachService(g_state->receivers[kADBTransportServiceRefIndex], name, cb);
Joshua Duong7ea62d82020-05-01 09:25:12 -0700347 }
348
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800349 return info;
Joshua Duong7ea62d82020-05-01 09:25:12 -0700350}
Joshua Duong07e95872020-05-04 18:42:46 -0700351
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800352std::optional<MdnsInfo> mdns_get_pairing_service_info(const std::string& name) {
Joshua Duong07e95872020-05-04 18:42:46 -0700353 CHECK(!name.empty());
354
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800355 if (g_using_bonjour) {
356 return g_adb_mdnsresponder_funcs.mdns_get_pairing_service_info(name);
357 }
358
359 if (!g_state || g_state->receivers.empty()) {
360 return std::nullopt;
361 }
362
Joshua Duong07e95872020-05-04 18:42:46 -0700363 auto mdns_instance = mdns::mdns_parse_instance_name(name);
364 if (!mdns_instance.has_value()) {
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800365 D("Failed to parse mDNS name [%s]", name.data());
Joshua Duong07e95872020-05-04 18:42:46 -0700366 return std::nullopt;
367 }
368
369 std::optional<MdnsInfo> info;
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800370 auto cb = [&](const std::string& instance_name, const std::string& service_name,
371 const std::string& ip_addr,
372 uint16_t port) { info.emplace(instance_name, service_name, ip_addr, port); };
Joshua Duong07e95872020-05-04 18:42:46 -0700373
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800374 std::string reg_type;
Joshua Duong07e95872020-05-04 18:42:46 -0700375 // Verify it's a pairing service if user explicitly inputs it.
376 if (!mdns_instance->service_name.empty()) {
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800377 reg_type = android::base::StringPrintf("%s.%s", mdns_instance->service_name.data(),
378 mdns_instance->transport_type.data());
379 const auto index = adb_DNSServiceIndexByName(reg_type);
380 if (!index) {
381 return std::nullopt;
382 }
383 switch (*index) {
Joshua Duong07e95872020-05-04 18:42:46 -0700384 case kADBSecurePairingServiceRefIndex:
385 break;
386 default:
387 D("Not an adb pairing reg_type [%s]", reg_type.data());
388 return std::nullopt;
389 }
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800390 return info;
Joshua Duong07e95872020-05-04 18:42:46 -0700391 }
392
Joshua Duongf4ba8d72021-01-13 12:18:15 -0800393 ForEachService(g_state->receivers[kADBSecurePairingServiceRefIndex], name, cb);
394
Joshua Duong07e95872020-05-04 18:42:46 -0700395 return info;
396}