Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73447676 authored by Joshua Duong's avatar Joshua Duong
Browse files

Merge changes from topic "adbwifi-client-mdns" am: a71ba615

Change-Id: I621b1667dd42fca057c2ac992bf1fa4f988555af
parents e6060c92 a71ba615
Loading
Loading
Loading
Loading
+66 −0
Original line number Diff line number Diff line
@@ -17,6 +17,72 @@
#ifndef _ADB_MDNS_H_
#define _ADB_MDNS_H_

#include <android-base/macros.h>

const char* kADBServiceType = "_adb._tcp";
const char* kADBSecurePairingServiceType = "_adb_secure_pairing._tcp";
const char* kADBSecureConnectServiceType = "_adb_secure_connect._tcp";

const int kADBTransportServiceRefIndex = 0;
const int kADBSecurePairingServiceRefIndex = 1;
const int kADBSecureConnectServiceRefIndex = 2;

// Each ADB Secure service advertises with a TXT record indicating the version
// using a key/value pair per RFC 6763 (https://tools.ietf.org/html/rfc6763).
//
// The first key/value pair is always the version of the protocol.
// There may be more key/value pairs added after.
//
// The version is purposely represented as the single letter "v" due to the
// need to minimize DNS traffic. The version starts at 1.  With each breaking
// protocol change, the version is incremented by 1.
//
// Newer adb clients/daemons need to recognize and either reject
// or be backward-compatible with older verseions if there is a mismatch.
//
// Relevant sections:
//
// """
// 6.4.  Rules for Keys in DNS-SD Key/Value Pairs
//
// The key MUST be at least one character.  DNS-SD TXT record strings
// beginning with an '=' character (i.e., the key is missing) MUST be
// silently ignored.
//
// ...
//
// 6.5.  Rules for Values in DNS-SD Key/Value Pairs
//
// If there is an '=' in a DNS-SD TXT record string, then everything
// after the first '=' to the end of the string is the value.  The value
// can contain any eight-bit values including '='.
// """

#define ADB_SECURE_SERVICE_VERSION_TXT_RECORD(ver) ("v=" #ver)

// Client/service versions are initially defined to be matching,
// but may go out of sync as different clients and services
// try to talk to each other.
#define ADB_SECURE_SERVICE_VERSION 1
#define ADB_SECURE_CLIENT_VERSION ADB_SECURE_SERVICE_VERSION

const char* kADBSecurePairingServiceTxtRecord =
        ADB_SECURE_SERVICE_VERSION_TXT_RECORD(ADB_SECURE_SERVICE_VERSION);
const char* kADBSecureConnectServiceTxtRecord =
        ADB_SECURE_SERVICE_VERSION_TXT_RECORD(ADB_SECURE_SERVICE_VERSION);

const char* kADBDNSServices[] = {
        kADBServiceType,
        kADBSecurePairingServiceType,
        kADBSecureConnectServiceType,
};

const char* kADBDNSServiceTxtRecords[] = {
        nullptr,
        kADBSecurePairingServiceTxtRecord,
        kADBSecureConnectServiceTxtRecord,
};

const int kNumADBDNSServices = arraysize(kADBDNSServices);

#endif
+14 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#pragma once

#include <functional>
#include <optional>
#include <string>

@@ -86,3 +87,16 @@ std::optional<std::string> adb_get_server_executable_path();
// Globally acccesible argv/envp, for the purpose of re-execing adb.
extern const char* _Nullable * _Nullable __adb_argv;
extern const char* _Nullable * _Nullable __adb_envp;

// ADB Secure DNS service interface. Used to query what ADB Secure DNS services have been
// resolved, and to run some kind of callback for each one.
using adb_secure_foreach_service_callback = std::function<void(
        const char* _Nonnull host_name, const char* _Nonnull ip_address, uint16_t port)>;

// Queries pairing/connect services that have been discovered and resolved.
// If |host_name| is not null, run |cb| only for services
// matching |host_name|. Otherwise, run for all services.
void adb_secure_foreach_pairing_service(const char* _Nullable host_name,
                                        adb_secure_foreach_service_callback cb);
void adb_secure_foreach_connect_service(const char* _Nullable host_name,
                                        adb_secure_foreach_service_callback cb);
+237 −63
Original line number Diff line number Diff line
@@ -25,17 +25,33 @@
#endif

#include <thread>
#include <vector>

#include <android-base/stringprintf.h>
#include <dns_sd.h>

#include "adb_client.h"
#include "adb_mdns.h"
#include "adb_trace.h"
#include "fdevent/fdevent.h"
#include "sysdeps.h"

static DNSServiceRef service_ref;
static fdevent* service_ref_fde;
static DNSServiceRef service_refs[kNumADBDNSServices];
static fdevent* service_ref_fdes[kNumADBDNSServices];

static int adb_DNSServiceIndexByName(const char* regType) {
    for (int i = 0; i < kNumADBDNSServices; ++i) {
        if (!strncmp(regType, kADBDNSServices[i], strlen(kADBDNSServices[i]))) {
            return i;
        }
    }
    return -1;
}

static bool adb_DNSServiceShouldConnect(const char* regType) {
    int index = adb_DNSServiceIndexByName(regType);
    return index == kADBTransportServiceRefIndex;
}

// Use adb_DNSServiceRefSockFD() instead of calling DNSServiceRefSockFD()
// directly so that the socket is put through the appropriate compatibility
@@ -94,10 +110,16 @@ class ResolvedService : public AsyncServiceRef {
  public:
    virtual ~ResolvedService() = default;

    ResolvedService(std::string name, uint32_t interfaceIndex,
                    const char* hosttarget, uint16_t port) :
            name_(name),
            port_(port) {
    ResolvedService(std::string serviceName, std::string regType, uint32_t interfaceIndex,
                    const char* hosttarget, uint16_t port, int version)
        : serviceName_(serviceName),
          regType_(regType),
          hosttarget_(hosttarget),
          port_(port),
          sa_family_(0),
          ip_addr_data_(NULL),
          serviceVersion_(version) {
        memset(ip_addr_, 0, sizeof(ip_addr_));

        /* TODO: We should be able to get IPv6 support by adding
         * kDNSServiceProtocol_IPv6 to the flags below. However, when we do
@@ -116,20 +138,19 @@ class ResolvedService : public AsyncServiceRef {
        } else {
            Initialize();
        }

        D("Client version: %d Service version: %d\n", clientVersion_, serviceVersion_);
    }

    void Connect(const sockaddr* address) {
        char ip_addr[INET6_ADDRSTRLEN];
        const void* ip_addr_data;
        sa_family_ = address->sa_family;
        const char* addr_format;

        if (address->sa_family == AF_INET) {
            ip_addr_data =
                &reinterpret_cast<const sockaddr_in*>(address)->sin_addr;
        if (sa_family_ == AF_INET) {
            ip_addr_data_ = &reinterpret_cast<const sockaddr_in*>(address)->sin_addr;
            addr_format = "%s:%hu";
        } else if (address->sa_family == AF_INET6) {
            ip_addr_data =
                &reinterpret_cast<const sockaddr_in6*>(address)->sin6_addr;
        } else if (sa_family_ == AF_INET6) {
            ip_addr_data_ = &reinterpret_cast<const sockaddr_in6*>(address)->sin6_addr;
            addr_format = "[%s]:%hu";
        } else {  // Should be impossible
            D("mDNS resolved non-IP address.");
@@ -137,24 +158,115 @@ class ResolvedService : public AsyncServiceRef {
        }

        // Winsock version requires the const cast Because Microsoft.
        if (!inet_ntop(address->sa_family, const_cast<void*>(ip_addr_data),
                       ip_addr, INET6_ADDRSTRLEN)) {
        if (!inet_ntop(sa_family_, const_cast<void*>(ip_addr_data_), ip_addr_, sizeof(ip_addr_))) {
            D("Could not convert IP address to string.");
            return;
        }

        // adb secure service needs to do something different from just
        // connecting here.
        if (adb_DNSServiceShouldConnect(regType_.c_str())) {
            std::string response;
        connect_device(android::base::StringPrintf(addr_format, ip_addr, port_),
                       &response);
        D("Connect to %s (%s:%hu) : %s", name_.c_str(), ip_addr, port_,
          response.c_str());
            connect_device(android::base::StringPrintf(addr_format, ip_addr_, port_), &response);
            D("Connect to %s regtype %s (%s:%hu) : %s", serviceName_.c_str(), regType_.c_str(),
              ip_addr_, port_, response.c_str());
        } else {
            D("Not immediately connecting to serviceName=[%s], regtype=[%s] ipaddr=(%s:%hu)",
              serviceName_.c_str(), regType_.c_str(), ip_addr_, port_);
        }

        int adbSecureServiceType = serviceIndex();
        switch (adbSecureServiceType) {
            case kADBSecurePairingServiceRefIndex:
                sAdbSecurePairingServices->push_back(this);
                break;
            case kADBSecureConnectServiceRefIndex:
                sAdbSecureConnectServices->push_back(this);
                break;
            default:
                break;
        }
    }

    int serviceIndex() const { return adb_DNSServiceIndexByName(regType_.c_str()); }

    std::string hostTarget() const { return hosttarget_; }

    std::string ipAddress() const { return ip_addr_; }

    uint16_t port() const { return port_; }

    using ServiceRegistry = std::vector<ResolvedService*>;

    static ServiceRegistry* sAdbSecurePairingServices;
    static ServiceRegistry* sAdbSecureConnectServices;

    static void initAdbSecure();

    static void forEachService(const ServiceRegistry& services, const std::string& hostname,
                               adb_secure_foreach_service_callback cb);

  private:
    std::string name_;
    int clientVersion_ = ADB_SECURE_CLIENT_VERSION;
    std::string serviceName_;
    std::string regType_;
    std::string hosttarget_;
    const uint16_t port_;
    int sa_family_;
    const void* ip_addr_data_;
    char ip_addr_[INET6_ADDRSTRLEN];
    int serviceVersion_;
};

// static
std::vector<ResolvedService*>* ResolvedService::sAdbSecurePairingServices = NULL;

// static
std::vector<ResolvedService*>* ResolvedService::sAdbSecureConnectServices = NULL;

// static
void ResolvedService::initAdbSecure() {
    if (!sAdbSecurePairingServices) {
        sAdbSecurePairingServices = new ServiceRegistry;
    }
    if (!sAdbSecureConnectServices) {
        sAdbSecureConnectServices = new ServiceRegistry;
    }
}

// static
void ResolvedService::forEachService(const ServiceRegistry& services,
                                     const std::string& wanted_host,
                                     adb_secure_foreach_service_callback cb) {
    initAdbSecure();

    for (auto service : services) {
        auto hostname = service->hostTarget();
        auto ip = service->ipAddress();
        auto port = service->port();

        if (wanted_host == "") {
            cb(hostname.c_str(), ip.c_str(), port);
        } else if (hostname == wanted_host) {
            cb(hostname.c_str(), ip.c_str(), port);
        }
    }
}

// static
void adb_secure_foreach_pairing_service(const char* host_name,
                                        adb_secure_foreach_service_callback cb) {
    ResolvedService::forEachService(*ResolvedService::sAdbSecurePairingServices,
                                    host_name ? host_name : "", cb);
}

// static
void adb_secure_foreach_connect_service(const char* host_name,
                                        adb_secure_foreach_service_callback cb) {
    ResolvedService::forEachService(*ResolvedService::sAdbSecureConnectServices,
                                    host_name ? host_name : "", cb);
}

static void DNSSD_API register_service_ip(DNSServiceRef /*sdRef*/,
                                          DNSServiceFlags /*flags*/,
                                          uint32_t /*interfaceIndex*/,
@@ -167,6 +279,12 @@ static void DNSSD_API register_service_ip(DNSServiceRef /*sdRef*/,
    std::unique_ptr<ResolvedService> data(
        reinterpret_cast<ResolvedService*>(context));
    data->Connect(address);

    // For ADB Secure services, keep those ResolvedService's around
    // for later processing with secure connection establishment.
    if (data->serviceIndex() != kADBTransportServiceRefIndex) {
        data.release();
    }
}

static void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,
@@ -182,18 +300,23 @@ static void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,

class DiscoveredService : public AsyncServiceRef {
  public:
    DiscoveredService(uint32_t interfaceIndex, const char* serviceName,
                      const char* regtype, const char* domain)
        : serviceName_(serviceName) {

    DiscoveredService(uint32_t interfaceIndex, const char* serviceName, const char* regtype,
                      const char* domain)
        : serviceName_(serviceName), regType_(regtype) {
        DNSServiceErrorType ret =
            DNSServiceResolve(&sdRef_, 0, interfaceIndex, serviceName, regtype,
                              domain, register_resolved_mdns_service,
                              reinterpret_cast<void*>(this));

        if (ret != kDNSServiceErr_NoError) {
            D("Got %d from DNSServiceResolve.", ret);
        } else {
        D("DNSServiceResolve for "
          "interfaceIndex %u "
          "serviceName %s "
          "regtype %s "
          "domain %s "
          ": %d",
          interfaceIndex, serviceName, regtype, domain, ret);

        if (ret == kDNSServiceErr_NoError) {
            Initialize();
        }
    }
@@ -202,20 +325,62 @@ class DiscoveredService : public AsyncServiceRef {
        return serviceName_.c_str();
    }

    const char* RegType() { return regType_.c_str(); }

  private:
    std::string serviceName_;
    std::string regType_;
};

static void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,
                                                     DNSServiceFlags flags,
                                                     uint32_t interfaceIndex,
                                                     DNSServiceErrorType errorCode,
                                                     const char* fullname,
                                                     const char* hosttarget,
                                                     uint16_t port,
                                                     uint16_t /*txtLen*/,
                                                     const unsigned char* /*txtRecord*/,
                                                     void* context) {
// Returns the version the device wanted to advertise,
// or -1 if parsing fails.
static int parse_version_from_txt_record(uint16_t txtLen, const unsigned char* txtRecord) {
    if (!txtLen) return -1;
    if (!txtRecord) return -1;

    // https://tools.ietf.org/html/rfc6763
    // """
    // 6.1.  General Format Rules for DNS TXT Records
    //
    // A DNS TXT record can be up to 65535 (0xFFFF) bytes long.  The total
    // length is indicated by the length given in the resource record header
    // in the DNS message.  There is no way to tell directly from the data
    // alone how long it is (e.g., there is no length count at the start, or
    // terminating NULL byte at the end).
    // """

    // Let's trust the TXT record's length byte
    // Worst case, it wastes 255 bytes
    std::vector<char> recordAsString(txtLen + 1, '\0');
    char* str = recordAsString.data();

    memcpy(str, txtRecord + 1 /* skip the length byte */, txtLen);

    // Check if it's the version key
    static const char* versionKey = "v=";
    size_t versionKeyLen = strlen(versionKey);

    if (strncmp(versionKey, str, versionKeyLen)) return -1;

    auto valueStart = str + versionKeyLen;

    long parsedNumber = strtol(valueStart, 0, 10);

    // No valid conversion. Also, 0
    // is not a valid version.
    if (!parsedNumber) return -1;

    // Outside bounds of long.
    if (parsedNumber == LONG_MIN || parsedNumber == LONG_MAX) return -1;

    // Possibly valid version
    return static_cast<int>(parsedNumber);
}

static void DNSSD_API register_resolved_mdns_service(
        DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
        DNSServiceErrorType errorCode, const char* fullname, const char* hosttarget, uint16_t port,
        uint16_t txtLen, const unsigned char* txtRecord, void* context) {
    D("Resolved a service.");
    std::unique_ptr<DiscoveredService> discovered(
        reinterpret_cast<DiscoveredService*>(context));
@@ -225,10 +390,14 @@ static void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,
        return;
    }

    // TODO: Reject certain combinations of invalid or mismatched client and
    // service versions here before creating anything.
    // At the moment, there is nothing to reject, so accept everything
    // as an optimistic default.
    auto serviceVersion = parse_version_from_txt_record(txtLen, txtRecord);

    auto resolved =
        new ResolvedService(discovered->ServiceName(),
                            interfaceIndex, hosttarget, ntohs(port));
    auto resolved = new ResolvedService(discovered->ServiceName(), discovered->RegType(),
                                        interfaceIndex, hosttarget, ntohs(port), serviceVersion);

    if (! resolved->Initialized()) {
        delete resolved;
@@ -239,19 +408,18 @@ static void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,
    }
}

static void DNSSD_API register_mdns_transport(DNSServiceRef sdRef,
                                              DNSServiceFlags flags,
                                              uint32_t interfaceIndex,
                                              DNSServiceErrorType errorCode,
                                              const char* serviceName,
                                              const char* regtype,
                                              const char* domain,
                                              void*  /*context*/) {
static void DNSSD_API on_service_browsed(DNSServiceRef sdRef, DNSServiceFlags flags,
                                         uint32_t interfaceIndex, DNSServiceErrorType errorCode,
                                         const char* serviceName, const char* regtype,
                                         const char* domain, void* /*context*/) {
    D("Registering a transport.");
    if (errorCode != kDNSServiceErr_NoError) {
        D("Got error %d during mDNS browse.", errorCode);
        DNSServiceRefDeallocate(sdRef);
        fdevent_destroy(service_ref_fde);
        int serviceIndex = adb_DNSServiceIndexByName(regtype);
        if (serviceIndex != -1) {
            fdevent_destroy(service_ref_fdes[serviceIndex]);
        }
        return;
    }

@@ -262,21 +430,27 @@ static void DNSSD_API register_mdns_transport(DNSServiceRef sdRef,
}

void init_mdns_transport_discovery_thread(void) {
    DNSServiceErrorType errorCode = DNSServiceBrowse(&service_ref, 0, 0, kADBServiceType, nullptr,
                                                     register_mdns_transport, nullptr);
    int errorCodes[kNumADBDNSServices];

    if (errorCode != kDNSServiceErr_NoError) {
        D("Got %d initiating mDNS browse.", errorCode);
        return;
    for (int i = 0; i < kNumADBDNSServices; ++i) {
        errorCodes[i] = DNSServiceBrowse(&service_refs[i], 0, 0, kADBDNSServices[i], nullptr,
                                         on_service_browsed, nullptr);

        if (errorCodes[i] != kDNSServiceErr_NoError) {
            D("Got %d browsing for mDNS service %s.", errorCodes[i], kADBDNSServices[i]);
        }

    fdevent_run_on_main_thread([]() {
        service_ref_fde =
            fdevent_create(adb_DNSServiceRefSockFD(service_ref), pump_service_ref, &service_ref);
        fdevent_set(service_ref_fde, FDE_READ);
        if (errorCodes[i] == kDNSServiceErr_NoError) {
            fdevent_run_on_main_thread([i]() {
                service_ref_fdes[i] = fdevent_create(adb_DNSServiceRefSockFD(service_refs[i]),
                                                     pump_service_ref, &service_refs[i]);
                fdevent_set(service_ref_fdes[i], FDE_READ);
            });
        }
    }
}

void init_mdns_transport_discovery(void) {
    ResolvedService::initAdbSecure();
    std::thread(init_mdns_transport_discovery_thread).detach();
}
+97 −14
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
 * limitations under the License.
 */

#include "mdns.h"
#include "adb_mdns.h"
#include "sysdeps.h"

@@ -32,8 +33,8 @@ using namespace std::chrono_literals;

static std::mutex& mdns_lock = *new std::mutex();
static int port;
static DNSServiceRef mdns_ref;
static bool mdns_registered = false;
static DNSServiceRef mdns_refs[kNumADBDNSServices];
static bool mdns_registered[kNumADBDNSServices];

static void start_mdns() {
    if (android::base::GetProperty("init.svc.mdnsd", "") == "running") {
@@ -60,34 +61,86 @@ static void mdns_callback(DNSServiceRef /*ref*/,
    }
}

static void setup_mdns_thread() {
    start_mdns();
static void register_mdns_service(int index, int port) {
    std::lock_guard<std::mutex> lock(mdns_lock);

    std::string hostname = "adb-";
    hostname += android::base::GetProperty("ro.serialno", "unidentified");

    auto error = DNSServiceRegister(&mdns_ref, 0, 0, hostname.c_str(),
                                    kADBServiceType, nullptr, nullptr,
                                    htobe16((uint16_t)port), 0, nullptr,
                                    mdns_callback, nullptr);
    // https://tools.ietf.org/html/rfc6763
    // """
    // The format of the data within a DNS TXT record is one or more
    // strings, packed together in memory without any intervening gaps or
    // padding bytes for word alignment.
    //
    // The format of each constituent string within the DNS TXT record is a
    // single length byte, followed by 0-255 bytes of text data.
    // """
    //
    // Therefore:
    // 1. Begin with the string length
    // 2. No null termination

    std::vector<char> txtRecord;

    if (kADBDNSServiceTxtRecords[index]) {
        size_t txtRecordStringLength = strlen(kADBDNSServiceTxtRecords[index]);

        txtRecord.resize(1 +                    // length byte
                         txtRecordStringLength  // string bytes
        );

        txtRecord[0] = (char)txtRecordStringLength;
        memcpy(txtRecord.data() + 1, kADBDNSServiceTxtRecords[index], txtRecordStringLength);
    }

    auto error = DNSServiceRegister(
            &mdns_refs[index], 0, 0, hostname.c_str(), kADBDNSServices[index], nullptr, nullptr,
            htobe16((uint16_t)port), (uint16_t)txtRecord.size(),
            txtRecord.empty() ? nullptr : txtRecord.data(), mdns_callback, nullptr);

    if (error != kDNSServiceErr_NoError) {
        LOG(ERROR) << "Could not register mDNS service (" << error << ").";
        return;
        LOG(ERROR) << "Could not register mDNS service " << kADBDNSServices[index] << ", error ("
                   << error << ").";
        mdns_registered[index] = false;
    }

    mdns_registered = true;
    mdns_registered[index] = true;

    LOG(INFO) << "adbd mDNS service " << kADBDNSServices[index]
              << " registered: " << mdns_registered[index];
}

static void teardown_mdns() {
static void unregister_mdns_service(int index) {
    std::lock_guard<std::mutex> lock(mdns_lock);

    if (mdns_registered) {
        DNSServiceRefDeallocate(mdns_ref);
    if (mdns_registered[index]) {
        DNSServiceRefDeallocate(mdns_refs[index]);
    }
}

static void register_base_mdns_transport() {
    register_mdns_service(kADBTransportServiceRefIndex, port);
}

static void setup_mdns_thread() {
    start_mdns();

    // We will now only set up the normal transport mDNS service
    // instead of registering all the adb secure mDNS services
    // in the beginning. This is to provide more privacy/security.
    register_base_mdns_transport();
}

// This also tears down any adb secure mDNS services, if they exist.
static void teardown_mdns() {
    for (int i = 0; i < kNumADBDNSServices; ++i) {
        unregister_mdns_service(i);
    }
}

// Public interface/////////////////////////////////////////////////////////////

void setup_mdns(int port_in) {
    port = port_in;
    std::thread(setup_mdns_thread).detach();
@@ -95,3 +148,33 @@ void setup_mdns(int port_in) {
    // TODO: Make this more robust against a hard kill.
    atexit(teardown_mdns);
}

void register_adb_secure_pairing_service(int port) {
    std::thread([port]() {
        register_mdns_service(kADBSecurePairingServiceRefIndex, port);
    }).detach();
}

void unregister_adb_secure_pairing_service() {
    std::thread([]() { unregister_mdns_service(kADBSecurePairingServiceRefIndex); }).detach();
}

bool is_adb_secure_pairing_service_registered() {
    std::lock_guard<std::mutex> lock(mdns_lock);
    return mdns_registered[kADBSecurePairingServiceRefIndex];
}

void register_adb_secure_connect_service(int port) {
    std::thread([port]() {
        register_mdns_service(kADBSecureConnectServiceRefIndex, port);
    }).detach();
}

void unregister_adb_secure_connect_service() {
    std::thread([]() { unregister_mdns_service(kADBSecureConnectServiceRefIndex); }).detach();
}

bool is_adb_secure_connect_service_registered() {
    std::lock_guard<std::mutex> lock(mdns_lock);
    return mdns_registered[kADBSecureConnectServiceRefIndex];
}
+8 −0
Original line number Diff line number Diff line
@@ -19,4 +19,12 @@

void setup_mdns(int port);

void register_adb_secure_pairing_service(int port);
void unregister_adb_secure_pairing_service(int port);
bool is_adb_secure_pairing_service_registered();

void register_adb_secure_connect_service(int port);
void unregister_adb_secure_connect_service(int port);
bool is_adb_secure_connect_service_registered();

#endif  // _DAEMON_MDNS_H_