blob: 07f0c0c442f83e878b7b880dfc633a7e9c3893f5 [file]
/*
* Copyright (c) 2024, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OTBR_ANDROID_MDNS_PUBLISHER_HPP_
#define OTBR_ANDROID_MDNS_PUBLISHER_HPP_
#include "mdns/mdns.hpp"
#include <aidl/com/android/server/thread/openthread/BnNsdDiscoverServiceCallback.h>
#include <aidl/com/android/server/thread/openthread/BnNsdResolveHostCallback.h>
#include <aidl/com/android/server/thread/openthread/BnNsdResolveServiceCallback.h>
#include <aidl/com/android/server/thread/openthread/BnNsdStatusReceiver.h>
#include <aidl/com/android/server/thread/openthread/DnsTxtAttribute.h>
#include <aidl/com/android/server/thread/openthread/INsdPublisher.h>
#include <set>
namespace otbr {
namespace Android {
using Status = ::ndk::ScopedAStatus;
using aidl::com::android::server::thread::openthread::BnNsdDiscoverServiceCallback;
using aidl::com::android::server::thread::openthread::BnNsdResolveHostCallback;
using aidl::com::android::server::thread::openthread::BnNsdResolveServiceCallback;
using aidl::com::android::server::thread::openthread::BnNsdStatusReceiver;
using aidl::com::android::server::thread::openthread::DnsTxtAttribute;
using aidl::com::android::server::thread::openthread::INsdPublisher;
class MdnsPublisher : public Mdns::Publisher
{
public:
explicit MdnsPublisher(Publisher::StateCallback aCallback)
: mStateCallback(std::move(aCallback))
, mNextListenerId(0)
{
}
~MdnsPublisher(void) { Stop(); }
/** Sets the INsdPublisher which forwards the mDNS API requests to the NsdManager in system_server. */
void SetINsdPublisher(std::shared_ptr<INsdPublisher> aINsdPublisher);
otbrError Start(void) override { return OTBR_ERROR_NONE; }
void Stop(void) override
{
mServiceRegistrations.clear();
mHostRegistrations.clear();
if (mNsdPublisher != nullptr)
{
mNsdPublisher->reset();
}
}
bool IsStarted(void) const override { return mNsdPublisher != nullptr; }
void UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback) override;
void UnpublishHost(const std::string &aName, ResultCallback &&aCallback) override;
void UnpublishKey(const std::string &aName, ResultCallback &&aCallback) override;
void SubscribeService(const std::string &aType, const std::string &aInstanceName) override;
void UnsubscribeService(const std::string &aType, const std::string &aInstanceName) override;
void SubscribeHost(const std::string &aHostName) override;
void UnsubscribeHost(const std::string &aHostName) override;
class NsdStatusReceiver : public BnNsdStatusReceiver
{
public:
explicit NsdStatusReceiver(Mdns::Publisher::ResultCallback aCallback)
: mCallback(std::move(aCallback))
{
}
Status onSuccess(void) override;
Status onError(int aError) override;
private:
Mdns::Publisher::ResultCallback mCallback;
};
struct ServiceResolver : private ::NonCopyable
{
explicit ServiceResolver(int aListenerId, std::shared_ptr<INsdPublisher> aNsdPublisher)
: mListenerId(aListenerId)
, mNsdPublisher(std::move(aNsdPublisher))
{
}
~ServiceResolver(void)
{
if (mNsdPublisher)
{
mNsdPublisher->stopServiceResolution(mListenerId);
}
}
int mListenerId;
std::shared_ptr<INsdPublisher> mNsdPublisher;
};
struct ServiceSubscription : public std::enable_shared_from_this<ServiceSubscription>, private ::NonCopyable
{
explicit ServiceSubscription(std::string aType,
std::string aName,
MdnsPublisher &aPublisher,
std::shared_ptr<INsdPublisher> aNsdPublisher)
: mType(std::move(aType))
, mName(std::move(aName))
, mPublisher(aPublisher)
, mNsdPublisher(std::move(aNsdPublisher))
, mBrowseListenerId(-1)
{
}
~ServiceSubscription(void) { Release(); }
void Release(void);
void Browse(void);
void Resolve(const std::string &aName, const std::string &aType);
void AddServiceResolver(const std::string &aName, ServiceResolver *aResolver);
void RemoveServiceResolver(const std::string &aInstanceName);
std::string mType;
std::string mName;
MdnsPublisher &mPublisher;
std::shared_ptr<INsdPublisher> mNsdPublisher;
int32_t mBrowseListenerId;
std::map<std::string, std::set<ServiceResolver *>> mResolvers;
};
struct HostSubscription : private ::NonCopyable
{
explicit HostSubscription(std::string aName,
MdnsPublisher &aPublisher,
std::shared_ptr<INsdPublisher> aNsdPublisher,
int listenerId)
: mName(std::move(aName))
, mPublisher(aPublisher)
, mNsdPublisher(std::move(aNsdPublisher))
, mListenerId(listenerId)
{
}
~HostSubscription(void) { Release(); }
void Release(void) { mNsdPublisher->stopHostResolution(mListenerId); }
std::string mName;
MdnsPublisher &mPublisher;
std::shared_ptr<INsdPublisher> mNsdPublisher;
const int32_t mListenerId;
};
class NsdDiscoverServiceCallback : public BnNsdDiscoverServiceCallback
{
public:
explicit NsdDiscoverServiceCallback(std::weak_ptr<ServiceSubscription> aSubscription)
: mSubscription(std::move(aSubscription))
{
}
Status onServiceDiscovered(const std::string &aName, const std::string &aType, bool aIsFound);
private:
std::weak_ptr<ServiceSubscription> mSubscription;
};
class NsdResolveServiceCallback : public BnNsdResolveServiceCallback
{
public:
explicit NsdResolveServiceCallback(std::weak_ptr<ServiceSubscription> aSubscription)
: mSubscription(std::move(aSubscription))
{
}
Status onServiceResolved(const std::string &aHostname,
int aNetifIndex,
const std::string &aName,
const std::string &aType,
int aPort,
const std::vector<std::string> &aAddresses,
const std::vector<DnsTxtAttribute> &aTxt,
int aTtlSeconds);
private:
std::weak_ptr<ServiceSubscription> mSubscription;
};
class NsdResolveHostCallback : public BnNsdResolveHostCallback
{
public:
explicit NsdResolveHostCallback(std::weak_ptr<HostSubscription> aSubscription)
: mSubscription(std::move(aSubscription))
{
}
Status onHostResolved(const std::string &aName, const std::vector<std::string> &aAddresses);
private:
std::weak_ptr<HostSubscription> mSubscription;
};
protected:
otbrError PublishServiceImpl(const std::string &aHostName,
const std::string &aName,
const std::string &aType,
const SubTypeList &aSubTypeList,
uint16_t aPort,
const TxtData &aTxtData,
ResultCallback &&aCallback) override;
otbrError PublishHostImpl(const std::string &aName, const AddressList &aAddresses, ResultCallback &&aCallback);
otbrError PublishKeyImpl(const std::string &aName, const KeyData &aKeyData, ResultCallback &&aCallback) override;
void OnServiceResolveFailedImpl(const std::string &aType, const std::string &aInstanceName, int32_t aErrorCode);
void OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode);
otbrError DnsErrorToOtbrError(int32_t aError);
private:
class NsdServiceRegistration : public ServiceRegistration
{
public:
NsdServiceRegistration(const std::string &aHostName,
const std::string &aName,
const std::string &aType,
const SubTypeList &aSubTypeList,
uint16_t aPort,
const TxtData &aTxtData,
ResultCallback &&aCallback,
MdnsPublisher *aPublisher,
int32_t aListenerId,
std::weak_ptr<INsdPublisher> aINsdPublisher)
: ServiceRegistration(aHostName,
aName,
aType,
aSubTypeList,
aPort,
aTxtData,
std::move(aCallback),
aPublisher)
, mListenerId(aListenerId)
, mNsdPublisher(std::move(aINsdPublisher))
{
}
~NsdServiceRegistration(void) override;
const int32_t mListenerId;
std::shared_ptr<NsdStatusReceiver> mUnregisterReceiver;
private:
std::weak_ptr<INsdPublisher> mNsdPublisher;
};
class NsdHostRegistration : public HostRegistration
{
public:
NsdHostRegistration(const std::string &aName,
const AddressList &aAddresses,
ResultCallback &&aCallback,
MdnsPublisher *aPublisher,
int32_t aListenerId,
std::weak_ptr<INsdPublisher> aINsdPublisher)
: HostRegistration(aName, aAddresses, std::move(aCallback), aPublisher)
, mListenerId(aListenerId)
, mNsdPublisher(aINsdPublisher)
{
}
~NsdHostRegistration(void) override;
const int32_t mListenerId;
std::shared_ptr<NsdStatusReceiver> mUnregisterReceiver;
private:
std::weak_ptr<INsdPublisher> mNsdPublisher;
};
typedef std::vector<std::shared_ptr<ServiceSubscription>> ServiceSubscriptionList;
typedef std::vector<std::shared_ptr<HostSubscription>> HostSubscriptionList;
static constexpr int kDefaultResolvedTtl = 10;
static constexpr int kMinResolvedTtl = 1;
static constexpr int kMaxResolvedTtl = 10;
int32_t AllocateListenerId(void);
StateCallback mStateCallback;
int32_t mNextListenerId;
std::shared_ptr<INsdPublisher> mNsdPublisher = nullptr;
ServiceSubscriptionList mServiceSubscriptions;
HostSubscriptionList mHostSubscriptions;
};
} // namespace Android
} // namespace otbr
#endif // OTBR_ANDROID_MDNS_PUBLISHER_HPP_