nsDNSServiceDiscovery.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
  6. Cu.import('resource://gre/modules/Services.jsm');
  7. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  8. Cu.import("resource://gre/modules/MulticastDNS.jsm");
  9. const DNSSERVICEDISCOVERY_CID = Components.ID("{f9346d98-f27a-4e89-b744-493843416480}");
  10. const DNSSERVICEDISCOVERY_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-sd;1";
  11. const DNSSERVICEINFO_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-info;1";
  12. function log(aMsg) {
  13. dump("-*- nsDNSServiceDiscovery.js : " + aMsg + "\n");
  14. }
  15. function generateUuid() {
  16. var uuidGenerator = Components.classes["@mozilla.org/uuid-generator;1"].
  17. getService(Ci.nsIUUIDGenerator);
  18. return uuidGenerator.generateUUID().toString();
  19. }
  20. // Helper class to transform return objects to correct type.
  21. function ListenerWrapper(aListener, aMdns) {
  22. this.listener = aListener;
  23. this.mdns = aMdns;
  24. this.discoveryStarting = false;
  25. this.stopDiscovery = false;
  26. this.registrationStarting = false;
  27. this.stopRegistration = false;
  28. this.uuid = generateUuid();
  29. }
  30. ListenerWrapper.prototype = {
  31. // Helper function for transforming an Object into nsIDNSServiceInfo.
  32. makeServiceInfo: function (aServiceInfo) {
  33. let serviceInfo = Cc[DNSSERVICEINFO_CONTRACT_ID].createInstance(Ci.nsIDNSServiceInfo);
  34. for (let name of ['host', 'address', 'port', 'serviceName', 'serviceType']) {
  35. try {
  36. serviceInfo[name] = aServiceInfo[name];
  37. } catch (e) {
  38. // ignore exceptions
  39. }
  40. }
  41. let attributes;
  42. try {
  43. attributes = _toPropertyBag2(aServiceInfo.attributes);
  44. } catch (err) {
  45. // Ignore unset attributes in object.
  46. log("Caught unset attributes error: " + err + " - " + err.stack);
  47. attributes = Cc['@mozilla.org/hash-property-bag;1']
  48. .createInstance(Ci.nsIWritablePropertyBag2);
  49. }
  50. serviceInfo.attributes = attributes;
  51. return serviceInfo;
  52. },
  53. /* transparent types */
  54. onDiscoveryStarted: function(aServiceType) {
  55. this.discoveryStarting = false;
  56. this.listener.onDiscoveryStarted(aServiceType);
  57. if (this.stopDiscovery) {
  58. this.mdns.stopDiscovery(aServiceType, this);
  59. }
  60. },
  61. onDiscoveryStopped: function(aServiceType) {
  62. this.listener.onDiscoveryStopped(aServiceType);
  63. },
  64. onStartDiscoveryFailed: function(aServiceType, aErrorCode) {
  65. log('onStartDiscoveryFailed: ' + aServiceType + ' (' + aErrorCode + ')');
  66. this.discoveryStarting = false;
  67. this.stopDiscovery = true;
  68. this.listener.onStartDiscoveryFailed(aServiceType, aErrorCode);
  69. },
  70. onStopDiscoveryFailed: function(aServiceType, aErrorCode) {
  71. log('onStopDiscoveryFailed: ' + aServiceType + ' (' + aErrorCode + ')');
  72. this.listener.onStopDiscoveryFailed(aServiceType, aErrorCode);
  73. },
  74. /* transform types */
  75. onServiceFound: function(aServiceInfo) {
  76. this.listener.onServiceFound(this.makeServiceInfo(aServiceInfo));
  77. },
  78. onServiceLost: function(aServiceInfo) {
  79. this.listener.onServiceLost(this.makeServiceInfo(aServiceInfo));
  80. },
  81. onServiceRegistered: function(aServiceInfo) {
  82. this.registrationStarting = false;
  83. this.listener.onServiceRegistered(this.makeServiceInfo(aServiceInfo));
  84. if (this.stopRegistration) {
  85. this.mdns.unregisterService(aServiceInfo, this);
  86. }
  87. },
  88. onServiceUnregistered: function(aServiceInfo) {
  89. this.listener.onServiceUnregistered(this.makeServiceInfo(aServiceInfo));
  90. },
  91. onServiceResolved: function(aServiceInfo) {
  92. this.listener.onServiceResolved(this.makeServiceInfo(aServiceInfo));
  93. },
  94. onRegistrationFailed: function(aServiceInfo, aErrorCode) {
  95. log('onRegistrationFailed: (' + aErrorCode + ')');
  96. this.registrationStarting = false;
  97. this.stopRegistration = true;
  98. this.listener.onRegistrationFailed(this.makeServiceInfo(aServiceInfo), aErrorCode);
  99. },
  100. onUnregistrationFailed: function(aServiceInfo, aErrorCode) {
  101. log('onUnregistrationFailed: (' + aErrorCode + ')');
  102. this.listener.onUnregistrationFailed(this.makeServiceInfo(aServiceInfo), aErrorCode);
  103. },
  104. onResolveFailed: function(aServiceInfo, aErrorCode) {
  105. log('onResolveFailed: (' + aErrorCode + ')');
  106. this.listener.onResolveFailed(this.makeServiceInfo(aServiceInfo), aErrorCode);
  107. }
  108. };
  109. function nsDNSServiceDiscovery() {
  110. log("nsDNSServiceDiscovery");
  111. this.mdns = new MulticastDNS();
  112. }
  113. nsDNSServiceDiscovery.prototype = {
  114. classID: DNSSERVICEDISCOVERY_CID,
  115. QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIDNSServiceDiscovery]),
  116. startDiscovery: function(aServiceType, aListener) {
  117. log("startDiscovery");
  118. let listener = new ListenerWrapper(aListener, this.mdns);
  119. listener.discoveryStarting = true;
  120. this.mdns.startDiscovery(aServiceType, listener);
  121. return {
  122. QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
  123. cancel: (function() {
  124. if (this.discoveryStarting || this.stopDiscovery) {
  125. this.stopDiscovery = true;
  126. return;
  127. }
  128. this.mdns.stopDiscovery(aServiceType, listener);
  129. }).bind(listener)
  130. };
  131. },
  132. registerService: function(aServiceInfo, aListener) {
  133. log("registerService");
  134. let listener = new ListenerWrapper(aListener, this.mdns);
  135. listener.registrationStarting = true;
  136. this.mdns.registerService(aServiceInfo, listener);
  137. return {
  138. QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
  139. cancel: (function() {
  140. if (this.registrationStarting || this.stopRegistration) {
  141. this.stopRegistration = true;
  142. return;
  143. }
  144. this.mdns.unregisterService(aServiceInfo, listener);
  145. }).bind(listener)
  146. };
  147. },
  148. resolveService: function(aServiceInfo, aListener) {
  149. log("resolveService");
  150. this.mdns.resolveService(aServiceInfo, new ListenerWrapper(aListener));
  151. }
  152. };
  153. this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsDNSServiceDiscovery]);
  154. function _toPropertyBag2(obj)
  155. {
  156. if (obj.QueryInterface) {
  157. return obj.QueryInterface(Ci.nsIPropertyBag2);
  158. }
  159. let result = Cc['@mozilla.org/hash-property-bag;1']
  160. .createInstance(Ci.nsIWritablePropertyBag2);
  161. for (let name in obj) {
  162. result.setPropertyAsAString(name, obj[name]);
  163. }
  164. return result;
  165. }