diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /mobile/android/base/java/org/mozilla/gecko/mdns | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'mobile/android/base/java/org/mozilla/gecko/mdns')
-rw-r--r-- | mobile/android/base/java/org/mozilla/gecko/mdns/MulticastDNSManager.java | 535 |
1 files changed, 535 insertions, 0 deletions
diff --git a/mobile/android/base/java/org/mozilla/gecko/mdns/MulticastDNSManager.java b/mobile/android/base/java/org/mozilla/gecko/mdns/MulticastDNSManager.java new file mode 100644 index 000000000..6f23790b9 --- /dev/null +++ b/mobile/android/base/java/org/mozilla/gecko/mdns/MulticastDNSManager.java @@ -0,0 +1,535 @@ +/* -*- 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.mdns; + +import org.mozilla.gecko.AppConstants.Versions; +import org.mozilla.gecko.EventDispatcher; +import org.mozilla.gecko.GeckoAppShell; +import org.mozilla.gecko.util.EventCallback; +import org.mozilla.gecko.util.GeckoRequest; +import org.mozilla.gecko.util.NativeEventListener; +import org.mozilla.gecko.util.NativeJSObject; +import org.mozilla.gecko.util.ThreadUtils; + +import org.json.JSONException; +import org.json.JSONObject; + +import android.annotation.TargetApi; +import android.content.Context; +import android.net.nsd.NsdManager; +import android.net.nsd.NsdServiceInfo; +import android.support.annotation.UiThread; +import android.util.Log; + +import java.net.InetAddress; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * This class is the bridge between XPCOM mDNS module and NsdManager. + * + * @See nsIDNSServiceDiscovery.idl + */ +public abstract class MulticastDNSManager { + protected static final String LOGTAG = "GeckoMDNSManager"; + private static MulticastDNSManager instance = null; + + public static MulticastDNSManager getInstance(final Context context) { + if (instance == null) { + instance = new DummyMulticastDNSManager(); + } + return instance; + } + + public abstract void init(); + public abstract void tearDown(); +} + +/** + * Mix-in class for MulticastDNSManagers to call EventDispatcher. + */ +class MulticastDNSEventManager { + private NativeEventListener mListener = null; + private boolean mEventsRegistered = false; + + MulticastDNSEventManager(NativeEventListener listener) { + mListener = listener; + } + + @UiThread + public void init() { + ThreadUtils.assertOnUiThread(); + + if (mEventsRegistered || mListener == null) { + return; + } + + registerEvents(); + mEventsRegistered = true; + } + + @UiThread + public void tearDown() { + ThreadUtils.assertOnUiThread(); + + if (!mEventsRegistered || mListener == null) { + return; + } + + unregisterEvents(); + mEventsRegistered = false; + } + + private void registerEvents() { + EventDispatcher.getInstance().registerGeckoThreadListener(mListener, + "NsdManager:DiscoverServices", + "NsdManager:StopServiceDiscovery", + "NsdManager:RegisterService", + "NsdManager:UnregisterService", + "NsdManager:ResolveService"); + } + + private void unregisterEvents() { + EventDispatcher.getInstance().unregisterGeckoThreadListener(mListener, + "NsdManager:DiscoverServices", + "NsdManager:StopServiceDiscovery", + "NsdManager:RegisterService", + "NsdManager:UnregisterService", + "NsdManager:ResolveService"); + } +} + +class NsdMulticastDNSManager extends MulticastDNSManager implements NativeEventListener { + private final NsdManager nsdManager; + private final MulticastDNSEventManager mEventManager; + private Map<String, DiscoveryListener> mDiscoveryListeners = null; + private Map<String, RegistrationListener> mRegistrationListeners = null; + + @TargetApi(16) + public NsdMulticastDNSManager(final Context context) { + nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE); + mEventManager = new MulticastDNSEventManager(this); + mDiscoveryListeners = new ConcurrentHashMap<String, DiscoveryListener>(); + mRegistrationListeners = new ConcurrentHashMap<String, RegistrationListener>(); + } + + @Override + public void init() { + mEventManager.init(); + } + + @Override + public void tearDown() { + mDiscoveryListeners.clear(); + mRegistrationListeners.clear(); + + mEventManager.tearDown(); + } + + @Override + public void handleMessage(final String event, final NativeJSObject message, final EventCallback callback) { + Log.v(LOGTAG, "handleMessage: " + event); + + switch (event) { + case "NsdManager:DiscoverServices": { + DiscoveryListener listener = new DiscoveryListener(nsdManager); + listener.discoverServices(message.getString("serviceType"), callback); + mDiscoveryListeners.put(message.getString("uniqueId"), listener); + break; + } + case "NsdManager:StopServiceDiscovery": { + String uuid = message.getString("uniqueId"); + DiscoveryListener listener = mDiscoveryListeners.remove(uuid); + if (listener == null) { + Log.e(LOGTAG, "DiscoveryListener " + uuid + " was not found."); + return; + } + listener.stopServiceDiscovery(callback); + break; + } + case "NsdManager:RegisterService": { + RegistrationListener listener = new RegistrationListener(nsdManager); + listener.registerService(message.getInt("port"), + message.optString("serviceName", android.os.Build.MODEL), + message.getString("serviceType"), + parseAttributes(message.optObjectArray("attributes", null)), + callback); + mRegistrationListeners.put(message.getString("uniqueId"), listener); + break; + } + case "NsdManager:UnregisterService": { + String uuid = message.getString("uniqueId"); + RegistrationListener listener = mRegistrationListeners.remove(uuid); + if (listener == null) { + Log.e(LOGTAG, "RegistrationListener " + uuid + " was not found."); + return; + } + listener.unregisterService(callback); + break; + } + case "NsdManager:ResolveService": { + (new ResolveListener(nsdManager)).resolveService(message.getString("serviceName"), + message.getString("serviceType"), + callback); + break; + } + } + } + + private Map<String, String> parseAttributes(final NativeJSObject[] jsobjs) { + if (jsobjs == null || jsobjs.length == 0 || !Versions.feature21Plus) { + return null; + } + + Map<String, String> attributes = new HashMap<String, String>(jsobjs.length); + for (NativeJSObject obj : jsobjs) { + attributes.put(obj.getString("name"), obj.getString("value")); + } + + return attributes; + } + + @TargetApi(16) + public static JSONObject toJSON(final NsdServiceInfo serviceInfo) throws JSONException { + JSONObject obj = new JSONObject(); + + InetAddress host = serviceInfo.getHost(); + if (host != null) { + obj.put("host", host.getCanonicalHostName()); + obj.put("address", host.getHostAddress()); + } + + int port = serviceInfo.getPort(); + if (port != 0) { + obj.put("port", port); + } + + String serviceName = serviceInfo.getServiceName(); + if (serviceName != null) { + obj.put("serviceName", serviceName); + } + + String serviceType = serviceInfo.getServiceType(); + if (serviceType != null) { + obj.put("serviceType", serviceType); + } + + return obj; + } +} + +class DummyMulticastDNSManager extends MulticastDNSManager implements NativeEventListener { + static final int FAILURE_UNSUPPORTED = -65544; + private final MulticastDNSEventManager mEventManager; + + public DummyMulticastDNSManager() { + mEventManager = new MulticastDNSEventManager(this); + } + + @Override + public void init() { + mEventManager.init(); + } + + @Override + public void tearDown() { + mEventManager.tearDown(); + } + + @Override + public void handleMessage(final String event, final NativeJSObject message, final EventCallback callback) { + Log.v(LOGTAG, "handleMessage: " + event); + callback.sendError(FAILURE_UNSUPPORTED); + } +} + +@TargetApi(16) +class DiscoveryListener implements NsdManager.DiscoveryListener { + private static final String LOGTAG = "GeckoMDNSManager"; + private final NsdManager nsdManager; + + // Callbacks are called from different thread, and every callback can be called only once. + private EventCallback mStartCallback = null; + private EventCallback mStopCallback = null; + + DiscoveryListener(final NsdManager nsdManager) { + this.nsdManager = nsdManager; + } + + public void discoverServices(final String serviceType, final EventCallback callback) { + synchronized (this) { + mStartCallback = callback; + } + nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, this); + } + + public void stopServiceDiscovery(final EventCallback callback) { + synchronized (this) { + mStopCallback = callback; + } + nsdManager.stopServiceDiscovery(this); + } + + @Override + public synchronized void onDiscoveryStarted(final String serviceType) { + Log.d(LOGTAG, "onDiscoveryStarted: " + serviceType); + + EventCallback callback; + synchronized (this) { + callback = mStartCallback; + } + + if (callback == null) { + return; + } + + callback.sendSuccess(serviceType); + } + + @Override + public synchronized void onStartDiscoveryFailed(final String serviceType, final int errorCode) { + Log.e(LOGTAG, "onStartDiscoveryFailed: " + serviceType + "(" + errorCode + ")"); + + EventCallback callback; + synchronized (this) { + callback = mStartCallback; + } + + callback.sendError(errorCode); + } + + @Override + public synchronized void onDiscoveryStopped(final String serviceType) { + Log.d(LOGTAG, "onDiscoveryStopped: " + serviceType); + + EventCallback callback; + synchronized (this) { + callback = mStopCallback; + } + + if (callback == null) { + return; + } + + callback.sendSuccess(serviceType); + } + + @Override + public synchronized void onStopDiscoveryFailed(final String serviceType, final int errorCode) { + Log.e(LOGTAG, "onStopDiscoveryFailed: " + serviceType + "(" + errorCode + ")"); + + EventCallback callback; + synchronized (this) { + callback = mStopCallback; + } + + if (callback == null) { + return; + } + + callback.sendError(errorCode); + } + + @Override + public void onServiceFound(final NsdServiceInfo serviceInfo) { + Log.d(LOGTAG, "onServiceFound: " + serviceInfo.getServiceName()); + JSONObject json; + try { + json = NsdMulticastDNSManager.toJSON(serviceInfo); + } catch (JSONException e) { + throw new RuntimeException(e); + } + GeckoAppShell.sendRequestToGecko(new GeckoRequest("NsdManager:ServiceFound", json) { + @Override + public void onResponse(NativeJSObject nativeJSObject) { + // don't care return value. + } + }); + } + + @Override + public void onServiceLost(final NsdServiceInfo serviceInfo) { + Log.d(LOGTAG, "onServiceLost: " + serviceInfo.getServiceName()); + JSONObject json; + try { + json = NsdMulticastDNSManager.toJSON(serviceInfo); + } catch (JSONException e) { + throw new RuntimeException(e); + } + GeckoAppShell.sendRequestToGecko(new GeckoRequest("NsdManager:ServiceLost", json) { + @Override + public void onResponse(NativeJSObject nativeJSObject) { + // don't care return value. + } + }); + } +} + +@TargetApi(16) +class RegistrationListener implements NsdManager.RegistrationListener { + private static final String LOGTAG = "GeckoMDNSManager"; + private final NsdManager nsdManager; + + // Callbacks are called from different thread, and every callback can be called only once. + private EventCallback mStartCallback = null; + private EventCallback mStopCallback = null; + + RegistrationListener(final NsdManager nsdManager) { + this.nsdManager = nsdManager; + } + + public void registerService(final int port, final String serviceName, final String serviceType, final Map<String, String> attributes, final EventCallback callback) { + Log.d(LOGTAG, "registerService: " + serviceName + "." + serviceType + ":" + port); + + NsdServiceInfo serviceInfo = new NsdServiceInfo(); + serviceInfo.setPort(port); + serviceInfo.setServiceName(serviceName); + serviceInfo.setServiceType(serviceType); + setAttributes(serviceInfo, attributes); + + synchronized (this) { + mStartCallback = callback; + } + nsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, this); + } + + @TargetApi(21) + private void setAttributes(final NsdServiceInfo serviceInfo, final Map<String, String> attributes) { + if (attributes == null || !Versions.feature21Plus) { + return; + } + + for (Map.Entry<String, String> entry : attributes.entrySet()) { + serviceInfo.setAttribute(entry.getKey(), entry.getValue()); + } + } + + public void unregisterService(final EventCallback callback) { + Log.d(LOGTAG, "unregisterService"); + synchronized (this) { + mStopCallback = callback; + } + + nsdManager.unregisterService(this); + } + + @Override + public synchronized void onServiceRegistered(final NsdServiceInfo serviceInfo) { + Log.d(LOGTAG, "onServiceRegistered: " + serviceInfo.getServiceName()); + + EventCallback callback; + synchronized (this) { + callback = mStartCallback; + } + + if (callback == null) { + return; + } + + try { + callback.sendSuccess(NsdMulticastDNSManager.toJSON(serviceInfo)); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + + @Override + public synchronized void onRegistrationFailed(final NsdServiceInfo serviceInfo, final int errorCode) { + Log.e(LOGTAG, "onRegistrationFailed: " + serviceInfo.getServiceName() + "(" + errorCode + ")"); + + EventCallback callback; + synchronized (this) { + callback = mStartCallback; + } + + callback.sendError(errorCode); + } + + @Override + public synchronized void onServiceUnregistered(final NsdServiceInfo serviceInfo) { + Log.d(LOGTAG, "onServiceUnregistered: " + serviceInfo.getServiceName()); + + EventCallback callback; + synchronized (this) { + callback = mStopCallback; + } + + if (callback == null) { + return; + } + + try { + callback.sendSuccess(NsdMulticastDNSManager.toJSON(serviceInfo)); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + + @Override + public synchronized void onUnregistrationFailed(final NsdServiceInfo serviceInfo, final int errorCode) { + Log.e(LOGTAG, "onUnregistrationFailed: " + serviceInfo.getServiceName() + "(" + errorCode + ")"); + + EventCallback callback; + synchronized (this) { + callback = mStopCallback; + } + + if (callback == null) { + return; + } + + callback.sendError(errorCode); + } +} + +@TargetApi(16) +class ResolveListener implements NsdManager.ResolveListener { + private static final String LOGTAG = "GeckoMDNSManager"; + private final NsdManager nsdManager; + + // Callback is called from different thread, and the callback can be called only once. + private EventCallback mCallback = null; + + public ResolveListener(final NsdManager nsdManager) { + this.nsdManager = nsdManager; + } + + public void resolveService(final String serviceName, final String serviceType, final EventCallback callback) { + NsdServiceInfo serviceInfo = new NsdServiceInfo(); + serviceInfo.setServiceName(serviceName); + serviceInfo.setServiceType(serviceType); + + mCallback = callback; + nsdManager.resolveService(serviceInfo, this); + } + + + @Override + public synchronized void onResolveFailed(final NsdServiceInfo serviceInfo, final int errorCode) { + Log.e(LOGTAG, "onResolveFailed: " + serviceInfo.getServiceName() + "(" + errorCode + ")"); + + if (mCallback == null) { + return; + } + mCallback.sendError(errorCode); + } + + @Override + public synchronized void onServiceResolved(final NsdServiceInfo serviceInfo) { + Log.d(LOGTAG, "onServiceResolved: " + serviceInfo.getServiceName()); + + if (mCallback == null) { + return; + } + + try { + mCallback.sendSuccess(NsdMulticastDNSManager.toJSON(serviceInfo)); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } +} |