Bug 1286636 - Use dedicated custom-port query socket to do mDNS queries. Respond to queries using per-interface sockets. r=justindarc

This commit is contained in:
Kannan Vijayan 2016-07-18 12:41:31 -04:00
Родитель 7021782f32
Коммит 2c6b8dc9ef
1 изменённых файлов: 97 добавлений и 49 удалений

Просмотреть файл

@ -100,6 +100,7 @@ class PublishedService {
class MulticastDNS {
constructor() {
this._listeners = new Map();
this._querySocket = undefined;
this._broadcastSocket = undefined;
this._broadcastTimer = undefined;
this._sockets = new Map();
@ -220,6 +221,22 @@ class MulticastDNS {
aListener.onServiceUnregistered(aServiceInfo);
}
_respondToQuery(serviceKey, message) {
let address = message.fromAddr.address;
let port = message.fromAddr.port;
DEBUG && debug('_respondToQuery(): key=' + serviceKey + ', fromAddr='
+ address + ":" + port);
let publishedService = this._services.get(serviceKey);
if (!publishedService) {
debug("_respondToQuery Could not find service (key=" + serviceKey + ")");
return;
}
DEBUG && debug('_respondToQuery(): key=' + serviceKey + ': SENDING RESPONSE');
this._advertiseServiceHelper(publishedService, {address,port});
}
_advertiseService(serviceKey, firstAdv) {
DEBUG && debug('_advertiseService(): key=' + serviceKey);
let publishedService = this._services.get(serviceKey);
@ -230,31 +247,7 @@ class MulticastDNS {
publishedService.advertiseTimer = undefined;
this._getSockets().then((sockets) => {
if (publishedService.address == "0.0.0.0") {
let addressList = [];
sockets.forEach((socket, address) => {
if (address != "127.0.0.1") {
addressList.push(address);
}
});
this._getBroadcastSocket().then(socket => {
let packet = this._makeServicePacket(publishedService, addressList);
let data = packet.serialize();
socket.send(MDNS_MULTICAST_GROUP, MDNS_PORT, data, data.length);
});
} else {
sockets.forEach((socket, address) => {
if (address == publishedService.address) {
let packet = this._makeServicePacket(publishedService, [address]);
let data = packet.serialize();
socket.send(MDNS_MULTICAST_GROUP, MDNS_PORT, data, data.length);
}
});
}
this._advertiseServiceHelper(publishedService, null).then(() => {
// If first advertisement, re-advertise in 1 second.
// Otherwise, set the lastAdvertised time.
if (firstAdv) {
@ -268,6 +261,28 @@ class MulticastDNS {
});
}
_advertiseServiceHelper(svc, target) {
if (!target) {
target = {address:MDNS_MULTICAST_GROUP, port:MDNS_PORT};
}
return this._getSockets().then((sockets) => {
sockets.forEach((socket, address) => {
if (svc.address == "0.0.0.0" || address == svc.address)
{
let packet = this._makeServicePacket(svc, [address]);
let data = packet.serialize();
try {
socket.send(target.address, target.port, data, data.length);
} catch (err) {
DEBUG && debug("Failed to send packet to "
+ target.address + ":" + target.port);
}
}
});
});
}
_cancelBroadcastTimer() {
if (!this._broadcastTimer) {
return;
@ -323,6 +338,7 @@ class MulticastDNS {
}
_query(name) {
DEBUG && debug('query("' + name + '")');
let packet = new DNSPacket();
packet.setFlag('QR', DNS_QUERY_RESPONSE_CODES.QUERY);
@ -336,15 +352,15 @@ class MulticastDNS {
let data = packet.serialize();
this._getSockets().then((sockets) => {
sockets.forEach((socket) => {
socket.send(MDNS_MULTICAST_GROUP, MDNS_PORT, data, data.length);
});
this._getQuerySocket().then(querySocket => {
DEBUG && debug('sending query on query socket ("' + name + '")');
querySocket.send(MDNS_MULTICAST_GROUP, MDNS_PORT, data, data.length);
});
// Automatically announce previously-discovered
// services that match and haven't expired yet.
setTimeout(() => {
DEBUG && debug('announcing previously discovered services ("' + name + '")');
let { serviceType } = _parseServiceDomainName(name);
this._clearExpiredDiscoveries();
@ -386,8 +402,9 @@ class MulticastDNS {
}
for (let [serviceKey, publishedService] of this._services) {
DEBUG && debug("_handleQueryPacket: " + packet.toJSON());
if (publishedService.ptrMatch(record.name)) {
this._advertiseService(serviceKey);
this._respondToQuery(serviceKey, message);
}
}
});
@ -542,6 +559,18 @@ class MulticastDNS {
DEBUG && debug('_onServiceFound()' + serviceInfo.serviceName);
}
_getQuerySocket() {
return new Promise((resolve, reject) => {
if (!this._querySocket) {
this._querySocket = _openSocket(0, {
onPacketReceived: this._onResponsePacketReceived.bind(this),
onStopListening: this._onResponseStopListening.bind(this)
}, /* joinMulticast = */ false);
}
resolve(this._querySocket);
});
}
_getSockets() {
return new Promise((resolve) => {
if (this._sockets.size > 0) {
@ -551,17 +580,10 @@ class MulticastDNS {
Promise.all([getAddresses(), getHostname()]).then(() => {
_addresses.forEach((address) => {
let socket = Cc['@mozilla.org/network/udp-socket;1']
.createInstance(Ci.nsIUDPSocket);
socket.init(MDNS_PORT, false,
Services.scriptSecurityManager.getSystemPrincipal());
socket.asyncListen({
let socket = _openSocket(MDNS_PORT, {
onPacketReceived: this._onPacketReceived.bind(this),
onStopListening: this._onStopListening.bind(this)
});
socket.joinMulticast(MDNS_MULTICAST_GROUP, address);
}, /* joinMulticast = */ address);
this._sockets.set(address, socket);
});
@ -572,17 +594,10 @@ class MulticastDNS {
_getBroadcastSocket() {
return new Promise((resolve) => {
if (this._broadcastSocket !== undefined) {
resolve(this._broadcastSocket);
return;
if (!this._broadcastSocket) {
this._broadcastSocket = _openSocket(MDNS_PORT, null,
/* joinMulticast = */ false);
}
let socket = Cc['@mozilla.org/network/udp-socket;1']
.createInstance(Ci.nsIUDPSocket);
socket.init(MDNS_PORT, false,
Services.scriptSecurityManager.getSystemPrincipal());
this._broadcastSocket = socket;
resolve(this._broadcastSocket);
});
}
@ -609,6 +624,11 @@ class MulticastDNS {
this._sockets.clear();
}
_onResponsePacketReceived(socket, message) {
DEBUG && debug('_onResponsePacketReceived');
this._onPacketReceived(socket, message);
}
_onPacketReceived(socket, message) {
let packet = DNSPacket.parse(message.rawData);
@ -628,6 +648,11 @@ class MulticastDNS {
DEBUG && debug('_onStopListening() ' + status);
}
_onResponseStopListening(socket, status) {
DEBUG && debug('_onResponseStopListening() ' + status);
}
_addServiceListener(serviceType, listener) {
let listeners = this._listeners.get(serviceType);
if (!listeners) {
@ -762,3 +787,26 @@ function _propertyBagToObject(propBag) {
}
return result;
}
/**
* @private
*/
function _openSocket(port, handler, joinMulticast) {
let socket = Cc['@mozilla.org/network/udp-socket;1']
.createInstance(Ci.nsIUDPSocket);
if (arguments.length <= 2)
joinMulticast = true;
socket.init(port, false,
Services.scriptSecurityManager.getSystemPrincipal());
if (handler) {
socket.asyncListen({
onPacketReceived: handler.onPacketReceived,
onStopListening: handler.onStopListening
});
}
if (joinMulticast !== false)
socket.joinMulticast(MDNS_MULTICAST_GROUP, joinMulticast);
return socket;
}