diff options
Diffstat (limited to 'netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp')
-rw-r--r-- | netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp | 779 |
1 files changed, 0 insertions, 779 deletions
diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp deleted file mode 100644 index 72b5577749..0000000000 --- a/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp +++ /dev/null @@ -1,779 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "MDNSResponderOperator.h" -#include "MDNSResponderReply.h" -#include "mozilla/EndianUtils.h" -#include "mozilla/Logging.h" -#include "mozilla/ScopeExit.h" -#include "mozilla/Unused.h" -#include "nsComponentManagerUtils.h" -#include "nsCOMPtr.h" -#include "nsDebug.h" -#include "nsDNSServiceInfo.h" -#include "nsHashPropertyBag.h" -#include "nsIProperty.h" -#include "nsISimpleEnumerator.h" -#include "nsIVariant.h" -#include "nsServiceManagerUtils.h" -#include "nsNetAddr.h" -#include "nsNetCID.h" -#include "nsSocketTransportService2.h" -#include "nsThreadUtils.h" -#include "nsXPCOMCID.h" -#include "private/pprio.h" - -#include "nsASocketHandler.h" - -namespace mozilla { -namespace net { - -static LazyLogModule gMDNSLog("MDNSResponderOperator"); -#undef LOG_I -#define LOG_I(...) MOZ_LOG(mozilla::net::gMDNSLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) -#undef LOG_E -#define LOG_E(...) MOZ_LOG(mozilla::net::gMDNSLog, mozilla::LogLevel::Error, (__VA_ARGS__)) - -class MDNSResponderOperator::ServiceWatcher final - : public nsASocketHandler -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - - // nsASocketHandler methods - virtual void OnSocketReady(PRFileDesc* fd, int16_t outFlags) override - { - MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); - MOZ_ASSERT(fd == mFD); - - if (outFlags & (PR_POLL_ERR | PR_POLL_HUP | PR_POLL_NVAL)) { - LOG_E("error polling on listening socket (%p)", fd); - mCondition = NS_ERROR_UNEXPECTED; - } - - if (!(outFlags & PR_POLL_READ)) { - return; - } - - DNSServiceProcessResult(mService); - } - - virtual void OnSocketDetached(PRFileDesc *fd) override - { - MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); - MOZ_ASSERT(mThread); - MOZ_ASSERT(fd == mFD); - - if (!mFD) { - return; - } - - // Bug 1175387: do not double close the handle here. - PR_ChangeFileDescNativeHandle(mFD, -1); - PR_Close(mFD); - mFD = nullptr; - - mThread->Dispatch(NewRunnableMethod(this, &ServiceWatcher::Deallocate), - NS_DISPATCH_NORMAL); - } - - virtual void IsLocal(bool *aIsLocal) override { *aIsLocal = true; } - - virtual void KeepWhenOffline(bool *aKeepWhenOffline) override - { - *aKeepWhenOffline = true; - } - - virtual uint64_t ByteCountSent() override { return 0; } - virtual uint64_t ByteCountReceived() override { return 0; } - - explicit ServiceWatcher(DNSServiceRef aService, - MDNSResponderOperator* aOperator) - : mThread(nullptr) - , mSts(nullptr) - , mOperatorHolder(aOperator) - , mService(aService) - , mFD(nullptr) - , mAttached(false) - { - if (!gSocketTransportService) - { - nsCOMPtr<nsISocketTransportService> sts = - do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID); - } - } - - nsresult Init() - { - MOZ_ASSERT(PR_GetCurrentThread() != gSocketThread); - mThread = NS_GetCurrentThread(); - - if (!mService) { - return NS_OK; - } - - if (!gSocketTransportService) { - return NS_ERROR_FAILURE; - } - mSts = gSocketTransportService; - - int osfd = DNSServiceRefSockFD(mService); - if (osfd == -1) { - return NS_ERROR_FAILURE; - } - - mFD = PR_ImportFile(osfd); - return PostEvent(&ServiceWatcher::OnMsgAttach); - } - - void Close() - { - MOZ_ASSERT(PR_GetCurrentThread() != gSocketThread); - - if (!gSocketTransportService) { - Deallocate(); - return; - } - - PostEvent(&ServiceWatcher::OnMsgClose); - } - -private: - ~ServiceWatcher() = default; - - void Deallocate() - { - if (mService) { - DNSServiceRefDeallocate(mService); - mService = nullptr; - } - mOperatorHolder = nullptr; - } - - nsresult PostEvent(void(ServiceWatcher::*func)(void)) - { - return gSocketTransportService->Dispatch(NewRunnableMethod(this, func), - NS_DISPATCH_NORMAL); - } - - void OnMsgClose() - { - MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); - - if (NS_FAILED(mCondition)) { - return; - } - - // tear down socket. this signals the STS to detach our socket handler. - mCondition = NS_BINDING_ABORTED; - - // if we are attached, then socket transport service will call our - // OnSocketDetached method automatically. Otherwise, we have to call it - // (and thus close the socket) manually. - if (!mAttached) { - OnSocketDetached(mFD); - } - } - - void OnMsgAttach() - { - MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); - - if (NS_FAILED(mCondition)) { - return; - } - - mCondition = TryAttach(); - - // if we hit an error while trying to attach then bail... - if (NS_FAILED(mCondition)) { - NS_ASSERTION(!mAttached, "should not be attached already"); - OnSocketDetached(mFD); - } - - } - - nsresult TryAttach() - { - MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); - - nsresult rv; - - if (!gSocketTransportService) { - return NS_ERROR_FAILURE; - } - - // - // find out if it is going to be ok to attach another socket to the STS. - // if not then we have to wait for the STS to tell us that it is ok. - // the notification is asynchronous, which means that when we could be - // in a race to call AttachSocket once notified. for this reason, when - // we get notified, we just re-enter this function. as a result, we are - // sure to ask again before calling AttachSocket. in this way we deal - // with the race condition. though it isn't the most elegant solution, - // it is far simpler than trying to build a system that would guarantee - // FIFO ordering (which wouldn't even be that valuable IMO). see bug - // 194402 for more info. - // - if (!gSocketTransportService->CanAttachSocket()) { - nsCOMPtr<nsIRunnable> event = - NewRunnableMethod(this, &ServiceWatcher::OnMsgAttach); - - nsresult rv = gSocketTransportService->NotifyWhenCanAttachSocket(event); - if (NS_FAILED(rv)) { - return rv; - } - } - - // - // ok, we can now attach our socket to the STS for polling - // - rv = gSocketTransportService->AttachSocket(mFD, this); - if (NS_FAILED(rv)) { - return rv; - } - - mAttached = true; - - // - // now, configure our poll flags for listening... - // - mPollFlags = (PR_POLL_READ | PR_POLL_EXCEPT); - - return NS_OK; - } - - nsCOMPtr<nsIThread> mThread; - RefPtr<nsSocketTransportService> mSts; - RefPtr<MDNSResponderOperator> mOperatorHolder; - DNSServiceRef mService; - PRFileDesc* mFD; - bool mAttached; -}; - -NS_IMPL_ISUPPORTS(MDNSResponderOperator::ServiceWatcher, nsISupports) - -MDNSResponderOperator::MDNSResponderOperator() - : mService(nullptr) - , mWatcher(nullptr) - , mThread(NS_GetCurrentThread()) - , mIsCancelled(false) -{ -} - -MDNSResponderOperator::~MDNSResponderOperator() -{ - Stop(); -} - -nsresult -MDNSResponderOperator::Start() -{ - if (mIsCancelled) { - return NS_OK; - } - - if (IsServing()) { - Stop(); - } - - return NS_OK; -} - -nsresult -MDNSResponderOperator::Stop() -{ - return ResetService(nullptr); -} - -nsresult -MDNSResponderOperator::ResetService(DNSServiceRef aService) -{ - nsresult rv; - - if (aService != mService) { - if (mWatcher) { - mWatcher->Close(); - mWatcher = nullptr; - } - - if (aService) { - RefPtr<ServiceWatcher> watcher = new ServiceWatcher(aService, this); - if (NS_WARN_IF(NS_FAILED(rv = watcher->Init()))) { - return rv; - } - mWatcher = watcher; - } - - mService = aService; - } - return NS_OK; -} - -BrowseOperator::BrowseOperator(const nsACString& aServiceType, - nsIDNSServiceDiscoveryListener* aListener) - : MDNSResponderOperator() - , mServiceType(aServiceType) - , mListener(aListener) -{ -} - -nsresult -BrowseOperator::Start() -{ - nsresult rv; - if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) { - return rv; - } - - DNSServiceRef service = nullptr; - DNSServiceErrorType err = DNSServiceBrowse(&service, - 0, - kDNSServiceInterfaceIndexAny, - mServiceType.get(), - nullptr, - &BrowseReplyRunnable::Reply, - this); - NS_WARNING_ASSERTION(kDNSServiceErr_NoError == err, "DNSServiceBrowse fail"); - - if (mListener) { - if (kDNSServiceErr_NoError == err) { - mListener->OnDiscoveryStarted(mServiceType); - } else { - mListener->OnStartDiscoveryFailed(mServiceType, err); - } - } - - if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { - return NS_ERROR_FAILURE; - } - - return ResetService(service); -} - -nsresult -BrowseOperator::Stop() -{ - bool isServing = IsServing(); - nsresult rv = MDNSResponderOperator::Stop(); - - if (isServing && mListener) { - if (NS_SUCCEEDED(rv)) { - mListener->OnDiscoveryStopped(mServiceType); - } else { - mListener->OnStopDiscoveryFailed(mServiceType, - static_cast<uint32_t>(rv)); - } - } - - return rv; -} - -void -BrowseOperator::Reply(DNSServiceRef aSdRef, - DNSServiceFlags aFlags, - uint32_t aInterfaceIndex, - DNSServiceErrorType aErrorCode, - const nsACString& aServiceName, - const nsACString& aRegType, - const nsACString& aReplyDomain) -{ - MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); - - if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { - LOG_E("BrowseOperator::Reply (%d)", aErrorCode); - if (mListener) { - mListener->OnStartDiscoveryFailed(mServiceType, aErrorCode); - } - return; - } - - if (!mListener) { return; } - nsCOMPtr<nsIDNSServiceInfo> info = new nsDNSServiceInfo(); - - if (NS_WARN_IF(!info)) { return; } - if (NS_WARN_IF(NS_FAILED(info->SetServiceName(aServiceName)))) { return; } - if (NS_WARN_IF(NS_FAILED(info->SetServiceType(aRegType)))) { return; } - if (NS_WARN_IF(NS_FAILED(info->SetDomainName(aReplyDomain)))) { return; } - - if (aFlags & kDNSServiceFlagsAdd) { - mListener->OnServiceFound(info); - } else { - mListener->OnServiceLost(info); - } -} - -RegisterOperator::RegisterOperator(nsIDNSServiceInfo* aServiceInfo, - nsIDNSRegistrationListener* aListener) - : MDNSResponderOperator() - , mServiceInfo(aServiceInfo) - , mListener(aListener) -{ -} - -nsresult -RegisterOperator::Start() -{ - nsresult rv; - - rv = MDNSResponderOperator::Start(); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - uint16_t port; - if (NS_WARN_IF(NS_FAILED(rv = mServiceInfo->GetPort(&port)))) { - return rv; - } - nsAutoCString type; - if (NS_WARN_IF(NS_FAILED(rv = mServiceInfo->GetServiceType(type)))) { - return rv; - } - - TXTRecordRef txtRecord; - char buf[TXT_BUFFER_SIZE] = { 0 }; - TXTRecordCreate(&txtRecord, TXT_BUFFER_SIZE, buf); - - nsCOMPtr<nsIPropertyBag2> attributes; - if (NS_FAILED(rv = mServiceInfo->GetAttributes(getter_AddRefs(attributes)))) { - LOG_I("register: no attributes"); - } else { - nsCOMPtr<nsISimpleEnumerator> enumerator; - if (NS_WARN_IF(NS_FAILED(rv = - attributes->GetEnumerator(getter_AddRefs(enumerator))))) { - return rv; - } - - bool hasMoreElements; - while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) && - hasMoreElements) { - nsCOMPtr<nsISupports> element; - MOZ_ALWAYS_SUCCEEDS(enumerator->GetNext(getter_AddRefs(element))); - nsCOMPtr<nsIProperty> property = do_QueryInterface(element); - MOZ_ASSERT(property); - - nsAutoString name; - nsCOMPtr<nsIVariant> value; - MOZ_ALWAYS_SUCCEEDS(property->GetName(name)); - MOZ_ALWAYS_SUCCEEDS(property->GetValue(getter_AddRefs(value))); - - nsAutoCString str; - if (NS_WARN_IF(NS_FAILED(value->GetAsACString(str)))) { - continue; - } - - TXTRecordSetValue(&txtRecord, - /* it's safe because key name is ASCII only. */ - NS_LossyConvertUTF16toASCII(name).get(), - str.Length(), - str.get()); - } - } - - nsAutoCString host; - nsAutoCString name; - nsAutoCString domain; - - DNSServiceRef service = nullptr; - DNSServiceErrorType err = - DNSServiceRegister(&service, - 0, - 0, - NS_SUCCEEDED(mServiceInfo->GetServiceName(name)) ? - name.get() : nullptr, - type.get(), - NS_SUCCEEDED(mServiceInfo->GetDomainName(domain)) ? - domain.get() : nullptr, - NS_SUCCEEDED(mServiceInfo->GetHost(host)) ? - host.get() : nullptr, - NativeEndian::swapToNetworkOrder(port), - TXTRecordGetLength(&txtRecord), - TXTRecordGetBytesPtr(&txtRecord), - &RegisterReplyRunnable::Reply, - this); - NS_WARNING_ASSERTION(kDNSServiceErr_NoError == err, - "DNSServiceRegister fail"); - - TXTRecordDeallocate(&txtRecord); - - if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { - if (mListener) { - mListener->OnRegistrationFailed(mServiceInfo, err); - } - return NS_ERROR_FAILURE; - } - - return ResetService(service); -} - -nsresult -RegisterOperator::Stop() -{ - bool isServing = IsServing(); - nsresult rv = MDNSResponderOperator::Stop(); - - if (isServing && mListener) { - if (NS_SUCCEEDED(rv)) { - mListener->OnServiceUnregistered(mServiceInfo); - } else { - mListener->OnUnregistrationFailed(mServiceInfo, - static_cast<uint32_t>(rv)); - } - } - - return rv; -} - -void -RegisterOperator::Reply(DNSServiceRef aSdRef, - DNSServiceFlags aFlags, - DNSServiceErrorType aErrorCode, - const nsACString& aName, - const nsACString& aRegType, - const nsACString& aDomain) -{ - MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); - - if (kDNSServiceErr_NoError != aErrorCode) { - LOG_E("RegisterOperator::Reply (%d)", aErrorCode); - } - - if (!mListener) { return; } - nsCOMPtr<nsIDNSServiceInfo> info = new nsDNSServiceInfo(mServiceInfo); - if (NS_WARN_IF(NS_FAILED(info->SetServiceName(aName)))) { return; } - if (NS_WARN_IF(NS_FAILED(info->SetServiceType(aRegType)))) { return; } - if (NS_WARN_IF(NS_FAILED(info->SetDomainName(aDomain)))) { return; } - - if (kDNSServiceErr_NoError == aErrorCode) { - if (aFlags & kDNSServiceFlagsAdd) { - mListener->OnServiceRegistered(info); - } else { - // If a successfully-registered name later suffers a name conflict - // or similar problem and has to be deregistered, the callback will - // be invoked with the kDNSServiceFlagsAdd flag not set. - LOG_E("RegisterOperator::Reply: deregister"); - if (NS_WARN_IF(NS_FAILED(Stop()))) { - return; - } - } - } else { - mListener->OnRegistrationFailed(info, aErrorCode); - } -} - -ResolveOperator::ResolveOperator(nsIDNSServiceInfo* aServiceInfo, - nsIDNSServiceResolveListener* aListener) - : MDNSResponderOperator() - , mServiceInfo(aServiceInfo) - , mListener(aListener) -{ -} - -nsresult -ResolveOperator::Start() -{ - nsresult rv; - if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) { - return rv; - } - - nsAutoCString name; - mServiceInfo->GetServiceName(name); - nsAutoCString type; - mServiceInfo->GetServiceType(type); - nsAutoCString domain; - mServiceInfo->GetDomainName(domain); - - LOG_I("Resolve: (%s), (%s), (%s)", name.get(), type.get(), domain.get()); - - DNSServiceRef service = nullptr; - DNSServiceErrorType err = - DNSServiceResolve(&service, - 0, - kDNSServiceInterfaceIndexAny, - name.get(), - type.get(), - domain.get(), - (DNSServiceResolveReply)&ResolveReplyRunnable::Reply, - this); - - if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { - if (mListener) { - mListener->OnResolveFailed(mServiceInfo, err); - } - return NS_ERROR_FAILURE; - } - - return ResetService(service); -} - -void -ResolveOperator::Reply(DNSServiceRef aSdRef, - DNSServiceFlags aFlags, - uint32_t aInterfaceIndex, - DNSServiceErrorType aErrorCode, - const nsACString& aFullName, - const nsACString& aHostTarget, - uint16_t aPort, - uint16_t aTxtLen, - const unsigned char* aTxtRecord) -{ - MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); - - auto guard = MakeScopeExit([&] { - Unused << NS_WARN_IF(NS_FAILED(Stop())); - }); - - if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { - LOG_E("ResolveOperator::Reply (%d)", aErrorCode); - return; - } - - // Resolve TXT record - int count = TXTRecordGetCount(aTxtLen, aTxtRecord); - LOG_I("resolve: txt count = %d, len = %d", count, aTxtLen); - nsCOMPtr<nsIWritablePropertyBag2> attributes = new nsHashPropertyBag(); - if (NS_WARN_IF(!attributes)) { - return; - } - if (count) { - for (int i = 0; i < count; ++i) { - char key[TXT_BUFFER_SIZE] = { '\0' }; - uint8_t vSize = 0; - const void* value = nullptr; - if (kDNSServiceErr_NoError != - TXTRecordGetItemAtIndex(aTxtLen, - aTxtRecord, - i, - TXT_BUFFER_SIZE, - key, - &vSize, - &value)) { - break; - } - - nsAutoCString str(reinterpret_cast<const char*>(value), vSize); - LOG_I("resolve TXT: (%d) %s=%s", vSize, key, str.get()); - - if (NS_WARN_IF(NS_FAILED(attributes->SetPropertyAsACString( - /* it's safe to convert because key name is ASCII only. */ - NS_ConvertASCIItoUTF16(key), - str)))) { - break; - } - } - } - - if (!mListener) { return; } - nsCOMPtr<nsIDNSServiceInfo> info = new nsDNSServiceInfo(mServiceInfo); - if (NS_WARN_IF(NS_FAILED(info->SetHost(aHostTarget)))) { return; } - if (NS_WARN_IF(NS_FAILED(info->SetPort(aPort)))) { return; } - if (NS_WARN_IF(NS_FAILED(info->SetAttributes(attributes)))) { return; } - - if (kDNSServiceErr_NoError == aErrorCode) { - GetAddrInfor(info); - } - else { - mListener->OnResolveFailed(info, aErrorCode); - Unused << NS_WARN_IF(NS_FAILED(Stop())); - } -} - -void -ResolveOperator::GetAddrInfor(nsIDNSServiceInfo* aServiceInfo) -{ - RefPtr<GetAddrInfoOperator> getAddreOp = new GetAddrInfoOperator(aServiceInfo, - mListener); - Unused << NS_WARN_IF(NS_FAILED(getAddreOp->Start())); -} - -GetAddrInfoOperator::GetAddrInfoOperator(nsIDNSServiceInfo* aServiceInfo, - nsIDNSServiceResolveListener* aListener) - : MDNSResponderOperator() - , mServiceInfo(aServiceInfo) - , mListener(aListener) -{ -} - -nsresult -GetAddrInfoOperator::Start() -{ - nsresult rv; - if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) { - return rv; - } - - nsAutoCString host; - mServiceInfo->GetHost(host); - - LOG_I("GetAddrInfo: (%s)", host.get()); - - DNSServiceRef service = nullptr; - DNSServiceErrorType err = - DNSServiceGetAddrInfo(&service, - kDNSServiceFlagsForceMulticast, - kDNSServiceInterfaceIndexAny, - kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, - host.get(), - (DNSServiceGetAddrInfoReply)&GetAddrInfoReplyRunnable::Reply, - this); - - if (NS_WARN_IF(kDNSServiceErr_NoError != err)) { - if (mListener) { - mListener->OnResolveFailed(mServiceInfo, err); - } - return NS_ERROR_FAILURE; - } - - return ResetService(service); -} - -void -GetAddrInfoOperator::Reply(DNSServiceRef aSdRef, - DNSServiceFlags aFlags, - uint32_t aInterfaceIndex, - DNSServiceErrorType aErrorCode, - const nsACString& aHostName, - const NetAddr& aAddress, - uint32_t aTTL) -{ - MOZ_ASSERT(GetThread() == NS_GetCurrentThread()); - - auto guard = MakeScopeExit([&] { - Unused << NS_WARN_IF(NS_FAILED(Stop())); - }); - - if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) { - LOG_E("GetAddrInfoOperator::Reply (%d)", aErrorCode); - return; - } - - if (!mListener) { return; } - - NetAddr addr = aAddress; - nsCOMPtr<nsINetAddr> address = new nsNetAddr(&addr); - nsCString addressStr; - if (NS_WARN_IF(NS_FAILED(address->GetAddress(addressStr)))) { return; } - - nsCOMPtr<nsIDNSServiceInfo> info = new nsDNSServiceInfo(mServiceInfo); - if (NS_WARN_IF(NS_FAILED(info->SetAddress(addressStr)))) { return; } - - /** - * |kDNSServiceFlagsMoreComing| means this callback will be one or more - * callback events later, so this instance should be kept alive until all - * follow-up events are processed. - */ - if (aFlags & kDNSServiceFlagsMoreComing) { - guard.release(); - } - - if (kDNSServiceErr_NoError == aErrorCode) { - mListener->OnServiceResolved(info); - } else { - mListener->OnResolveFailed(info, aErrorCode); - } -} - -} // namespace net -} // namespace mozilla |