diff options
Diffstat (limited to 'netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm')
-rw-r--r-- | netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm b/netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm new file mode 100644 index 000000000..771f9a794 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm @@ -0,0 +1,244 @@ +// -*- 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 = ["MulticastDNS"]; + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import("resource://gre/modules/Messaging.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +var log = Cu.import("resource://gre/modules/AndroidLog.jsm", {}).AndroidLog.d.bind(null, "MulticastDNS"); + +const FAILURE_INTERNAL_ERROR = -65537; + +// Helper function for sending commands to Java. +function send(type, data, callback) { + let msg = { + type: 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)); +} + +// Receives service found/lost event from NsdManager +function ServiceManager() { +} + +ServiceManager.prototype = { + listeners: {}, + numListeners: 0, + + registerEvent: function() { + log("registerEvent"); + Messaging.addListener(this.onServiceFound.bind(this), "NsdManager:ServiceFound"); + Messaging.addListener(this.onServiceLost.bind(this), "NsdManager:ServiceLost"); + }, + + unregisterEvent: function() { + log("unregisterEvent"); + Messaging.removeListener("NsdManager:ServiceFound"); + Messaging.removeListener("NsdManager:ServiceLost"); + }, + + addListener: function(aServiceType, aListener) { + log("addListener: " + aServiceType + ", " + aListener); + + if (!this.listeners[aServiceType]) { + this.listeners[aServiceType] = []; + } + if (this.listeners[aServiceType].includes(aListener)) { + log("listener already exists"); + return; + } + + this.listeners[aServiceType].push(aListener); + ++this.numListeners; + + if (this.numListeners === 1) { + this.registerEvent(); + } + + log("listener added: " + this); + }, + + removeListener: function(aServiceType, aListener) { + log("removeListener: " + aServiceType + ", " + aListener); + + if (!this.listeners[aServiceType]) { + log("listener doesn't exist"); + return; + } + let index = this.listeners[aServiceType].indexOf(aListener); + if (index < 0) { + log("listener doesn't exist"); + return; + } + + this.listeners[aServiceType].splice(index, 1); + --this.numListeners; + + if (this.numListeners === 0) { + this.unregisterEvent(); + } + + log("listener removed" + this); + }, + + onServiceFound: function(aServiceInfo) { + let listeners = this.listeners[aServiceInfo.serviceType]; + if (listeners) { + for (let listener of listeners) { + listener.onServiceFound(aServiceInfo); + } + } else { + log("no listener"); + } + return {}; + }, + + onServiceLost: function(aServiceInfo) { + let listeners = this.listeners[aServiceInfo.serviceType]; + if (listeners) { + for (let listener of listeners) { + listener.onServiceLost(aServiceInfo); + } + } else { + log("no listener"); + } + return {}; + } +}; + +// make an object from nsIPropertyBag2 +function parsePropertyBag2(bag) { + if (!bag || !(bag instanceof Ci.nsIPropertyBag2)) { + throw new TypeError("Not a property bag"); + } + + let attributes = []; + let enumerator = bag.enumerator; + while (enumerator.hasMoreElements()) { + let name = enumerator.getNext().QueryInterface(Ci.nsIProperty).name; + let value = bag.getPropertyAsACString(name); + attributes.push({ + "name": name, + "value": value + }); + } + + return attributes; +} + +function MulticastDNS() { + this.serviceManager = new ServiceManager(); +} + +MulticastDNS.prototype = { + startDiscovery: function(aServiceType, aListener) { + this.serviceManager.addListener(aServiceType, aListener); + + let serviceInfo = { + serviceType: aServiceType, + uniqueId: aListener.uuid + }; + + send("NsdManager:DiscoverServices", serviceInfo, (result, err) => { + if (err) { + log("onStartDiscoveryFailed: " + aServiceType + " (" + err + ")"); + this.serviceManager.removeListener(aServiceType, aListener); + aListener.onStartDiscoveryFailed(aServiceType, err); + } else { + aListener.onDiscoveryStarted(result); + } + }); + }, + + stopDiscovery: function(aServiceType, aListener) { + this.serviceManager.removeListener(aServiceType, aListener); + + let serviceInfo = { + uniqueId: aListener.uuid + }; + + send("NsdManager:StopServiceDiscovery", serviceInfo, (result, err) => { + if (err) { + log("onStopDiscoveryFailed: " + aServiceType + " (" + err + ")"); + aListener.onStopDiscoveryFailed(aServiceType, err); + } else { + aListener.onDiscoveryStopped(aServiceType); + } + }); + }, + + registerService: function(aServiceInfo, aListener) { + let serviceInfo = { + port: aServiceInfo.port, + serviceType: aServiceInfo.serviceType, + uniqueId: aListener.uuid + }; + + try { + serviceInfo.host = aServiceInfo.host; + } catch(e) { + // host unspecified + } + try { + serviceInfo.serviceName = aServiceInfo.serviceName; + } catch(e) { + // serviceName unspecified + } + try { + serviceInfo.attributes = parsePropertyBag2(aServiceInfo.attributes); + } catch(e) { + // attributes unspecified + } + + send("NsdManager:RegisterService", serviceInfo, (result, err) => { + if (err) { + log("onRegistrationFailed: (" + err + ")"); + aListener.onRegistrationFailed(aServiceInfo, err); + } else { + aListener.onServiceRegistered(result); + } + }); + }, + + unregisterService: function(aServiceInfo, aListener) { + let serviceInfo = { + uniqueId: aListener.uuid + }; + + send("NsdManager:UnregisterService", serviceInfo, (result, err) => { + if (err) { + log("onUnregistrationFailed: (" + err + ")"); + aListener.onUnregistrationFailed(aServiceInfo, err); + } else { + aListener.onServiceUnregistered(aServiceInfo); + } + }); + }, + + resolveService: function(aServiceInfo, aListener) { + send("NsdManager:ResolveService", aServiceInfo, (result, err) => { + if (err) { + log("onResolveFailed: (" + err + ")"); + aListener.onResolveFailed(aServiceInfo, err); + } else { + aListener.onServiceResolved(result); + } + }); + } +}; |