diff options
Diffstat (limited to 'netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm')
-rw-r--r-- | netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm b/netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm new file mode 100644 index 0000000000..d94e90efaa --- /dev/null +++ b/netwerk/dns/mdns/libmdns/MulticastDNSAndroid.jsm @@ -0,0 +1,262 @@ +// -*- 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"; + +var EXPORTED_SYMBOLS = ["MulticastDNS"]; + +const { EventDispatcher } = ChromeUtils.import( + "resource://gre/modules/Messaging.jsm" +); + +const DEBUG = false; + +var log = function(s) {}; +if (DEBUG) { + log = ChromeUtils.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, + }; + + for (let i in data) { + try { + msg[i] = data[i]; + } catch (e) {} + } + + EventDispatcher.instance.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, + + onEvent(event, data, callback) { + if (event === "NsdManager:ServiceFound") { + this.onServiceFound(); + } else if (event === "NsdManager:ServiceLost") { + this.onServiceLost(); + } + }, + + registerEvent() { + log("registerEvent"); + EventDispatcher.instance.registerListener(this, [ + "NsdManager:ServiceFound", + "NsdManager:ServiceLost", + ]); + }, + + unregisterEvent() { + log("unregisterEvent"); + EventDispatcher.instance.unregisterListener(this, [ + "NsdManager:ServiceFound", + "NsdManager:ServiceLost", + ]); + }, + + addListener(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(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(aServiceInfo) { + let listeners = this.listeners[aServiceInfo.serviceType]; + if (listeners) { + for (let listener of listeners) { + listener.onServiceFound(aServiceInfo); + } + } else { + log("no listener"); + } + return {}; + }, + + onServiceLost(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 = []; + for (let { name } of bag.enumerator) { + let value = bag.getPropertyAsACString(name); + attributes.push({ + name, + value, + }); + } + + return attributes; +} + +function MulticastDNS() { + this.serviceManager = new ServiceManager(); +} + +MulticastDNS.prototype = { + startDiscovery(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(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(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(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(aServiceInfo, aListener) { + send("NsdManager:ResolveService", aServiceInfo, (result, err) => { + if (err) { + log("onResolveFailed: (" + err + ")"); + aListener.onResolveFailed(aServiceInfo, err); + } else { + aListener.onServiceResolved(result); + } + }); + }, +}; |