/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set et sw=2 ts=4: */ /* 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 "nsIObserverService.h" #include "nsNetworkLinkService.h" #include "nsString.h" #include "mozilla/Logging.h" #include "mozilla/IntegerPrintfMacros.h" #include "nsNetAddr.h" #include "mozilla/StaticPrefs_network.h" #include "mozilla/Services.h" using namespace mozilla; static LazyLogModule gNotifyAddrLog("nsNetworkLinkService"); #define LOG(args) MOZ_LOG(gNotifyAddrLog, mozilla::LogLevel::Debug, args) NS_IMPL_ISUPPORTS(nsNetworkLinkService, nsINetworkLinkService, nsIObserver) nsNetworkLinkService::nsNetworkLinkService() : mStatusIsKnown(false) {} NS_IMETHODIMP nsNetworkLinkService::GetIsLinkUp(bool* aIsUp) { if (!mNetlinkSvc) { return NS_ERROR_NOT_AVAILABLE; } mNetlinkSvc->GetIsLinkUp(aIsUp); return NS_OK; } NS_IMETHODIMP nsNetworkLinkService::GetLinkStatusKnown(bool* aIsKnown) { *aIsKnown = mStatusIsKnown; return NS_OK; } NS_IMETHODIMP nsNetworkLinkService::GetLinkType(uint32_t* aLinkType) { NS_ENSURE_ARG_POINTER(aLinkType); // XXX This function has not yet been implemented for this platform *aLinkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN; return NS_OK; } NS_IMETHODIMP nsNetworkLinkService::GetNetworkID(nsACString& aNetworkID) { if (!mNetlinkSvc) { return NS_ERROR_NOT_AVAILABLE; } mNetlinkSvc->GetNetworkID(aNetworkID); return NS_OK; } NS_IMETHODIMP nsNetworkLinkService::GetDnsSuffixList(nsTArray& aDnsSuffixList) { if (!mNetlinkSvc) { return NS_ERROR_NOT_AVAILABLE; } return mNetlinkSvc->GetDnsSuffixList(aDnsSuffixList); } NS_IMETHODIMP nsNetworkLinkService::GetResolvers(nsTArray>& aResolvers) { nsTArray addresses; nsresult rv = GetNativeResolvers(addresses); if (NS_FAILED(rv)) { return rv; } for (const auto& addr : addresses) { aResolvers.AppendElement(MakeRefPtr(&addr)); } return NS_OK; } NS_IMETHODIMP nsNetworkLinkService::GetNativeResolvers( nsTArray& aResolvers) { if (!mNetlinkSvc) { return NS_ERROR_NOT_AVAILABLE; } return mNetlinkSvc->GetResolvers(aResolvers); } NS_IMETHODIMP nsNetworkLinkService::GetPlatformDNSIndications( uint32_t* aPlatformDNSIndications) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsNetworkLinkService::Observe(nsISupports* subject, const char* topic, const char16_t* data) { if (!strcmp("xpcom-shutdown-threads", topic)) { Shutdown(); } return NS_OK; } nsresult nsNetworkLinkService::Init() { nsCOMPtr observerService = mozilla::services::GetObserverService(); if (!observerService) { return NS_ERROR_FAILURE; } nsresult rv; rv = observerService->AddObserver(this, "xpcom-shutdown-threads", false); NS_ENSURE_SUCCESS(rv, rv); mNetlinkSvc = new mozilla::net::NetlinkService(); rv = mNetlinkSvc->Init(this); if (NS_FAILED(rv)) { mNetlinkSvc = nullptr; LOG(("Cannot initialize NetlinkService [rv=0x%08" PRIx32 "]", static_cast(rv))); return rv; } NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } nsresult nsNetworkLinkService::Shutdown() { // remove xpcom shutdown observer nsCOMPtr observerService = mozilla::services::GetObserverService(); if (observerService) { observerService->RemoveObserver(this, "xpcom-shutdown-threads"); } if (mNetlinkSvc) { mNetlinkSvc->Shutdown(); mNetlinkSvc = nullptr; } return NS_OK; } void nsNetworkLinkService::OnNetworkChanged() { if (StaticPrefs::network_notify_changed()) { RefPtr self = this; NS_DispatchToMainThread(NS_NewRunnableFunction( "nsNetworkLinkService::OnNetworkChanged", [self]() { self->NotifyObservers(NS_NETWORK_LINK_TOPIC, NS_NETWORK_LINK_DATA_CHANGED); })); } } void nsNetworkLinkService::OnNetworkIDChanged() { RefPtr self = this; NS_DispatchToMainThread(NS_NewRunnableFunction( "nsNetworkLinkService::OnNetworkIDChanged", [self]() { self->NotifyObservers(NS_NETWORK_ID_CHANGED_TOPIC, nullptr); })); } void nsNetworkLinkService::OnLinkUp() { RefPtr self = this; NS_DispatchToMainThread( NS_NewRunnableFunction("nsNetworkLinkService::OnLinkUp", [self]() { self->NotifyObservers(NS_NETWORK_LINK_TOPIC, NS_NETWORK_LINK_DATA_UP); })); } void nsNetworkLinkService::OnLinkDown() { RefPtr self = this; NS_DispatchToMainThread( NS_NewRunnableFunction("nsNetworkLinkService::OnLinkDown", [self]() { self->NotifyObservers(NS_NETWORK_LINK_TOPIC, NS_NETWORK_LINK_DATA_DOWN); })); } void nsNetworkLinkService::OnLinkStatusKnown() { mStatusIsKnown = true; } void nsNetworkLinkService::OnDnsSuffixListUpdated() { RefPtr self = this; NS_DispatchToMainThread(NS_NewRunnableFunction( "nsNetworkLinkService::OnDnsSuffixListUpdated", [self]() { self->NotifyObservers(NS_DNS_SUFFIX_LIST_UPDATED_TOPIC, nullptr); })); } /* Sends the given event. Assumes aTopic/aData never goes out of scope (static * strings are ideal). */ void nsNetworkLinkService::NotifyObservers(const char* aTopic, const char* aData) { MOZ_ASSERT(NS_IsMainThread()); LOG(("nsNetworkLinkService::NotifyObservers: topic:%s data:%s\n", aTopic, aData ? aData : "")); nsCOMPtr observerService = mozilla::services::GetObserverService(); if (observerService) { observerService->NotifyObservers( static_cast(this), aTopic, aData ? NS_ConvertASCIItoUTF16(aData).get() : nullptr); } }