113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin/*
213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin * Copyright (C) 2016 The Android Open Source Project
313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin *
413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin * Licensed under the Apache License, Version 2.0 (the "License");
513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin * you may not use this file except in compliance with the License.
613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin * You may obtain a copy of the License at
713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin *
813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin *      http://www.apache.org/licenses/LICENSE-2.0
913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin *
1013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin * Unless required by applicable law or agreed to in writing, software
1113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin * distributed under the License is distributed on an "AS IS" BASIS,
1213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin * See the License for the specific language governing permissions and
1413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin * limitations under the License.
1513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin */
1613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
1713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin#define TRACE_TAG TRANSPORT
1813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
1913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin#include "transport.h"
2013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
212fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin#ifdef _WIN32
222fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin#include <winsock2.h>
232fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin#else
2413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin#include <arpa/inet.h>
252fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin#endif
2613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
276f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gao#include <thread>
286f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gao
2913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin#include <android-base/stringprintf.h>
3013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin#include <dns_sd.h>
3113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
3213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin#include "adb_mdns.h"
3313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin#include "adb_trace.h"
3413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin#include "fdevent.h"
3513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin#include "sysdeps.h"
3613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
3713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlinstatic DNSServiceRef service_ref;
3813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlinstatic fdevent service_ref_fde;
3913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
402fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin// Use adb_DNSServiceRefSockFD() instead of calling DNSServiceRefSockFD()
412fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin// directly so that the socket is put through the appropriate compatibility
422fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin// layers to work with the rest of ADB's internal APIs.
432fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlinstatic inline int adb_DNSServiceRefSockFD(DNSServiceRef ref) {
442fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin    return adb_register_socket(DNSServiceRefSockFD(ref));
452fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin}
462fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin#define DNSServiceRefSockFD ___xxx_DNSServiceRefSockFD
472fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin
482fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlinstatic void DNSSD_API register_service_ip(DNSServiceRef sdRef,
492fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          DNSServiceFlags flags,
502fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          uint32_t interfaceIndex,
512fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          DNSServiceErrorType errorCode,
522fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          const char* hostname,
532fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          const sockaddr* address,
542fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          uint32_t ttl,
552fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          void* context);
5613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
5713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlinstatic void pump_service_ref(int /*fd*/, unsigned ev, void* data) {
5813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    DNSServiceRef* ref = reinterpret_cast<DNSServiceRef*>(data);
5913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
6013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    if (ev & FDE_READ)
6113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        DNSServiceProcessResult(*ref);
6213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin}
6313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
6413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlinclass AsyncServiceRef {
6513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin  public:
6613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    bool Initialized() {
6713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        return initialized_;
6813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    }
6913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
7013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    virtual ~AsyncServiceRef() {
7113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        if (! initialized_) {
7213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            return;
7313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        }
7413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
7513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        DNSServiceRefDeallocate(sdRef_);
7613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        fdevent_remove(&fde_);
7713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    }
7813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
7913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin  protected:
8013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    DNSServiceRef sdRef_;
8113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
8213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    void Initialize() {
832fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin        fdevent_install(&fde_, adb_DNSServiceRefSockFD(sdRef_),
8413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin                        pump_service_ref, &sdRef_);
8513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        fdevent_set(&fde_, FDE_READ);
8613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        initialized_ = true;
8713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    }
8813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
8913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin  private:
9013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    bool initialized_;
9113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    fdevent fde_;
9213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin};
9313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
9413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlinclass ResolvedService : public AsyncServiceRef {
9513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin  public:
9613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    virtual ~ResolvedService() = default;
9713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
9813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    ResolvedService(std::string name, uint32_t interfaceIndex,
9913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin                    const char* hosttarget, uint16_t port) :
10013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            name_(name),
10113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            port_(port) {
102304150a521b95654a0568536d2f8c7696dbbb333Casey Dahlin
103304150a521b95654a0568536d2f8c7696dbbb333Casey Dahlin        /* TODO: We should be able to get IPv6 support by adding
104304150a521b95654a0568536d2f8c7696dbbb333Casey Dahlin         * kDNSServiceProtocol_IPv6 to the flags below. However, when we do
105304150a521b95654a0568536d2f8c7696dbbb333Casey Dahlin         * this, we get served link-local addresses that are usually useless to
106304150a521b95654a0568536d2f8c7696dbbb333Casey Dahlin         * connect to. What's more, we seem to /only/ get those and nothing else.
107304150a521b95654a0568536d2f8c7696dbbb333Casey Dahlin         * If we want IPv6 in the future we'll have to figure out why.
108304150a521b95654a0568536d2f8c7696dbbb333Casey Dahlin         */
10913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        DNSServiceErrorType ret =
11013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            DNSServiceGetAddrInfo(
11113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin                &sdRef_, 0, interfaceIndex,
112304150a521b95654a0568536d2f8c7696dbbb333Casey Dahlin                kDNSServiceProtocol_IPv4, hosttarget,
11313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin                register_service_ip, reinterpret_cast<void*>(this));
11413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
11513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        if (ret != kDNSServiceErr_NoError) {
11613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            D("Got %d from DNSServiceGetAddrInfo.", ret);
11713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        } else {
11813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            Initialize();
11913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        }
12013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    }
12113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
12213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    void Connect(const sockaddr* address) {
12313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        char ip_addr[INET6_ADDRSTRLEN];
12413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        const void* ip_addr_data;
12513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        const char* addr_format;
12613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
12713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        if (address->sa_family == AF_INET) {
12813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            ip_addr_data =
12913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin                &reinterpret_cast<const sockaddr_in*>(address)->sin_addr;
13013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            addr_format = "%s:%hu";
13113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        } else if (address->sa_family == AF_INET6) {
13213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            ip_addr_data =
13313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin                &reinterpret_cast<const sockaddr_in6*>(address)->sin6_addr;
13413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            addr_format = "[%s]:%hu";
13513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        } else { // Should be impossible
13613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            D("mDNS resolved non-IP address.");
13713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            return;
13813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        }
13913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
1402fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin        // Winsock version requires the const cast Because Microsoft.
1412fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin        if (!inet_ntop(address->sa_family, const_cast<void*>(ip_addr_data),
1422fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                       ip_addr, INET6_ADDRSTRLEN)) {
14313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            D("Could not convert IP address to string.");
14413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            return;
14513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        }
14613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
14713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        std::string response;
14813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        connect_device(android::base::StringPrintf(addr_format, ip_addr, port_),
14913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin                       &response);
15013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        D("Connect to %s (%s:%hu) : %s", name_.c_str(), ip_addr, port_,
15113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin          response.c_str());
15213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    }
15313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
15413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin  private:
15513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    std::string name_;
15613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    const uint16_t port_;
15713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin};
15813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
1592fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlinstatic void DNSSD_API register_service_ip(DNSServiceRef /*sdRef*/,
1602fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          DNSServiceFlags /*flags*/,
1612fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          uint32_t /*interfaceIndex*/,
1622fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          DNSServiceErrorType /*errorCode*/,
1632fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          const char* /*hostname*/,
1642fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          const sockaddr* address,
1652fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          uint32_t /*ttl*/,
1662fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                          void* context) {
1672fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin    D("Got IP for service.");
16813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    std::unique_ptr<ResolvedService> data(
16913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        reinterpret_cast<ResolvedService*>(context));
17013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    data->Connect(address);
17113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin}
17213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
1732fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlinstatic void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,
1742fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     DNSServiceFlags flags,
1752fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     uint32_t interfaceIndex,
1762fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     DNSServiceErrorType errorCode,
1772fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     const char* fullname,
1782fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     const char* hosttarget,
1792fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     uint16_t port,
1802fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     uint16_t txtLen,
1812fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     const unsigned char* txtRecord,
1822fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     void* context);
18313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
18413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlinclass DiscoveredService : public AsyncServiceRef {
18513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin  public:
18613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    DiscoveredService(uint32_t interfaceIndex, const char* serviceName,
18713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin                      const char* regtype, const char* domain)
18813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        : serviceName_(serviceName) {
18913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
19013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        DNSServiceErrorType ret =
19113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            DNSServiceResolve(&sdRef_, 0, interfaceIndex, serviceName, regtype,
19213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin                              domain, register_resolved_mdns_service,
19313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin                              reinterpret_cast<void*>(this));
19413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
19513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        if (ret != kDNSServiceErr_NoError) {
19613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            D("Got %d from DNSServiceResolve.", ret);
19713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        } else {
19813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin            Initialize();
19913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        }
20013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    }
20113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
20213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    const char* ServiceName() {
20313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        return serviceName_.c_str();
20413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    }
20513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
20613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin  private:
20713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    std::string serviceName_;
20813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin};
20913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
2102fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlinstatic void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,
2112fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     DNSServiceFlags flags,
2122fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     uint32_t interfaceIndex,
2132fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     DNSServiceErrorType errorCode,
2142fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     const char* fullname,
2152fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     const char* hosttarget,
2162fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     uint16_t port,
2172fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     uint16_t /*txtLen*/,
2182fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     const unsigned char* /*txtRecord*/,
2192fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                                     void* context) {
2202fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin    D("Resolved a service.");
22113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    std::unique_ptr<DiscoveredService> discovered(
22213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        reinterpret_cast<DiscoveredService*>(context));
22313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
22413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    if (errorCode != kDNSServiceErr_NoError) {
22513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        D("Got error %d resolving service.", errorCode);
22613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        return;
22713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    }
22813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
22913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
23013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    auto resolved =
23113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        new ResolvedService(discovered->ServiceName(),
23213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin                            interfaceIndex, hosttarget, ntohs(port));
23313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
23413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    if (! resolved->Initialized()) {
23513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        delete resolved;
23613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    }
23713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
23813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    if (flags) { /* Only ever equals MoreComing or 0 */
23913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        discovered.release();
24013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    }
24113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin}
24213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
2432fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlinstatic void DNSSD_API register_mdns_transport(DNSServiceRef sdRef,
2442fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                              DNSServiceFlags flags,
2452fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                              uint32_t interfaceIndex,
2462fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                              DNSServiceErrorType errorCode,
2472fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                              const char* serviceName,
2482fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                              const char* regtype,
2492fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                              const char* domain,
2502fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin                                              void*  /*context*/) {
2512fe9b6047536e1dbb3e6253bd6c2b3400d6f5903Casey Dahlin    D("Registering a transport.");
25213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    if (errorCode != kDNSServiceErr_NoError) {
25313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        D("Got error %d during mDNS browse.", errorCode);
25413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        DNSServiceRefDeallocate(sdRef);
25513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        fdevent_remove(&service_ref_fde);
25613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        return;
25713a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    }
25813a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
25913a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    auto discovered = new DiscoveredService(interfaceIndex, serviceName,
26013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin                                            regtype, domain);
26113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
26213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    if (! discovered->Initialized()) {
26313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        delete discovered;
26413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    }
26513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin}
26613a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
2676f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gaovoid init_mdns_transport_discovery_thread(void) {
2686f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gao    DNSServiceErrorType errorCode = DNSServiceBrowse(&service_ref, 0, 0, kADBServiceType, nullptr,
2696f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gao                                                     register_mdns_transport, nullptr);
27013a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
27113a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    if (errorCode != kDNSServiceErr_NoError) {
27213a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        D("Got %d initiating mDNS browse.", errorCode);
27313a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin        return;
27413a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin    }
27513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin
2766f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gao    fdevent_run_on_main_thread([]() {
2776f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gao        fdevent_install(&service_ref_fde, adb_DNSServiceRefSockFD(service_ref), pump_service_ref,
2786f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gao                        &service_ref);
2796f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gao        fdevent_set(&service_ref_fde, FDE_READ);
2806f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gao    });
2816f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gao}
2826f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gao
2836f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gaovoid init_mdns_transport_discovery(void) {
2846f46e6b912b2cd30a699757c3f4bbf9b679e2b79Josh Gao    std::thread(init_mdns_transport_discovery_thread).detach();
28513a269ea24a98111d2e84a7ffa3c05ab8a4e73a9Casey Dahlin}
286