diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java index 2297a8bdf095..3ada0c610424 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java @@ -155,6 +155,7 @@ public class GeckoApplication extends Application NotificationHelper.getInstance(context).init(); MulticastDNSManager.getInstance(context).init(); + NetworkInfoService.getInstance(context).init(); // Make sure that all browser-ish applications default to the real LocalBrowserDB. // GeckoView consumers use their own Application class, so this doesn't affect them. diff --git a/mobile/android/base/java/org/mozilla/gecko/NetworkInfoService.java b/mobile/android/base/java/org/mozilla/gecko/NetworkInfoService.java new file mode 100644 index 000000000000..fca3c7e2f6ed --- /dev/null +++ b/mobile/android/base/java/org/mozilla/gecko/NetworkInfoService.java @@ -0,0 +1,144 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- + * 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/. */ + +package org.mozilla.gecko; + +import org.mozilla.gecko.EventDispatcher; +import org.mozilla.gecko.util.EventCallback; +import org.mozilla.gecko.util.NativeEventListener; +import org.mozilla.gecko.util.NativeJSObject; +import org.mozilla.gecko.util.ThreadUtils; + +import org.json.JSONArray; + +import android.content.Context; +import android.os.Build; +import android.support.annotation.UiThread; +import android.util.Log; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; + +public class NetworkInfoService implements NativeEventListener { + static final String LOGTAG = "NetworkInfoService"; + static NetworkInfoService instance = null; + + static final String MSG_LIST_NETWORK_ADDRESSES = "NetworkInfoService:ListNetworkAddresses"; + static final String MSG_GET_HOSTNAME = "NetworkInfoService:GetHostname"; + + public static NetworkInfoService getInstance(final Context context) { + if (instance == null) { + instance = new NetworkInfoService(context); + } + return instance; + } + + NetworkInfoService(final Context context) { + } + + @UiThread + public void init() { + ThreadUtils.assertOnUiThread(); + EventDispatcher.getInstance().registerGeckoThreadListener(this, + MSG_LIST_NETWORK_ADDRESSES, + MSG_GET_HOSTNAME); + } + + @UiThread + public void tearDown() { + ThreadUtils.assertOnUiThread(); + EventDispatcher.getInstance().unregisterGeckoThreadListener(this, + MSG_LIST_NETWORK_ADDRESSES, + MSG_GET_HOSTNAME); + } + + @Override + public void handleMessage(final String event, final NativeJSObject message, + final EventCallback callback) + { + Log.v(LOGTAG, "handleMessage: " + event); + + switch (event) { + case MSG_LIST_NETWORK_ADDRESSES: { + handleListNetworkAddresses(callback); + break; + } + case MSG_GET_HOSTNAME: { + handleGetHostname(callback); + break; + } + } + } + + void handleListNetworkAddresses(final EventCallback callback) { + Set addresses = new HashSet(); + try { + Enumeration ifaceEnum = NetworkInterface.getNetworkInterfaces(); + if (ifaceEnum != null) { + while (ifaceEnum.hasMoreElements()) { + NetworkInterface iface = ifaceEnum.nextElement(); + Enumeration addrList = iface.getInetAddresses(); + while (addrList.hasMoreElements()) { + InetAddress addr = addrList.nextElement(); + addresses.add(addr.getHostAddress()); + } + } + } + } catch (SocketException exc) { + callback.sendError(-1); + return; + } + + JSONArray array = new JSONArray(); + for (String addr : addresses) { + array.put(addr); + } + callback.sendSuccess(array); + } + + void handleGetHostname(final EventCallback callback) { + // callback.sendError(-1); + callback.sendSuccess(getDeviceName()); + } + + private static String getDeviceName() { + String manufacturer = Build.MANUFACTURER; + String model = Build.MODEL; + if (model.startsWith(manufacturer)) { + return capitalize(model); + } + return capitalize(manufacturer) + " " + model; + } + + private static String capitalize(String str) { + if (str.length() <= 1) + return str; + + // Capitalize the manufacturer's first letter. + char ch0 = str.charAt(0); + if (Character.isLetter(ch0) && Character.isLowerCase(ch0)) { + boolean upcase = true; + // But don't capitalize the first letter if it's an 'i' followed + // by a non-lowercase letter. Sheesh. + if (ch0 == 'i') { + if (str.length() >= 2) { + char ch1 = str.charAt(1); + if (!Character.isLetter(ch1) || !Character.isLowerCase(ch1)) { + upcase = false; + } + } + } + if (upcase) { + return Character.toUpperCase(ch0) + str.substring(1); + } + } + return str; + } + +} diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index 6067c327da86..e732240cfff2 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -469,6 +469,7 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [ 'menu/MenuPanel.java', 'menu/MenuPopup.java', 'MotionEventInterceptor.java', + 'NetworkInfoService.java', 'NotificationClient.java', 'NotificationHandler.java', 'NotificationHelper.java', diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index a31e1c97020b..3131cf1304d0 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -262,6 +262,8 @@ @BINPATH@/components/zipwriter.xpt ; JavaScript components +@BINPATH@/components/nsNetworkInfoService.manifest +@BINPATH@/components/nsNetworkInfoService.js @BINPATH@/components/ChromeNotifications.js @BINPATH@/components/ChromeNotifications.manifest @BINPATH@/components/ConsoleAPI.manifest diff --git a/netwerk/base/NetworkInfoServiceAndroid.jsm b/netwerk/base/NetworkInfoServiceAndroid.jsm new file mode 100644 index 000000000000..af363082ff5f --- /dev/null +++ b/netwerk/base/NetworkInfoServiceAndroid.jsm @@ -0,0 +1,67 @@ +// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- +/* 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/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["NetworkInfoServiceAndroid"]; + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import("resource://gre/modules/Messaging.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/AndroidLog.jsm"); + +var log = AndroidLog.d.bind(null, "NetworkInfoServiceAndroid"); + +const FAILURE_INTERNAL_ERROR = -65537; +const MSG_TAG = 'NetworkInfoService'; + +// Helper function for sending commands to Java. +function send(type, data, callback) { + if (type[0] == ":") { + type = MSG_TAG + type; + } + let msg = { type }; + + for (let i in data) { + try { + msg[i] = data[i]; + } catch (e) { + } + } + + Messaging.sendRequestForResult(msg) + .then(result => callback(result, null), + err => callback(null, typeof err === "number" ? err : FAILURE_INTERNAL_ERROR)); +} + +class NetworkInfoServiceAndroid { + constructor() { + } + + listNetworkAddresses(aListener) { + send(":ListNetworkAddresses", {}, (result, err) => { + if (err) { + log("ListNetworkAddresses Failed: (" + err + ")"); + aListener.onListNetworkAddressesFailed(); + } else { + log("ListNetworkAddresses Succeeded: (" + JSON.stringify(result) + ")"); + aListener.onListedNetworkAddresses(result); + } + }); + } + + getHostname(aListener) { + send(":GetHostname", {}, (result, err) => { + if (err) { + log("GetHostname Failed: (" + err + ")"); + aListener.onGetHostnameFailed(); + } else { + log("GetHostname Succeeded: (" + JSON.stringify(result) + ")"); + aListener.onGotHostname(result); + } + }); + } +} diff --git a/netwerk/base/NetworkInfoServiceCocoa.cpp b/netwerk/base/NetworkInfoServiceCocoa.cpp new file mode 100644 index 000000000000..0846da67907c --- /dev/null +++ b/netwerk/base/NetworkInfoServiceCocoa.cpp @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 +#include +#include +#include +#include +#include +#include + +#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; + + nsresult rv = ListInterfaceAddresses(fd, ifreq->ifr_name, aAddrMap); + NS_WARN_IF(NS_FAILED(rv)); + + 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); + 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 diff --git a/netwerk/base/NetworkInfoServiceImpl.h b/netwerk/base/NetworkInfoServiceImpl.h new file mode 100644 index 000000000000..6f92c335f680 --- /dev/null +++ b/netwerk/base/NetworkInfoServiceImpl.h @@ -0,0 +1,18 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "nsString.h" +#include "nsDataHashtable.h" + +namespace mozilla { +namespace net { + +typedef nsDataHashtable AddrMapType; + +nsresult DoListAddresses(AddrMapType& aAddrMap); + +} // namespace net +} // namespace mozilla diff --git a/netwerk/base/NetworkInfoServiceLinux.cpp b/netwerk/base/NetworkInfoServiceLinux.cpp new file mode 100644 index 000000000000..3ea690ec1db8 --- /dev/null +++ b/netwerk/base/NetworkInfoServiceLinux.cpp @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 +#include +#include +#include +#include +#include +#include + +#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 = sizeof(struct ifreq); + + nsresult rv = ListInterfaceAddresses(fd, ifreq->ifr_name, aAddrMap); + NS_WARN_IF(NS_FAILED(rv)); + + 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); + 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 diff --git a/netwerk/base/NetworkInfoServiceWindows.cpp b/netwerk/base/NetworkInfoServiceWindows.cpp new file mode 100644 index 000000000000..2a9448e35196 --- /dev/null +++ b/netwerk/base/NetworkInfoServiceWindows.cpp @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 +#include +#include + +#include "mozilla/UniquePtr.h" + +#include "NetworkInfoServiceImpl.h" + +namespace mozilla { +namespace net { + +nsresult +DoListAddresses(AddrMapType& aAddrMap) +{ + UniquePtr ipAddrTable; + DWORD size = sizeof(MIB_IPADDRTABLE); + + ipAddrTable.reset((MIB_IPADDRTABLE*) malloc(size)); + if (!ipAddrTable) { + return NS_ERROR_FAILURE; + } + + DWORD retVal = GetIpAddrTable(ipAddrTable.get(), &size, 0); + if (retVal == ERROR_INSUFFICIENT_BUFFER) { + ipAddrTable.reset((MIB_IPADDRTABLE*) malloc(size)); + if (!ipAddrTable) { + return NS_ERROR_FAILURE; + } + retVal = GetIpAddrTable(ipAddrTable.get(), &size, 0); + } + if (retVal != NO_ERROR) { + return NS_ERROR_FAILURE; + } + + for (DWORD i = 0; i < ipAddrTable->dwNumEntries; i++) { + int index = ipAddrTable->table[i].dwIndex; + uint32_t addrVal = (uint32_t) ipAddrTable->table[i].dwAddr; + + nsCString indexString; + indexString.AppendInt(index, 10); + + nsCString addrString; + addrString.AppendPrintf("%d.%d.%d.%d", + (addrVal >> 0) & 0xff, (addrVal >> 8) & 0xff, + (addrVal >> 16) & 0xff, (addrVal >> 24) & 0xff); + + aAddrMap.Put(indexString, addrString); + } + + return NS_OK; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/base/moz.build b/netwerk/base/moz.build index 88a8a0bfb958..e2fcea3f292f 100644 --- a/netwerk/base/moz.build +++ b/netwerk/base/moz.build @@ -65,6 +65,7 @@ XPIDL_SOURCES += [ 'nsINestedURI.idl', 'nsINetAddr.idl', 'nsINetUtil.idl', + 'nsINetworkInfoService.idl', 'nsINetworkInterceptController.idl', 'nsINetworkLinkService.idl', 'nsINetworkPredictor.idl', @@ -276,6 +277,31 @@ else: 'nsURLHelperUnix.cpp', ] +# nsINetworkInfoService support. +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': + SOURCES += [ + 'NetworkInfoServiceWindows.cpp', + 'nsNetworkInfoService.cpp', + ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + SOURCES += [ + 'NetworkInfoServiceCocoa.cpp', + 'nsNetworkInfoService.cpp', + ] +elif CONFIG['OS_TARGET'] == 'Linux': + SOURCES += [ + 'NetworkInfoServiceLinux.cpp', + 'nsNetworkInfoService.cpp', + ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': + EXTRA_COMPONENTS += [ + 'nsNetworkInfoService.js', + 'nsNetworkInfoService.manifest' + ] + EXTRA_JS_MODULES += [ + 'NetworkInfoServiceAndroid.jsm', + ] + if CONFIG['MOZ_ENABLE_QTNETWORK']: SOURCES += [ ] diff --git a/netwerk/base/nsINetworkInfoService.idl b/netwerk/base/nsINetworkInfoService.idl new file mode 100644 index 000000000000..bd880450871b --- /dev/null +++ b/netwerk/base/nsINetworkInfoService.idl @@ -0,0 +1,57 @@ +/* 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 "nsISupports.idl" + +/** + * Listener for getting list of addresses. + */ +[scriptable, uuid(c4bdaac1-3ab1-4fdb-9a16-17cbed794603)] +interface nsIListNetworkAddressesListener : nsISupports +{ + /** + * Callback function that gets called by nsINetworkInfoService.listNetworkAddresses. + * Each address in the array is a string IP address in canonical form, + * e.g. 192.168.1.10, or an IPV6 address in string form. + */ + void onListedNetworkAddresses([array, size_is(aAddressArraySize)] in string aAddressArray, + in unsigned long aAddressArraySize); + void onListNetworkAddressesFailed(); +}; + +/** + * Listener for getting hostname. + */ +[scriptable, uuid(3ebdcb62-2df4-4042-8864-3fa81abd4693)] +interface nsIGetHostnameListener : nsISupports +{ + void onGotHostname(in AUTF8String aHostname); + void onGetHostnameFailed(); +}; + +/** + * Service information + */ +[scriptable, uuid(55fc8dae-4a58-4e0f-a49b-901cbabae809)] +interface nsINetworkInfoService : nsISupports +{ + /** + * Obtain a list of local machine network addresses. The listener object's + * onListedNetworkAddresses will be called with the obtained addresses. + * On failure, the listener object's onListNetworkAddressesFailed() will be called. + */ + void listNetworkAddresses(in nsIListNetworkAddressesListener aListener); + + /** + * Obtain the hostname of the local machine. The listener object's + * onGotHostname will be called with the obtained hostname. + * On failure, the listener object's onGetHostnameFailed() will be called. + */ + void getHostname(in nsIGetHostnameListener aListener); +}; + +%{ C++ +#define NETWORKINFOSERVICE_CONTRACT_ID \ + "@mozilla.org/network-info-service;1" +%} diff --git a/netwerk/base/nsNetworkInfoService.cpp b/netwerk/base/nsNetworkInfoService.cpp new file mode 100644 index 000000000000..5b188c7f14bb --- /dev/null +++ b/netwerk/base/nsNetworkInfoService.cpp @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#if defined(XP_MACOSX) || defined(XP_LINUX) +#include +#elif defined(XP_WIN) +#include +#endif + +#include "nsNetworkInfoService.h" +#include "mozilla/ScopeExit.h" + +#if defined(XP_MACOSX) || defined(XP_WIN) || defined(XP_LINUX) +#include "NetworkInfoServiceImpl.h" +#else +#error "Unsupported platform for nsNetworkInfoService! Check moz.build" +#endif + +namespace mozilla { +namespace net { + +NS_IMPL_ISUPPORTS(nsNetworkInfoService, + nsINetworkInfoService) + +nsNetworkInfoService::nsNetworkInfoService() +{ +} + +nsresult +nsNetworkInfoService::Init() +{ + return NS_OK; +} + +nsresult +nsNetworkInfoService::ListNetworkAddresses(nsIListNetworkAddressesListener* aListener) +{ + nsresult rv; + + AddrMapType addrMap; + rv = DoListAddresses(addrMap); + if (NS_WARN_IF(NS_FAILED(rv))) { + aListener->OnListNetworkAddressesFailed(); + return NS_OK; + } + + uint32_t addrCount = addrMap.Count(); + const char** addrStrings = (const char**) malloc(sizeof(*addrStrings) * addrCount); + if (!addrStrings) { + aListener->OnListNetworkAddressesFailed(); + return NS_OK; + } + auto autoFreeAddrStrings = MakeScopeExit([&] { + free(addrStrings); + }); + + uint32_t idx = 0; + for (auto iter = addrMap.Iter(); !iter.Done(); iter.Next()) { + addrStrings[idx++] = iter.Data().get(); + } + aListener->OnListedNetworkAddresses(addrStrings, addrCount); + return NS_OK; +} + +// TODO: Bug 1275373: https://bugzilla.mozilla.org/show_bug.cgi?id=1275373 +// Use platform-specific implementation of DoGetHostname on Cocoa and Windows. +static nsresult +DoGetHostname(nsACString& aHostname) +{ + char hostnameBuf[256]; + int result = gethostname(hostnameBuf, 256); + if (result == -1) { + return NS_ERROR_FAILURE; + } + + // Ensure that there is always a terminating NUL byte. + hostnameBuf[255] = '\0'; + + // Find the first '.', terminate string there. + char* dotLocation = strchr(hostnameBuf, '.'); + if (dotLocation) { + *dotLocation = '\0'; + } + + if (strlen(hostnameBuf) == 0) { + return NS_ERROR_FAILURE; + } + + aHostname.AssignASCII(hostnameBuf); + return NS_OK; +} + +nsresult +nsNetworkInfoService::GetHostname(nsIGetHostnameListener* aListener) +{ + nsresult rv; + nsCString hostnameStr; + rv = DoGetHostname(hostnameStr); + if (NS_FAILED(rv)) { + aListener->OnGetHostnameFailed(); + return NS_OK; + } + + aListener->OnGotHostname(hostnameStr); + + return NS_OK; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/base/nsNetworkInfoService.h b/netwerk/base/nsNetworkInfoService.h new file mode 100644 index 000000000000..be6f686bd2ba --- /dev/null +++ b/netwerk/base/nsNetworkInfoService.h @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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_net_nsNetworkInfoService_h +#define mozilla_net_nsNetworkInfoService_h + +#include "nsISupportsImpl.h" +#include "mozilla/ErrorResult.h" + +#include "nsINetworkInfoService.h" + +#define NETWORKINFOSERVICE_CID \ +{ 0x296d0900, 0xf8ef, 0x4df0, \ + { 0x9c, 0x35, 0xdb, 0x58, 0x62, 0xab, 0xc5, 0x8d } } + +namespace mozilla { +namespace net { + +class nsNetworkInfoService final + : public nsINetworkInfoService +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSINETWORKINFOSERVICE + + nsresult Init(); + + explicit nsNetworkInfoService(); + +private: + virtual ~nsNetworkInfoService() = default; +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_dom_nsNetworkInfoService_h diff --git a/netwerk/base/nsNetworkInfoService.js b/netwerk/base/nsNetworkInfoService.js new file mode 100644 index 000000000000..e39edf377f2b --- /dev/null +++ b/netwerk/base/nsNetworkInfoService.js @@ -0,0 +1,56 @@ +/* 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/. */ +"use strict"; + +const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; + +Cu.import('resource://gre/modules/Services.jsm'); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +Cu.import("resource://gre/modules/NetworkInfoServiceAndroid.jsm"); + +const NETWORKINFOSERVICE_CID = Components.ID("{0d8245af-d5d3-4100-a6b5-1cc026aa19f2}"); +const NETWORKINFOSERVICE_CONTRACT_ID = "@mozilla.org/network-info-service;1"; + +function log(aMsg) { + dump("-*- nsNetworkInfoService.js : " + aMsg + "\n"); +} + +function setQueryInterface(cls, ...aQIList) { + cls.prototype.QueryInterface = XPCOMUtils.generateQI(aQIList); +} + +class nsNetworkInfoService { + constructor() { + this.impl = new NetworkInfoServiceAndroid(); + log("nsNetworkInfoService"); + } + + listNetworkAddresses(aListener) { + this.impl.listNetworkAddresses({ + onListNetworkAddressesFailed(err) { + aListener.onListNetworkAddressesFailed(); + }, + onListedNetworkAddresses(addresses) { + aListener.onListedNetworkAddresses(addresses, addresses.length); + } + }); + } + + getHostname(aListener) { + this.impl.getHostname({ + onGetHostnameFailed(err) { + aListener.onGetHostnameFailed(); + }, + onGotHostname(hostname) { + aListener.onGotHostname(hostname); + } + }); + } +} +setQueryInterface(nsNetworkInfoService, Ci.nsISupportsWeakReference, + Ci.nsINetworkInfoService); +nsNetworkInfoService.prototype.classID = NETWORKINFOSERVICE_CID; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsNetworkInfoService]); diff --git a/netwerk/base/nsNetworkInfoService.manifest b/netwerk/base/nsNetworkInfoService.manifest new file mode 100644 index 000000000000..5c262ef2be0c --- /dev/null +++ b/netwerk/base/nsNetworkInfoService.manifest @@ -0,0 +1,4 @@ +# nsNetworkInfoService.js + +component {0d8245af-d5d3-4100-a6b5-1cc026aa19f2} nsNetworkInfoService.js +contract @mozilla.org/network-info-service;1 {0d8245af-d5d3-4100-a6b5-1cc026aa19f2} diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index a52d7b4bdbe1..acd6a74b8c97 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -47,6 +47,11 @@ #define BUILD_BINHEX_DECODER 1 #endif +#if defined(XP_MACOSX) || defined(XP_WIN) || \ + (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID)) +#define BUILD_NETWORK_INFO_SERVICE 1 +#endif + typedef nsCategoryCache ContentSnifferCache; ContentSnifferCache* gNetSniffers = nullptr; ContentSnifferCache* gDataSniffers = nullptr; @@ -442,6 +447,15 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsTXTToHTMLConv, Init) } // namespace net } // namespace mozilla +/////////////////////////////////////////////////////////////////////////////// + +#ifdef BUILD_NETWORK_INFO_SERVICE +#include "nsNetworkInfoService.h" +typedef mozilla::net::nsNetworkInfoService nsNetworkInfoService; +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNetworkInfoService, Init) +#endif // BUILD_NETWORK_INFO_SERVICE + + #include "nsIndexedToHTML.h" #ifdef BUILD_BINHEX_DECODER #include "nsBinHexDecoder.h" @@ -857,6 +871,9 @@ NS_DEFINE_NAMED_CID(NS_NSILOADCONTEXTINFOFACTORY_CID); NS_DEFINE_NAMED_CID(NS_NETWORKPREDICTOR_CID); NS_DEFINE_NAMED_CID(NS_CAPTIVEPORTAL_CID); NS_DEFINE_NAMED_CID(NS_REQUESTCONTEXTSERVICE_CID); +#ifdef BUILD_NETWORK_INFO_SERVICE +NS_DEFINE_NAMED_CID(NETWORKINFOSERVICE_CID); +#endif // BUILD_NETWORK_INFO_SERVICE static const mozilla::Module::CIDEntry kNeckoCIDs[] = { { &kNS_IOSERVICE_CID, false, nullptr, nsIOServiceConstructor }, @@ -1009,6 +1026,9 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = { { &kNS_NETWORKPREDICTOR_CID, false, nullptr, mozilla::net::Predictor::Create }, { &kNS_CAPTIVEPORTAL_CID, false, nullptr, mozilla::net::CaptivePortalServiceConstructor }, { &kNS_REQUESTCONTEXTSERVICE_CID, false, nullptr, RequestContextServiceConstructor }, +#ifdef BUILD_NETWORK_INFO_SERVICE + { &kNETWORKINFOSERVICE_CID, false, nullptr, nsNetworkInfoServiceConstructor }, +#endif { nullptr } }; @@ -1167,6 +1187,9 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = { { NS_NETWORKPREDICTOR_CONTRACTID, &kNS_NETWORKPREDICTOR_CID }, { NS_CAPTIVEPORTAL_CONTRACTID, &kNS_CAPTIVEPORTAL_CID }, { NS_REQUESTCONTEXTSERVICE_CONTRACTID, &kNS_REQUESTCONTEXTSERVICE_CID }, +#ifdef BUILD_NETWORK_INFO_SERVICE + { NETWORKINFOSERVICE_CONTRACT_ID, &kNETWORKINFOSERVICE_CID }, +#endif { nullptr } };