mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-26 17:17:31 +09:00
parent
470a6e4401
commit
13fcc4a046
949 changed files with 95662 additions and 444 deletions
103
netwerk/base/NetworkInfoServiceCocoa.cpp
Normal file
103
netwerk/base/NetworkInfoServiceCocoa.cpp
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/* -*- Mode: C++; tab-width: 8; 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 <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
|
||||
#include "NetworkInfoServiceImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
static nsresult
|
||||
ListInterfaceAddresses(int aFd, const char* aIface, AddrMapType& aAddrMap);
|
||||
|
||||
nsresult
|
||||
DoListAddresses(AddrMapType& aAddrMap)
|
||||
{
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
auto autoCloseSocket = MakeScopeExit([&] {
|
||||
close(fd);
|
||||
});
|
||||
|
||||
struct ifconf ifconf;
|
||||
/* 16k of space should be enough to list all interfaces. Worst case, if it's
|
||||
* not then we will error out and fail to list addresses. This should only
|
||||
* happen on pathological machines with way too many interfaces.
|
||||
*/
|
||||
char buf[16384];
|
||||
|
||||
ifconf.ifc_len = sizeof(buf);
|
||||
ifconf.ifc_buf = buf;
|
||||
if (ioctl(fd, SIOCGIFCONF, &ifconf) != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
struct ifreq* ifreq = ifconf.ifc_req;
|
||||
int i = 0;
|
||||
while (i < ifconf.ifc_len) {
|
||||
size_t len = IFNAMSIZ + ifreq->ifr_addr.sa_len;
|
||||
|
||||
DebugOnly<nsresult> rv =
|
||||
ListInterfaceAddresses(fd, ifreq->ifr_name, aAddrMap);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ListInterfaceAddresses failed");
|
||||
|
||||
ifreq = (struct ifreq*) ((char*)ifreq + len);
|
||||
i += len;
|
||||
}
|
||||
|
||||
autoCloseSocket.release();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ListInterfaceAddresses(int aFd, const char* aInterface, AddrMapType& aAddrMap)
|
||||
{
|
||||
struct ifreq ifreq;
|
||||
memset(&ifreq, 0, sizeof(struct ifreq));
|
||||
strncpy(ifreq.ifr_name, aInterface, IFNAMSIZ - 1);
|
||||
if (ioctl(aFd, SIOCGIFADDR, &ifreq) != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
char host[128];
|
||||
int family;
|
||||
switch(family=ifreq.ifr_addr.sa_family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
getnameinfo(&ifreq.ifr_addr, sizeof(ifreq.ifr_addr), host, sizeof(host), 0, 0, NI_NUMERICHOST);
|
||||
break;
|
||||
case AF_UNSPEC:
|
||||
return NS_OK;
|
||||
default:
|
||||
// Unknown family.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCString ifaceStr;
|
||||
ifaceStr.AssignASCII(aInterface);
|
||||
|
||||
nsCString addrStr;
|
||||
addrStr.AssignASCII(host);
|
||||
|
||||
aAddrMap.Put(ifaceStr, addrStr);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
@ -257,6 +257,10 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
|||
'nsURLHelperWin.cpp',
|
||||
'ShutdownLayer.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
SOURCES += [
|
||||
'nsURLHelperOSX.cpp',
|
||||
]
|
||||
else:
|
||||
SOURCES += [
|
||||
'nsURLHelperUnix.cpp',
|
||||
|
|
@ -268,6 +272,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
|||
'NetworkInfoServiceWindows.cpp',
|
||||
'nsNetworkInfoService.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
SOURCES += [
|
||||
'NetworkInfoServiceCocoa.cpp',
|
||||
'nsNetworkInfoService.cpp',
|
||||
]
|
||||
elif CONFIG['OS_ARCH'] == 'Linux':
|
||||
SOURCES += [
|
||||
'NetworkInfoServiceLinux.cpp',
|
||||
|
|
|
|||
|
|
@ -3055,6 +3055,17 @@ nsSocketTransport::PRFileDescAutoLock::SetKeepaliveVals(bool aEnabled,
|
|||
}
|
||||
return NS_OK;
|
||||
|
||||
#elif defined(XP_DARWIN)
|
||||
// Darwin uses sec; only supports idle time being set.
|
||||
int err = setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE,
|
||||
&aIdleTime, sizeof(aIdleTime));
|
||||
if (NS_WARN_IF(err)) {
|
||||
LogOSError("nsSocketTransport Failed setting TCP_KEEPALIVE",
|
||||
mSocketTransport);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return NS_OK;
|
||||
|
||||
#elif defined(XP_UNIX)
|
||||
// Not all *nix OSes support the following setsockopt() options
|
||||
// build errors will tell us if they are not.
|
||||
|
|
|
|||
216
netwerk/base/nsURLHelperOSX.cpp
Normal file
216
netwerk/base/nsURLHelperOSX.cpp
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
/* Mac OS X-specific local file uri parsing */
|
||||
#include "nsURLHelper.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
static nsTArray<nsCString> *gVolumeList = nullptr;
|
||||
|
||||
static bool pathBeginsWithVolName(const nsACString& path, nsACString& firstPathComponent)
|
||||
{
|
||||
// Return whether the 1st path component in path (escaped) is equal to the name
|
||||
// of a mounted volume. Return the 1st path component (unescaped) in any case.
|
||||
// This needs to be done as quickly as possible, so we cache a list of volume names.
|
||||
// XXX Register an event handler to detect drives being mounted/unmounted?
|
||||
|
||||
if (!gVolumeList) {
|
||||
gVolumeList = new nsTArray<nsCString>;
|
||||
if (!gVolumeList) {
|
||||
return false; // out of memory
|
||||
}
|
||||
}
|
||||
|
||||
// Cache a list of volume names
|
||||
if (!gVolumeList->Length()) {
|
||||
OSErr err;
|
||||
ItemCount volumeIndex = 1;
|
||||
|
||||
do {
|
||||
HFSUniStr255 volName;
|
||||
FSRef rootDirectory;
|
||||
err = ::FSGetVolumeInfo(0, volumeIndex, nullptr, kFSVolInfoNone, nullptr,
|
||||
&volName, &rootDirectory);
|
||||
if (err == noErr) {
|
||||
NS_ConvertUTF16toUTF8 volNameStr(Substring((char16_t *)volName.unicode,
|
||||
(char16_t *)volName.unicode + volName.length));
|
||||
gVolumeList->AppendElement(volNameStr);
|
||||
volumeIndex++;
|
||||
}
|
||||
} while (err == noErr);
|
||||
}
|
||||
|
||||
// Extract the first component of the path
|
||||
nsACString::const_iterator start;
|
||||
path.BeginReading(start);
|
||||
start.advance(1); // path begins with '/'
|
||||
nsACString::const_iterator directory_end;
|
||||
path.EndReading(directory_end);
|
||||
nsACString::const_iterator component_end(start);
|
||||
FindCharInReadable('/', component_end, directory_end);
|
||||
|
||||
nsAutoCString flatComponent((Substring(start, component_end)));
|
||||
NS_UnescapeURL(flatComponent);
|
||||
int32_t foundIndex = gVolumeList->IndexOf(flatComponent);
|
||||
firstPathComponent = flatComponent;
|
||||
return (foundIndex != -1);
|
||||
}
|
||||
|
||||
void
|
||||
net_ShutdownURLHelperOSX()
|
||||
{
|
||||
delete gVolumeList;
|
||||
gVolumeList = nullptr;
|
||||
}
|
||||
|
||||
static nsresult convertHFSPathtoPOSIX(const nsACString& hfsPath, nsACString& posixPath)
|
||||
{
|
||||
// Use CFURL to do the conversion. We don't want to do this by simply
|
||||
// using SwapSlashColon - we need the charset mapped from MacRoman
|
||||
// to UTF-8, and we need "/Volumes" (or whatever - Apple says this is subject to change)
|
||||
// prepended if the path is not on the boot drive.
|
||||
|
||||
CFStringRef pathStrRef = CFStringCreateWithCString(nullptr,
|
||||
PromiseFlatCString(hfsPath).get(),
|
||||
kCFStringEncodingMacRoman);
|
||||
if (!pathStrRef)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
CFURLRef urlRef = CFURLCreateWithFileSystemPath(nullptr,
|
||||
pathStrRef, kCFURLHFSPathStyle, true);
|
||||
if (urlRef) {
|
||||
UInt8 pathBuf[PATH_MAX];
|
||||
if (CFURLGetFileSystemRepresentation(urlRef, true, pathBuf, sizeof(pathBuf))) {
|
||||
posixPath = (char *)pathBuf;
|
||||
rv = NS_OK;
|
||||
}
|
||||
}
|
||||
CFRelease(pathStrRef);
|
||||
if (urlRef)
|
||||
CFRelease(urlRef);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void SwapSlashColon(char *s)
|
||||
{
|
||||
while (*s) {
|
||||
if (*s == '/')
|
||||
*s = ':';
|
||||
else if (*s == ':')
|
||||
*s = '/';
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
net_GetURLSpecFromActualFile(nsIFile *aFile, nsACString &result)
|
||||
{
|
||||
// NOTE: This is identical to the implementation in nsURLHelperUnix.cpp
|
||||
|
||||
nsresult rv;
|
||||
nsAutoCString ePath;
|
||||
|
||||
// construct URL spec from native file path
|
||||
rv = aFile->GetNativePath(ePath);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsAutoCString escPath;
|
||||
NS_NAMED_LITERAL_CSTRING(prefix, "file://");
|
||||
|
||||
// Escape the path with the directory mask
|
||||
if (NS_EscapeURL(ePath.get(), ePath.Length(), esc_Directory+esc_Forced, escPath))
|
||||
escPath.Insert(prefix, 0);
|
||||
else
|
||||
escPath.Assign(prefix + ePath);
|
||||
|
||||
// esc_Directory does not escape the semicolons, so if a filename
|
||||
// contains semicolons we need to manually escape them.
|
||||
// This replacement should be removed in bug #473280
|
||||
escPath.ReplaceSubstring(";", "%3b");
|
||||
|
||||
result = escPath;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
net_GetFileFromURLSpec(const nsACString &aURL, nsIFile **result)
|
||||
{
|
||||
// NOTE: See also the implementation in nsURLHelperUnix.cpp
|
||||
// This matches it except for the HFS path handling.
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIFile> localFile;
|
||||
rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(localFile));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsAutoCString directory, fileBaseName, fileExtension, path;
|
||||
bool bHFSPath = false;
|
||||
|
||||
rv = net_ParseFileURL(aURL, directory, fileBaseName, fileExtension);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (!directory.IsEmpty()) {
|
||||
NS_EscapeURL(directory, esc_Directory|esc_AlwaysCopy, path);
|
||||
|
||||
// The canonical form of file URLs on OSX use POSIX paths:
|
||||
// file:///path-name.
|
||||
// But, we still encounter file URLs that use HFS paths:
|
||||
// file:///volume-name/path-name
|
||||
// Determine that here and normalize HFS paths to POSIX.
|
||||
nsAutoCString possibleVolName;
|
||||
if (pathBeginsWithVolName(directory, possibleVolName)) {
|
||||
// Though we know it begins with a volume name, it could still
|
||||
// be a valid POSIX path if the boot drive is named "Mac HD"
|
||||
// and there is a directory "Mac HD" at its root. If such a
|
||||
// directory doesn't exist, we'll assume this is an HFS path.
|
||||
FSRef testRef;
|
||||
possibleVolName.Insert("/", 0);
|
||||
if (::FSPathMakeRef((UInt8*)possibleVolName.get(), &testRef, nullptr) != noErr)
|
||||
bHFSPath = true;
|
||||
}
|
||||
|
||||
if (bHFSPath) {
|
||||
// "%2F"s need to become slashes, while all other slashes need to
|
||||
// become colons. If we start out by changing "%2F"s to colons, we
|
||||
// can reply on SwapSlashColon() to do what we need
|
||||
path.ReplaceSubstring("%2F", ":");
|
||||
path.Cut(0, 1); // directory begins with '/'
|
||||
SwapSlashColon((char *)path.get());
|
||||
// At this point, path is an HFS path made using the same
|
||||
// algorithm as nsURLHelperMac. We'll convert to POSIX below.
|
||||
}
|
||||
}
|
||||
if (!fileBaseName.IsEmpty())
|
||||
NS_EscapeURL(fileBaseName, esc_FileBaseName|esc_AlwaysCopy, path);
|
||||
if (!fileExtension.IsEmpty()) {
|
||||
path += '.';
|
||||
NS_EscapeURL(fileExtension, esc_FileExtension|esc_AlwaysCopy, path);
|
||||
}
|
||||
|
||||
NS_UnescapeURL(path);
|
||||
if (path.Length() != strlen(path.get()))
|
||||
return NS_ERROR_FILE_INVALID_PATH;
|
||||
|
||||
if (bHFSPath)
|
||||
convertHFSPathtoPOSIX(path, path);
|
||||
|
||||
// assuming path is encoded in the native charset
|
||||
rv = localFile->InitWithNativePath(path);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
localFile.forget(result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
@ -36,7 +36,12 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
|||
'/netwerk/system/win32',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'Linux':
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
LOCAL_INCLUDES += [
|
||||
'/netwerk/system/mac',
|
||||
]
|
||||
|
||||
elif CONFIG['OS_ARCH'] == 'Linux':
|
||||
LOCAL_INCLUDES += [
|
||||
'/netwerk/system/linux',
|
||||
]
|
||||
|
|
|
|||
779
netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp
Normal file
779
netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp
Normal file
|
|
@ -0,0 +1,779 @@
|
|||
/* -*- 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
|
||||
152
netwerk/dns/mdns/libmdns/MDNSResponderOperator.h
Normal file
152
netwerk/dns/mdns/libmdns/MDNSResponderOperator.h
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_netwerk_dns_mdns_libmdns_MDNSResponderOperator_h
|
||||
#define mozilla_netwerk_dns_mdns_libmdns_MDNSResponderOperator_h
|
||||
|
||||
#include "dns_sd.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDNSServiceDiscovery.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class MDNSResponderOperator
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MDNSResponderOperator)
|
||||
|
||||
public:
|
||||
MDNSResponderOperator();
|
||||
|
||||
virtual nsresult Start();
|
||||
virtual nsresult Stop();
|
||||
void Cancel() { mIsCancelled = true; }
|
||||
nsIThread* GetThread() const { return mThread; }
|
||||
|
||||
protected:
|
||||
virtual ~MDNSResponderOperator();
|
||||
|
||||
bool IsServing() const { return mService; }
|
||||
nsresult ResetService(DNSServiceRef aService);
|
||||
|
||||
private:
|
||||
class ServiceWatcher;
|
||||
|
||||
DNSServiceRef mService;
|
||||
RefPtr<ServiceWatcher> mWatcher;
|
||||
nsCOMPtr<nsIThread> mThread; // remember caller thread for callback
|
||||
Atomic<bool> mIsCancelled;
|
||||
};
|
||||
|
||||
class BrowseOperator final : public MDNSResponderOperator
|
||||
{
|
||||
public:
|
||||
BrowseOperator(const nsACString& aServiceType,
|
||||
nsIDNSServiceDiscoveryListener* aListener);
|
||||
|
||||
nsresult Start() override;
|
||||
nsresult Stop() override;
|
||||
|
||||
void Reply(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
uint32_t aInterfaceIndex,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const nsACString& aServiceName,
|
||||
const nsACString& aRegType,
|
||||
const nsACString& aReplyDomain);
|
||||
|
||||
private:
|
||||
~BrowseOperator() = default;
|
||||
|
||||
nsCString mServiceType;
|
||||
nsCOMPtr<nsIDNSServiceDiscoveryListener> mListener;
|
||||
};
|
||||
|
||||
class RegisterOperator final : public MDNSResponderOperator
|
||||
{
|
||||
enum { TXT_BUFFER_SIZE = 256 };
|
||||
|
||||
public:
|
||||
RegisterOperator(nsIDNSServiceInfo* aServiceInfo,
|
||||
nsIDNSRegistrationListener* aListener);
|
||||
|
||||
nsresult Start() override;
|
||||
nsresult Stop() override;
|
||||
|
||||
void Reply(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const nsACString& aName,
|
||||
const nsACString& aRegType,
|
||||
const nsACString& aDomain);
|
||||
|
||||
private:
|
||||
~RegisterOperator() = default;
|
||||
|
||||
nsCOMPtr<nsIDNSServiceInfo> mServiceInfo;
|
||||
nsCOMPtr<nsIDNSRegistrationListener> mListener;
|
||||
};
|
||||
|
||||
class ResolveOperator final : public MDNSResponderOperator
|
||||
{
|
||||
enum { TXT_BUFFER_SIZE = 256 };
|
||||
|
||||
public:
|
||||
ResolveOperator(nsIDNSServiceInfo* aServiceInfo,
|
||||
nsIDNSServiceResolveListener* aListener);
|
||||
|
||||
nsresult Start() override;
|
||||
|
||||
void 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);
|
||||
|
||||
private:
|
||||
~ResolveOperator() = default;
|
||||
void GetAddrInfor(nsIDNSServiceInfo* aServiceInfo);
|
||||
|
||||
nsCOMPtr<nsIDNSServiceInfo> mServiceInfo;
|
||||
nsCOMPtr<nsIDNSServiceResolveListener> mListener;
|
||||
};
|
||||
|
||||
union NetAddr;
|
||||
|
||||
class GetAddrInfoOperator final : public MDNSResponderOperator
|
||||
{
|
||||
public:
|
||||
GetAddrInfoOperator(nsIDNSServiceInfo* aServiceInfo,
|
||||
nsIDNSServiceResolveListener* aListener);
|
||||
|
||||
nsresult Start() override;
|
||||
|
||||
void Reply(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
uint32_t aInterfaceIndex,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const nsACString& aHostName,
|
||||
const NetAddr& aAddress,
|
||||
uint32_t aTTL);
|
||||
|
||||
private:
|
||||
~GetAddrInfoOperator() = default;
|
||||
|
||||
nsCOMPtr<nsIDNSServiceInfo> mServiceInfo;
|
||||
nsCOMPtr<nsIDNSServiceResolveListener> mListener;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_netwerk_dns_mdns_libmdns_MDNSResponderOperator_h
|
||||
302
netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp
Normal file
302
netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
/* -*- 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 "MDNSResponderReply.h"
|
||||
#include "mozilla/EndianUtils.h"
|
||||
#include "private/pprio.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
BrowseReplyRunnable::BrowseReplyRunnable(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
uint32_t aInterfaceIndex,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const nsACString& aServiceName,
|
||||
const nsACString& aRegType,
|
||||
const nsACString& aReplyDomain,
|
||||
BrowseOperator* aContext)
|
||||
: mSdRef(aSdRef)
|
||||
, mFlags(aFlags)
|
||||
, mInterfaceIndex(aInterfaceIndex)
|
||||
, mErrorCode(aErrorCode)
|
||||
, mServiceName(aServiceName)
|
||||
, mRegType(aRegType)
|
||||
, mReplyDomain(aReplyDomain)
|
||||
, mContext(aContext)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BrowseReplyRunnable::Run()
|
||||
{
|
||||
MOZ_ASSERT(mContext);
|
||||
mContext->Reply(mSdRef,
|
||||
mFlags,
|
||||
mInterfaceIndex,
|
||||
mErrorCode,
|
||||
mServiceName,
|
||||
mRegType,
|
||||
mReplyDomain);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BrowseReplyRunnable::Reply(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
uint32_t aInterfaceIndex,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const char* aServiceName,
|
||||
const char* aRegType,
|
||||
const char* aReplyDomain,
|
||||
void* aContext)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
BrowseOperator* obj(reinterpret_cast<BrowseOperator*>(aContext));
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> thread(obj->GetThread());
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
thread->Dispatch(new BrowseReplyRunnable(aSdRef,
|
||||
aFlags,
|
||||
aInterfaceIndex,
|
||||
aErrorCode,
|
||||
nsCString(aServiceName),
|
||||
nsCString(aRegType),
|
||||
nsCString(aReplyDomain),
|
||||
obj),
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
RegisterReplyRunnable::RegisterReplyRunnable(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const nsACString& aName,
|
||||
const nsACString& aRegType,
|
||||
const nsACString& domain,
|
||||
RegisterOperator* aContext)
|
||||
: mSdRef(aSdRef)
|
||||
, mFlags(aFlags)
|
||||
, mErrorCode(aErrorCode)
|
||||
, mName(aName)
|
||||
, mRegType(aRegType)
|
||||
, mDomain(domain)
|
||||
, mContext(aContext)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RegisterReplyRunnable::Run()
|
||||
{
|
||||
MOZ_ASSERT(mContext);
|
||||
|
||||
mContext->Reply(mSdRef,
|
||||
mFlags,
|
||||
mErrorCode,
|
||||
mName,
|
||||
mRegType,
|
||||
mDomain);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
RegisterReplyRunnable::Reply(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const char* aName,
|
||||
const char* aRegType,
|
||||
const char* domain,
|
||||
void* aContext)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
RegisterOperator* obj(reinterpret_cast<RegisterOperator*>(aContext));
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> thread(obj->GetThread());
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
thread->Dispatch(new RegisterReplyRunnable(aSdRef,
|
||||
aFlags,
|
||||
aErrorCode,
|
||||
nsCString(aName),
|
||||
nsCString(aRegType),
|
||||
nsCString(domain),
|
||||
obj),
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
ResolveReplyRunnable::ResolveReplyRunnable(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,
|
||||
ResolveOperator* aContext)
|
||||
: mSdRef(aSdRef)
|
||||
, mFlags(aFlags)
|
||||
, mInterfaceIndex(aInterfaceIndex)
|
||||
, mErrorCode(aErrorCode)
|
||||
, mFullname(aFullName)
|
||||
, mHosttarget(aHostTarget)
|
||||
, mPort(aPort)
|
||||
, mTxtLen(aTxtLen)
|
||||
, mTxtRecord(new unsigned char[aTxtLen])
|
||||
, mContext(aContext)
|
||||
{
|
||||
if (mTxtRecord) {
|
||||
memcpy(mTxtRecord.get(), aTxtRecord, aTxtLen);
|
||||
}
|
||||
}
|
||||
|
||||
ResolveReplyRunnable::~ResolveReplyRunnable()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ResolveReplyRunnable::Run()
|
||||
{
|
||||
MOZ_ASSERT(mContext);
|
||||
mContext->Reply(mSdRef,
|
||||
mFlags,
|
||||
mInterfaceIndex,
|
||||
mErrorCode,
|
||||
mFullname,
|
||||
mHosttarget,
|
||||
mPort,
|
||||
mTxtLen,
|
||||
mTxtRecord.get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ResolveReplyRunnable::Reply(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
uint32_t aInterfaceIndex,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const char* aFullName,
|
||||
const char* aHostTarget,
|
||||
uint16_t aPort,
|
||||
uint16_t aTxtLen,
|
||||
const unsigned char* aTxtRecord,
|
||||
void* aContext)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
ResolveOperator* obj(reinterpret_cast<ResolveOperator*>(aContext));
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> thread(obj->GetThread());
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
thread->Dispatch(new ResolveReplyRunnable(aSdRef,
|
||||
aFlags,
|
||||
aInterfaceIndex,
|
||||
aErrorCode,
|
||||
nsCString(aFullName),
|
||||
nsCString(aHostTarget),
|
||||
NativeEndian::swapFromNetworkOrder(aPort),
|
||||
aTxtLen,
|
||||
aTxtRecord,
|
||||
obj),
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
GetAddrInfoReplyRunnable::GetAddrInfoReplyRunnable(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
uint32_t aInterfaceIndex,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const nsACString& aHostName,
|
||||
const mozilla::net::NetAddr& aAddress,
|
||||
uint32_t aTTL,
|
||||
GetAddrInfoOperator* aContext)
|
||||
: mSdRef(aSdRef)
|
||||
, mFlags(aFlags)
|
||||
, mInterfaceIndex(aInterfaceIndex)
|
||||
, mErrorCode(aErrorCode)
|
||||
, mHostName(aHostName)
|
||||
, mAddress(aAddress)
|
||||
, mTTL(aTTL)
|
||||
, mContext(aContext)
|
||||
{
|
||||
}
|
||||
|
||||
GetAddrInfoReplyRunnable::~GetAddrInfoReplyRunnable()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GetAddrInfoReplyRunnable::Run()
|
||||
{
|
||||
MOZ_ASSERT(mContext);
|
||||
mContext->Reply(mSdRef,
|
||||
mFlags,
|
||||
mInterfaceIndex,
|
||||
mErrorCode,
|
||||
mHostName,
|
||||
mAddress,
|
||||
mTTL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
GetAddrInfoReplyRunnable::Reply(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
uint32_t aInterfaceIndex,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const char* aHostName,
|
||||
const struct sockaddr* aAddress,
|
||||
uint32_t aTTL,
|
||||
void* aContext)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
GetAddrInfoOperator* obj(reinterpret_cast<GetAddrInfoOperator*>(aContext));
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> thread(obj->GetThread());
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
NetAddr address;
|
||||
address.raw.family = aAddress->sa_family;
|
||||
|
||||
static_assert(sizeof(address.raw.data) >= sizeof(aAddress->sa_data),
|
||||
"size of sockaddr.sa_data is too big");
|
||||
memcpy(&address.raw.data, aAddress->sa_data, sizeof(aAddress->sa_data));
|
||||
|
||||
thread->Dispatch(new GetAddrInfoReplyRunnable(aSdRef,
|
||||
aFlags,
|
||||
aInterfaceIndex,
|
||||
aErrorCode,
|
||||
nsCString(aHostName),
|
||||
address,
|
||||
aTTL,
|
||||
obj),
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
164
netwerk/dns/mdns/libmdns/MDNSResponderReply.h
Normal file
164
netwerk/dns/mdns/libmdns/MDNSResponderReply.h
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_netwerk_dns_mdns_libmdns_MDNSResponderReply_h
|
||||
#define mozilla_netwerk_dns_mdns_libmdns_MDNSResponderReply_h
|
||||
|
||||
#include "dns_sd.h"
|
||||
#include "MDNSResponderOperator.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsIThread.h"
|
||||
#include "mozilla/net/DNS.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class BrowseReplyRunnable final : public Runnable
|
||||
{
|
||||
public:
|
||||
BrowseReplyRunnable(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
uint32_t aInterfaceIndex,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const nsACString& aServiceName,
|
||||
const nsACString& aRegType,
|
||||
const nsACString& aReplyDomain,
|
||||
BrowseOperator* aContext);
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
static void Reply(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
uint32_t aInterfaceIndex,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const char* aServiceName,
|
||||
const char* aRegType,
|
||||
const char* aReplyDomain,
|
||||
void* aContext);
|
||||
|
||||
private:
|
||||
DNSServiceRef mSdRef;
|
||||
DNSServiceFlags mFlags;
|
||||
uint32_t mInterfaceIndex;
|
||||
DNSServiceErrorType mErrorCode;
|
||||
nsCString mServiceName;
|
||||
nsCString mRegType;
|
||||
nsCString mReplyDomain;
|
||||
RefPtr<BrowseOperator> mContext;
|
||||
};
|
||||
|
||||
class RegisterReplyRunnable final : public Runnable
|
||||
{
|
||||
public:
|
||||
RegisterReplyRunnable(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const nsACString& aName,
|
||||
const nsACString& aRegType,
|
||||
const nsACString& aDomain,
|
||||
RegisterOperator* aContext);
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
static void Reply(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const char* aName,
|
||||
const char* aRegType,
|
||||
const char* aDomain,
|
||||
void* aContext);
|
||||
|
||||
private:
|
||||
DNSServiceRef mSdRef;
|
||||
DNSServiceFlags mFlags;
|
||||
DNSServiceErrorType mErrorCode;
|
||||
nsCString mName;
|
||||
nsCString mRegType;
|
||||
nsCString mDomain;
|
||||
RefPtr<RegisterOperator> mContext;
|
||||
};
|
||||
|
||||
class ResolveReplyRunnable final : public Runnable
|
||||
{
|
||||
public:
|
||||
ResolveReplyRunnable(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,
|
||||
ResolveOperator* aContext);
|
||||
~ResolveReplyRunnable();
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
static void Reply(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
uint32_t aInterfaceIndex,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const char* aFullName,
|
||||
const char* aHostTarget,
|
||||
uint16_t aPort,
|
||||
uint16_t aTxtLen,
|
||||
const unsigned char* aTxtRecord,
|
||||
void* aContext);
|
||||
|
||||
private:
|
||||
DNSServiceRef mSdRef;
|
||||
DNSServiceFlags mFlags;
|
||||
uint32_t mInterfaceIndex;
|
||||
DNSServiceErrorType mErrorCode;
|
||||
nsCString mFullname;
|
||||
nsCString mHosttarget;
|
||||
uint16_t mPort;
|
||||
uint16_t mTxtLen;
|
||||
UniquePtr<unsigned char> mTxtRecord;
|
||||
RefPtr<ResolveOperator> mContext;
|
||||
};
|
||||
|
||||
class GetAddrInfoReplyRunnable final : public Runnable
|
||||
{
|
||||
public:
|
||||
GetAddrInfoReplyRunnable(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
uint32_t aInterfaceIndex,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const nsACString& aHostName,
|
||||
const mozilla::net::NetAddr& aAddress,
|
||||
uint32_t aTTL,
|
||||
GetAddrInfoOperator* aContext);
|
||||
~GetAddrInfoReplyRunnable();
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
static void Reply(DNSServiceRef aSdRef,
|
||||
DNSServiceFlags aFlags,
|
||||
uint32_t aInterfaceIndex,
|
||||
DNSServiceErrorType aErrorCode,
|
||||
const char* aHostName,
|
||||
const struct sockaddr* aAddress,
|
||||
uint32_t aTTL,
|
||||
void* aContext);
|
||||
|
||||
private:
|
||||
DNSServiceRef mSdRef;
|
||||
DNSServiceFlags mFlags;
|
||||
uint32_t mInterfaceIndex;
|
||||
DNSServiceErrorType mErrorCode;
|
||||
nsCString mHostName;
|
||||
mozilla::net::NetAddr mAddress;
|
||||
uint32_t mTTL;
|
||||
RefPtr<GetAddrInfoOperator> mContext;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_netwerk_dns_mdns_libmdns_MDNSResponderReply_h
|
||||
|
|
@ -3,20 +3,32 @@
|
|||
# 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/.
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'nsDNSServiceDiscovery.js',
|
||||
'nsDNSServiceDiscovery.manifest',
|
||||
]
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
SOURCES += [
|
||||
'MDNSResponderOperator.cpp',
|
||||
'MDNSResponderReply.cpp',
|
||||
'nsDNSServiceDiscovery.cpp',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'fallback/DataReader.jsm',
|
||||
'fallback/DataWriter.jsm',
|
||||
'fallback/DNSPacket.jsm',
|
||||
'fallback/DNSRecord.jsm',
|
||||
'fallback/DNSResourceRecord.jsm',
|
||||
'fallback/DNSTypes.jsm',
|
||||
'fallback/MulticastDNS.jsm',
|
||||
]
|
||||
LOCAL_INCLUDES += [
|
||||
'/netwerk/base',
|
||||
]
|
||||
|
||||
else:
|
||||
EXTRA_COMPONENTS += [
|
||||
'nsDNSServiceDiscovery.js',
|
||||
'nsDNSServiceDiscovery.manifest',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'fallback/DataReader.jsm',
|
||||
'fallback/DataWriter.jsm',
|
||||
'fallback/DNSPacket.jsm',
|
||||
'fallback/DNSRecord.jsm',
|
||||
'fallback/DNSResourceRecord.jsm',
|
||||
'fallback/DNSTypes.jsm',
|
||||
'fallback/MulticastDNS.jsm',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'nsDNSServiceInfo.cpp',
|
||||
|
|
|
|||
262
netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp
Normal file
262
netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
/* -*- 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 "nsDNSServiceDiscovery.h"
|
||||
#include "MDNSResponderOperator.h"
|
||||
#include "nsICancelable.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "private/pprio.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
namespace {
|
||||
|
||||
inline void
|
||||
StartService()
|
||||
{
|
||||
/*** STUB ***/
|
||||
}
|
||||
|
||||
inline void
|
||||
StopService()
|
||||
{
|
||||
/*** STUB ***/
|
||||
}
|
||||
|
||||
class ServiceCounter
|
||||
{
|
||||
public:
|
||||
static bool IsServiceRunning()
|
||||
{
|
||||
return !!sUseCount;
|
||||
}
|
||||
|
||||
private:
|
||||
static uint32_t sUseCount;
|
||||
|
||||
protected:
|
||||
ServiceCounter()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!sUseCount++) {
|
||||
StartService();
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~ServiceCounter()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!--sUseCount) {
|
||||
StopService();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
uint32_t ServiceCounter::sUseCount = 0;
|
||||
|
||||
class DiscoveryRequest final : public nsICancelable
|
||||
, private ServiceCounter
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICANCELABLE
|
||||
|
||||
explicit DiscoveryRequest(nsDNSServiceDiscovery* aService,
|
||||
nsIDNSServiceDiscoveryListener* aListener);
|
||||
|
||||
private:
|
||||
virtual ~DiscoveryRequest() { Cancel(NS_OK); }
|
||||
|
||||
RefPtr<nsDNSServiceDiscovery> mService;
|
||||
nsIDNSServiceDiscoveryListener* mListener;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(DiscoveryRequest, nsICancelable)
|
||||
|
||||
DiscoveryRequest::DiscoveryRequest(nsDNSServiceDiscovery* aService,
|
||||
nsIDNSServiceDiscoveryListener* aListener)
|
||||
: mService(aService)
|
||||
, mListener(aListener)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DiscoveryRequest::Cancel(nsresult aReason)
|
||||
{
|
||||
if (mService) {
|
||||
mService->StopDiscovery(mListener);
|
||||
}
|
||||
|
||||
mService = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class RegisterRequest final : public nsICancelable
|
||||
, private ServiceCounter
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICANCELABLE
|
||||
|
||||
explicit RegisterRequest(nsDNSServiceDiscovery* aService,
|
||||
nsIDNSRegistrationListener* aListener);
|
||||
|
||||
private:
|
||||
virtual ~RegisterRequest() { Cancel(NS_OK); }
|
||||
|
||||
RefPtr<nsDNSServiceDiscovery> mService;
|
||||
nsIDNSRegistrationListener* mListener;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(RegisterRequest, nsICancelable)
|
||||
|
||||
RegisterRequest::RegisterRequest(nsDNSServiceDiscovery* aService,
|
||||
nsIDNSRegistrationListener* aListener)
|
||||
: mService(aService)
|
||||
, mListener(aListener)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RegisterRequest::Cancel(nsresult aReason)
|
||||
{
|
||||
if (mService) {
|
||||
mService->UnregisterService(mListener);
|
||||
}
|
||||
|
||||
mService = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsDNSServiceDiscovery, nsIDNSServiceDiscovery)
|
||||
|
||||
nsDNSServiceDiscovery::~nsDNSServiceDiscovery()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDNSServiceDiscovery::Init()
|
||||
{
|
||||
if (!XRE_IsParentProcess()) {
|
||||
MOZ_ASSERT(false, "nsDNSServiceDiscovery can only be used in parent process");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDNSServiceDiscovery::StartDiscovery(const nsACString& aServiceType,
|
||||
nsIDNSServiceDiscoveryListener* aListener,
|
||||
nsICancelable** aRetVal)
|
||||
{
|
||||
MOZ_ASSERT(aRetVal);
|
||||
|
||||
nsresult rv;
|
||||
if (NS_WARN_IF(NS_FAILED(rv = StopDiscovery(aListener)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICancelable> req = new DiscoveryRequest(this, aListener);
|
||||
RefPtr<BrowseOperator> browserOp = new BrowseOperator(aServiceType,
|
||||
aListener);
|
||||
if (NS_WARN_IF(NS_FAILED(rv = browserOp->Start()))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mDiscoveryMap.Put(aListener, browserOp);
|
||||
|
||||
req.forget(aRetVal);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDNSServiceDiscovery::StopDiscovery(nsIDNSServiceDiscoveryListener* aListener)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
RefPtr<BrowseOperator> browserOp;
|
||||
if (!mDiscoveryMap.Get(aListener, getter_AddRefs(browserOp))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
browserOp->Cancel(); // cancel non-started operation
|
||||
if (NS_WARN_IF(NS_FAILED(rv = browserOp->Stop()))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mDiscoveryMap.Remove(aListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDNSServiceDiscovery::RegisterService(nsIDNSServiceInfo* aServiceInfo,
|
||||
nsIDNSRegistrationListener* aListener,
|
||||
nsICancelable** aRetVal)
|
||||
{
|
||||
MOZ_ASSERT(aRetVal);
|
||||
|
||||
nsresult rv;
|
||||
if (NS_WARN_IF(NS_FAILED(rv = UnregisterService(aListener)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICancelable> req = new RegisterRequest(this, aListener);
|
||||
RefPtr<RegisterOperator> registerOp = new RegisterOperator(aServiceInfo,
|
||||
aListener);
|
||||
if (NS_WARN_IF(NS_FAILED(rv = registerOp->Start()))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mRegisterMap.Put(aListener, registerOp);
|
||||
|
||||
req.forget(aRetVal);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDNSServiceDiscovery::UnregisterService(nsIDNSRegistrationListener* aListener)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
RefPtr<RegisterOperator> registerOp;
|
||||
if (!mRegisterMap.Get(aListener, getter_AddRefs(registerOp))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
registerOp->Cancel(); // cancel non-started operation
|
||||
if (NS_WARN_IF(NS_FAILED(rv = registerOp->Stop()))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mRegisterMap.Remove(aListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDNSServiceDiscovery::ResolveService(nsIDNSServiceInfo* aServiceInfo,
|
||||
nsIDNSServiceResolveListener* aListener)
|
||||
{
|
||||
if (!ServiceCounter::IsServiceRunning()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
RefPtr<ResolveOperator> resolveOp = new ResolveOperator(aServiceInfo,
|
||||
aListener);
|
||||
if (NS_WARN_IF(NS_FAILED(rv = resolveOp->Start()))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
49
netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h
Normal file
49
netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceDiscovery_h
|
||||
#define mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceDiscovery_h
|
||||
|
||||
#include "MDNSResponderOperator.h"
|
||||
#include "nsIDNSServiceDiscovery.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class BrowseOperator;
|
||||
class RegisterOperator;
|
||||
|
||||
class nsDNSServiceDiscovery final : public nsIDNSServiceDiscovery
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIDNSSERVICEDISCOVERY
|
||||
|
||||
explicit nsDNSServiceDiscovery() = default;
|
||||
|
||||
/*
|
||||
** The mDNS service is started on demand. If no one uses, mDNS service will not
|
||||
** start. Therefore, all operations before service started will fail
|
||||
** and get error code |kDNSServiceErr_ServiceNotRunning| defined in dns_sd.h.
|
||||
**/
|
||||
nsresult Init();
|
||||
|
||||
nsresult StopDiscovery(nsIDNSServiceDiscoveryListener* aListener);
|
||||
nsresult UnregisterService(nsIDNSRegistrationListener* aListener);
|
||||
|
||||
private:
|
||||
virtual ~nsDNSServiceDiscovery();
|
||||
|
||||
nsRefPtrHashtable<nsISupportsHashKey, BrowseOperator> mDiscoveryMap;
|
||||
nsRefPtrHashtable<nsISupportsHashKey, RegisterOperator> mRegisterMap;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceDiscovery_h
|
||||
|
|
@ -11,7 +11,6 @@ XPIDL_MODULE = 'necko_http'
|
|||
|
||||
SOURCES += [
|
||||
'mozTXTToHTMLConv.cpp',
|
||||
'nsBinHexDecoder.cpp',
|
||||
'nsDirIndex.cpp',
|
||||
'nsDirIndexParser.cpp',
|
||||
'nsHTTPCompressConv.cpp',
|
||||
|
|
@ -27,6 +26,11 @@ if 'ftp' in CONFIG['NECKO_PROTOCOLS']:
|
|||
'ParseFTPList.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'cocoa':
|
||||
SOURCES += [
|
||||
'nsBinHexDecoder.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
|
|
|
|||
13
netwerk/system/mac/moz.build
Normal file
13
netwerk/system/mac/moz.build
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# 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/.
|
||||
|
||||
SOURCES += [
|
||||
'nsNetworkLinkService.mm',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
if CONFIG['CLANG_CXX']:
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
||||
54
netwerk/system/mac/nsNetworkLinkService.h
Normal file
54
netwerk/system/mac/nsNetworkLinkService.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef NSNETWORKLINKSERVICEMAC_H_
|
||||
#define NSNETWORKLINKSERVICEMAC_H_
|
||||
|
||||
#include "nsINetworkLinkService.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
#include <SystemConfiguration/SCNetworkReachability.h>
|
||||
#include <SystemConfiguration/SystemConfiguration.h>
|
||||
|
||||
class nsNetworkLinkService : public nsINetworkLinkService,
|
||||
public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSINETWORKLINKSERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsNetworkLinkService();
|
||||
|
||||
nsresult Init();
|
||||
nsresult Shutdown();
|
||||
|
||||
protected:
|
||||
virtual ~nsNetworkLinkService();
|
||||
|
||||
private:
|
||||
bool mLinkUp;
|
||||
bool mStatusKnown;
|
||||
|
||||
// Toggles allowing the sending of network-changed event.
|
||||
bool mAllowChangedEvent;
|
||||
|
||||
SCNetworkReachabilityRef mReachability;
|
||||
CFRunLoopRef mCFRunLoop;
|
||||
CFRunLoopSourceRef mRunLoopSource;
|
||||
SCDynamicStoreRef mStoreRef;
|
||||
|
||||
void UpdateReachability();
|
||||
void SendEvent(bool aNetworkChanged);
|
||||
static void ReachabilityChanged(SCNetworkReachabilityRef target,
|
||||
SCNetworkConnectionFlags flags,
|
||||
void *info);
|
||||
static void IPConfigChanged(SCDynamicStoreRef store,
|
||||
CFArrayRef changedKeys,
|
||||
void *info);
|
||||
void calculateNetworkId(void);
|
||||
nsCString mNetworkId;
|
||||
};
|
||||
|
||||
#endif /* NSNETWORKLINKSERVICEMAC_H_ */
|
||||
526
netwerk/system/mac/nsNetworkLinkService.mm
Normal file
526
netwerk/system/mac/nsNetworkLinkService.mm
Normal file
|
|
@ -0,0 +1,526 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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 <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCRT.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/SHA1.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "nsNetworkLinkService.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <netinet/in.h>
|
||||
|
||||
#define NETWORK_NOTIFY_CHANGED_PREF "network.notify.changed"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static LazyLogModule gNotifyAddrLog("nsNotifyAddr");
|
||||
#define LOG(args) MOZ_LOG(gNotifyAddrLog, mozilla::LogLevel::Debug, args)
|
||||
|
||||
// If non-successful, extract the error code and return it. This
|
||||
// error code dance is inspired by
|
||||
// http://developer.apple.com/technotes/tn/tn1145.html
|
||||
static OSStatus getErrorCodeBool(Boolean success)
|
||||
{
|
||||
OSStatus err = noErr;
|
||||
if (!success) {
|
||||
int scErr = ::SCError();
|
||||
if (scErr == kSCStatusOK) {
|
||||
scErr = kSCStatusFailed;
|
||||
}
|
||||
err = scErr;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// If given a NULL pointer, return the error code.
|
||||
static OSStatus getErrorCodePtr(const void *value)
|
||||
{
|
||||
return getErrorCodeBool(value != NULL);
|
||||
}
|
||||
|
||||
// Convenience function to allow NULL input.
|
||||
static void CFReleaseSafe(CFTypeRef cf)
|
||||
{
|
||||
if (cf) {
|
||||
// "If cf is NULL, this will cause a runtime error and your
|
||||
// application will crash." / Apple docs
|
||||
::CFRelease(cf);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsNetworkLinkService,
|
||||
nsINetworkLinkService,
|
||||
nsIObserver)
|
||||
|
||||
nsNetworkLinkService::nsNetworkLinkService()
|
||||
: mLinkUp(true)
|
||||
, mStatusKnown(false)
|
||||
, mAllowChangedEvent(true)
|
||||
, mReachability(nullptr)
|
||||
, mCFRunLoop(nullptr)
|
||||
, mRunLoopSource(nullptr)
|
||||
, mStoreRef(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
nsNetworkLinkService::~nsNetworkLinkService() = default;
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetworkLinkService::GetIsLinkUp(bool *aIsUp)
|
||||
{
|
||||
*aIsUp = mLinkUp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetworkLinkService::GetLinkStatusKnown(bool *aIsUp)
|
||||
{
|
||||
*aIsUp = mStatusKnown;
|
||||
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;
|
||||
}
|
||||
|
||||
#ifndef SA_SIZE
|
||||
#define SA_SIZE(sa) \
|
||||
( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
|
||||
sizeof(uint32_t) : \
|
||||
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1) ) )
|
||||
#endif
|
||||
|
||||
static char *getMac(struct sockaddr_dl *sdl, char *buf, size_t bufsize)
|
||||
{
|
||||
char *cp;
|
||||
int n, p = 0;
|
||||
|
||||
buf[0] = 0;
|
||||
cp = (char *)LLADDR(sdl);
|
||||
n = sdl->sdl_alen;
|
||||
if (n > 0) {
|
||||
while (--n >= 0) {
|
||||
p += snprintf(&buf[p], bufsize - p, "%02x%s",
|
||||
*cp++ & 0xff, n > 0 ? ":" : "");
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* If the IP matches, get the MAC and return true */
|
||||
static bool matchIp(struct sockaddr_dl *sdl, struct sockaddr_inarp *addr,
|
||||
char *ip, char *buf, size_t bufsize)
|
||||
{
|
||||
if (sdl->sdl_alen) {
|
||||
if (!strcmp(inet_ntoa(addr->sin_addr), ip)) {
|
||||
getMac(sdl, buf, bufsize);
|
||||
return true; /* done! */
|
||||
}
|
||||
}
|
||||
return false; /* continue */
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan for the 'IP' address in the ARP table and store the corresponding MAC
|
||||
* address in 'mac'. The output buffer is 'maclen' bytes big.
|
||||
*
|
||||
* Returns 'true' if it found the IP and returns a MAC.
|
||||
*/
|
||||
static bool scanArp(char *ip, char *mac, size_t maclen)
|
||||
{
|
||||
int mib[6];
|
||||
char *lim, *next;
|
||||
int st;
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = PF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = AF_INET;
|
||||
mib[4] = NET_RT_FLAGS;
|
||||
mib[5] = RTF_LLINFO;
|
||||
|
||||
size_t needed;
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
|
||||
return false;
|
||||
}
|
||||
if (needed == 0) {
|
||||
// empty table
|
||||
return false;
|
||||
}
|
||||
|
||||
UniquePtr <char[]>buf(new char[needed]);
|
||||
|
||||
for (;;) {
|
||||
st = sysctl(mib, 6, &buf[0], &needed, NULL, 0);
|
||||
if (st == 0 || errno != ENOMEM) {
|
||||
break;
|
||||
}
|
||||
needed += needed / 8;
|
||||
|
||||
auto tmp = MakeUnique<char[]>(needed);
|
||||
memcpy(&tmp[0], &buf[0], needed);
|
||||
buf = Move(tmp);
|
||||
}
|
||||
if (st == -1) {
|
||||
return false;
|
||||
}
|
||||
lim = &buf[needed];
|
||||
|
||||
struct rt_msghdr *rtm;
|
||||
for (next = &buf[0]; next < lim; next += rtm->rtm_msglen) {
|
||||
rtm = reinterpret_cast<struct rt_msghdr *>(next);
|
||||
struct sockaddr_inarp *sin2 =
|
||||
reinterpret_cast<struct sockaddr_inarp *>(rtm + 1);
|
||||
struct sockaddr_dl *sdl =
|
||||
reinterpret_cast<struct sockaddr_dl *>
|
||||
((char *)sin2 + SA_SIZE(sin2));
|
||||
if (matchIp(sdl, sin2, ip, mac, maclen)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int routingTable(char *gw, size_t aGwLen)
|
||||
{
|
||||
size_t needed;
|
||||
int mib[6];
|
||||
struct rt_msghdr *rtm;
|
||||
struct sockaddr *sa;
|
||||
struct sockaddr_in *sockin;
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = PF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = 0;
|
||||
mib[4] = NET_RT_DUMP;
|
||||
mib[5] = 0;
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
UniquePtr <char[]>buf(new char[needed]);
|
||||
|
||||
if (sysctl(mib, 6, &buf[0], &needed, NULL, 0) < 0) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
rtm = reinterpret_cast<struct rt_msghdr *>(&buf[0]);
|
||||
sa = reinterpret_cast<struct sockaddr *>(rtm + 1);
|
||||
sa = reinterpret_cast<struct sockaddr *>(SA_SIZE(sa) + (char *)sa);
|
||||
sockin = reinterpret_cast<struct sockaddr_in *>(sa);
|
||||
inet_ntop(AF_INET, &sockin->sin_addr.s_addr, gw, aGwLen-1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Figure out the current "network identification" string.
|
||||
//
|
||||
// It detects the IP of the default gateway in the routing table, then the MAC
|
||||
// address of that IP in the ARP table before it hashes that string (to avoid
|
||||
// information leakage).
|
||||
//
|
||||
void nsNetworkLinkService::calculateNetworkId(void)
|
||||
{
|
||||
bool found = false;
|
||||
char hw[MAXHOSTNAMELEN];
|
||||
if (!routingTable(hw, sizeof(hw))) {
|
||||
char mac[256]; // big enough for a printable MAC address
|
||||
if (scanArp(hw, mac, sizeof(mac))) {
|
||||
LOG(("networkid: MAC %s\n", hw));
|
||||
nsAutoCString mac(hw);
|
||||
// This 'addition' could potentially be a
|
||||
// fixed number from the profile or something.
|
||||
nsAutoCString addition("local-rubbish");
|
||||
nsAutoCString output;
|
||||
SHA1Sum sha1;
|
||||
nsCString combined(mac + addition);
|
||||
sha1.update(combined.get(), combined.Length());
|
||||
uint8_t digest[SHA1Sum::kHashSize];
|
||||
sha1.finish(digest);
|
||||
nsCString newString(reinterpret_cast<char*>(digest),
|
||||
SHA1Sum::kHashSize);
|
||||
nsresult rv = Base64Encode(newString, output);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
LOG(("networkid: id %s\n", output.get()));
|
||||
if (mNetworkId != output) {
|
||||
// new id
|
||||
mNetworkId = output;
|
||||
}
|
||||
else {
|
||||
// same id
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
// no id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetworkLinkService::Observe(nsISupports *subject,
|
||||
const char *topic,
|
||||
const char16_t *data)
|
||||
{
|
||||
if (!strcmp(topic, "xpcom-shutdown")) {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsNetworkLinkService::IPConfigChanged(SCDynamicStoreRef aStoreREf,
|
||||
CFArrayRef aChangedKeys,
|
||||
void *aInfo)
|
||||
{
|
||||
nsNetworkLinkService *service =
|
||||
static_cast<nsNetworkLinkService*>(aInfo);
|
||||
service->SendEvent(true);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNetworkLinkService::Init(void)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
do_GetService("@mozilla.org/observer-service;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = observerService->AddObserver(this, "xpcom-shutdown", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
Preferences::AddBoolVarCache(&mAllowChangedEvent,
|
||||
NETWORK_NOTIFY_CHANGED_PREF, true);
|
||||
|
||||
// If the network reachability API can reach 0.0.0.0 without
|
||||
// requiring a connection, there is a network interface available.
|
||||
struct sockaddr_in addr;
|
||||
bzero(&addr, sizeof(addr));
|
||||
addr.sin_len = sizeof(addr);
|
||||
addr.sin_family = AF_INET;
|
||||
mReachability =
|
||||
::SCNetworkReachabilityCreateWithAddress(NULL,
|
||||
(struct sockaddr *)&addr);
|
||||
if (!mReachability) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
SCNetworkReachabilityContext context = {0, this, NULL, NULL, NULL};
|
||||
if (!::SCNetworkReachabilitySetCallback(mReachability,
|
||||
ReachabilityChanged,
|
||||
&context)) {
|
||||
NS_WARNING("SCNetworkReachabilitySetCallback failed.");
|
||||
::CFRelease(mReachability);
|
||||
mReachability = NULL;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
SCDynamicStoreContext storeContext = {0, this, NULL, NULL, NULL};
|
||||
mStoreRef =
|
||||
::SCDynamicStoreCreate(NULL,
|
||||
CFSTR("AddIPAddressListChangeCallbackSCF"),
|
||||
IPConfigChanged, &storeContext);
|
||||
|
||||
CFStringRef patterns[2] = {NULL, NULL};
|
||||
OSStatus err = getErrorCodePtr(mStoreRef);
|
||||
if (err == noErr) {
|
||||
// This pattern is "State:/Network/Service/[^/]+/IPv4".
|
||||
patterns[0] =
|
||||
::SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
|
||||
kSCDynamicStoreDomainState,
|
||||
kSCCompAnyRegex,
|
||||
kSCEntNetIPv4);
|
||||
err = getErrorCodePtr(patterns[0]);
|
||||
if (err == noErr) {
|
||||
// This pattern is "State:/Network/Service/[^/]+/IPv6".
|
||||
patterns[1] =
|
||||
::SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
|
||||
kSCDynamicStoreDomainState,
|
||||
kSCCompAnyRegex,
|
||||
kSCEntNetIPv6);
|
||||
err = getErrorCodePtr(patterns[1]);
|
||||
}
|
||||
}
|
||||
|
||||
CFArrayRef patternList = NULL;
|
||||
// Create a pattern list containing just one pattern,
|
||||
// then tell SCF that we want to watch changes in keys
|
||||
// that match that pattern list, then create our run loop
|
||||
// source.
|
||||
if (err == noErr) {
|
||||
patternList = ::CFArrayCreate(NULL, (const void **) patterns,
|
||||
2, &kCFTypeArrayCallBacks);
|
||||
if (!patternList) {
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
if (err == noErr) {
|
||||
err =
|
||||
getErrorCodeBool(::SCDynamicStoreSetNotificationKeys(mStoreRef,
|
||||
NULL,
|
||||
patternList));
|
||||
}
|
||||
|
||||
if (err == noErr) {
|
||||
mRunLoopSource =
|
||||
::SCDynamicStoreCreateRunLoopSource(NULL, mStoreRef, 0);
|
||||
err = getErrorCodePtr(mRunLoopSource);
|
||||
}
|
||||
|
||||
CFReleaseSafe(patterns[0]);
|
||||
CFReleaseSafe(patterns[1]);
|
||||
CFReleaseSafe(patternList);
|
||||
|
||||
if (err != noErr) {
|
||||
CFReleaseSafe(mStoreRef);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Get the current run loop. This service is initialized at startup,
|
||||
// so we shouldn't run in to any problems with modal dialog run loops.
|
||||
mCFRunLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
|
||||
if (!mCFRunLoop) {
|
||||
NS_WARNING("Could not get current run loop.");
|
||||
::CFRelease(mReachability);
|
||||
mReachability = NULL;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
::CFRetain(mCFRunLoop);
|
||||
|
||||
::CFRunLoopAddSource(mCFRunLoop, mRunLoopSource, kCFRunLoopDefaultMode);
|
||||
|
||||
if (!::SCNetworkReachabilityScheduleWithRunLoop(mReachability, mCFRunLoop,
|
||||
kCFRunLoopDefaultMode)) {
|
||||
NS_WARNING("SCNetworkReachabilityScheduleWIthRunLoop failed.");
|
||||
::CFRelease(mReachability);
|
||||
mReachability = NULL;
|
||||
::CFRelease(mCFRunLoop);
|
||||
mCFRunLoop = NULL;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
UpdateReachability();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNetworkLinkService::Shutdown()
|
||||
{
|
||||
if (!::SCNetworkReachabilityUnscheduleFromRunLoop(mReachability,
|
||||
mCFRunLoop,
|
||||
kCFRunLoopDefaultMode)) {
|
||||
NS_WARNING("SCNetworkReachabilityUnscheduleFromRunLoop failed.");
|
||||
}
|
||||
|
||||
CFRunLoopRemoveSource(mCFRunLoop, mRunLoopSource, kCFRunLoopDefaultMode);
|
||||
|
||||
::CFRelease(mReachability);
|
||||
mReachability = nullptr;
|
||||
|
||||
::CFRelease(mCFRunLoop);
|
||||
mCFRunLoop = nullptr;
|
||||
|
||||
::CFRelease(mStoreRef);
|
||||
mStoreRef = nullptr;
|
||||
|
||||
::CFRelease(mRunLoopSource);
|
||||
mRunLoopSource = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsNetworkLinkService::UpdateReachability()
|
||||
{
|
||||
if (!mReachability) {
|
||||
return;
|
||||
}
|
||||
|
||||
SCNetworkConnectionFlags flags;
|
||||
if (!::SCNetworkReachabilityGetFlags(mReachability, &flags)) {
|
||||
mStatusKnown = false;
|
||||
return;
|
||||
}
|
||||
|
||||
bool reachable = (flags & kSCNetworkFlagsReachable) != 0;
|
||||
bool needsConnection = (flags & kSCNetworkFlagsConnectionRequired) != 0;
|
||||
|
||||
mLinkUp = (reachable && !needsConnection);
|
||||
mStatusKnown = true;
|
||||
}
|
||||
|
||||
void
|
||||
nsNetworkLinkService::SendEvent(bool aNetworkChanged)
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
if (!observerService) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *event;
|
||||
if (aNetworkChanged) {
|
||||
if (!mAllowChangedEvent) {
|
||||
return;
|
||||
}
|
||||
event = NS_NETWORK_LINK_DATA_CHANGED;
|
||||
} else if (!mStatusKnown) {
|
||||
event = NS_NETWORK_LINK_DATA_UNKNOWN;
|
||||
} else {
|
||||
event = mLinkUp ? NS_NETWORK_LINK_DATA_UP
|
||||
: NS_NETWORK_LINK_DATA_DOWN;
|
||||
}
|
||||
LOG(("SendEvent: network is '%s'\n", event));
|
||||
|
||||
observerService->NotifyObservers(static_cast<nsINetworkLinkService*>(this),
|
||||
NS_NETWORK_LINK_TOPIC,
|
||||
NS_ConvertASCIItoUTF16(event).get());
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsNetworkLinkService::ReachabilityChanged(SCNetworkReachabilityRef target,
|
||||
SCNetworkConnectionFlags flags,
|
||||
void *info)
|
||||
{
|
||||
nsNetworkLinkService *service =
|
||||
static_cast<nsNetworkLinkService*>(info);
|
||||
|
||||
service->UpdateReachability();
|
||||
service->SendEvent(false);
|
||||
service->calculateNetworkId();
|
||||
}
|
||||
|
|
@ -5,5 +5,7 @@
|
|||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
DIRS += ['win32']
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
DIRS += ['mac']
|
||||
elif CONFIG['OS_ARCH'] == 'Linux':
|
||||
DIRS += ['linux']
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue