Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 3 additions & 70 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,72 +1,5 @@

const Mdns = require('./lib');
const Networking = require('./lib/networking');

var config = require('./package.json');
var st = require('./lib/service_type');
var Networking = require('./lib/networking');

var networking = new Networking();

/** @member {string} */
module.exports.version = config.version;
module.exports.name = config.name;

/* @borrows Browser as Browser */
var Browser = module.exports.Browser = require('./lib/browser'); //just for convenience
/* @borrows Advertisement as Advertisement */
var Advertisement = module.exports.Advertisement = require('./lib/advertisement'); //just for convenience

/**
* Create a browser instance
* @method
* @param {string} [serviceType] - The Service type to browse for. Defaults to ServiceType.wildcard
* @return {Browser}
*/
module.exports.createBrowser = function browserCreated(serviceType) {
if (typeof serviceType === 'undefined') {
serviceType = st.ServiceType.wildcard;
}
return new Browser(networking, serviceType);
};


module.exports.excludeInterface = function (iface) {
if (networking.started) {
throw new Error('can not exclude interfaces after start');
}
if (iface === '0.0.0.0') {
networking.INADDR_ANY = false;
}
else {
var err = new Error('Not a supported interface');
err.interface = iface;
}
};


/**
* Create a service instance
* @method
* @param {string|ServiceType} serviceType - The service type to register
* @param {number} [port] - The port number for the service
* @param {object} [options] - ...
* @return {Advertisement}
*/
module.exports.createAdvertisement =
function advertisementCreated(serviceType, port, options) {
return new Advertisement(
networking, serviceType, port, options);
};


/** @property {module:ServiceType~ServiceType} */
module.exports.ServiceType = st.ServiceType;

/** @property {module:ServiceType.makeServiceType} */
module.exports.makeServiceType = st.makeServiceType;

/** @function */
module.exports.tcp = st.protocolHelper('tcp');

/** @function */
module.exports.udp = st.protocolHelper('udp');

module.exports = new Mdns({networking: new Networking()});
25 changes: 16 additions & 9 deletions lib/advertisement.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
var debug = require('debug')('mdns:advertisement');
const { DNSRecord } = require('dns-js');

var dns = require('dns-js');
var DNSRecord = dns.DNSRecord;
var ServiceType = require('./service_type').ServiceType;
var pf = require('./packetfactory');

Expand All @@ -23,6 +22,7 @@ internal.handleQuery = function (rec) {
debug('skipping query: type not PTR/SRV/ANY');
return;
}
var self = this;
// check if we should reply via multi or unicast
// TODO: handle the is_qu === true case and reply directly to remote
// var is_qu = (rec.cl & DNSRecord.Class.IS_QM) === DNSRecord.Class.IS_QM;
Expand All @@ -32,14 +32,15 @@ internal.handleQuery = function (rec) {
return;
}
try {
debug('trying to handleQuery with %s queries', internal.services.length);
var type = new ServiceType(rec.name);
internal.services.forEach(function (service) {
if (type.isWildcard() || type.matches(service.serviceType)) {
debug('answering query');
// TODO: should we only send PTR records if the query was for PTR
// records?
internal.sendDNSPacket(
pf.buildANPacket.apply(service, [DNSRecord.TTL]));
pf.buildANPacket.apply(service, [DNSRecord.TTL, self.networking]));
}
else {
debug('skipping query; type %s not * or %s', type,
Expand Down Expand Up @@ -98,7 +99,7 @@ internal.probeAndAdvertise = function () {
break;
case 3:
debug('publishing service, suffix=%s', this.nameSuffix);
var packet = pf.buildANPacket.apply(this, [DNSRecord.TTL]);
var packet = pf.buildANPacket.apply(this, [DNSRecord.TTL, this.networking]);
internal.sendDNSPacket = this.networking.send.bind(this.networking);
this.networking.send(packet);
// Repost announcement after 1sec (see rfc6762: 8.3)
Expand All @@ -121,6 +122,7 @@ internal.probeAndAdvertise = function () {
this.status = -1;
break;
}
//drive the statemachine forward if <3
if (this.status < 3) {
this.status++;
setTimeout(internal.probeAndAdvertise.bind(this), 250);
Expand Down Expand Up @@ -157,27 +159,32 @@ var Advertisement = module.exports = function (
this.networking.INADDR_ANY = this.options.INADDR_ANY;
}

networking.on('packets', function (packets /*, remote, connection*/) {
this.networking.on('packets', function (packets /*, remote, connection*/) {
packets.forEach(function (packet) {
packet.question.forEach(internal.handleQuery.bind(self));
packet.answer.forEach(internal.handleAnswer.bind(self));
});
});

this.start = function () {
networking.addUsage(self, function () {
debug('start advertisement');

function creationCallback() {
debug('creationCallback');
internal.probes.push(self);
internal.probeAndAdvertise.apply(self, []);
});
}

self.networking.addUsage(self, creationCallback);
};

this.stop = function (next) {
debug('unpublishing service');
internal.services =
internal.services.filter(function (service) { return service === self; });

networking.send(pf.buildANPacket.apply(self, [0]), function () {
networking.stop();
self.networking.send(pf.buildANPacket.apply(self, [0, networking]), function () {
self.networking.stop();
if (next) {
next();
}
Expand Down
78 changes: 78 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@


var config = require('../package.json');
var st = require('./service_type');


function Mdns(options) {
this.networking = options.networking;
}

module.exports = Mdns;



/** @member {string} */
module.exports.version = config.version;
module.exports.name = config.name;

/* @borrows Browser as Browser */
var Browser = module.exports.Browser = require('./browser'); //just for convenience
/* @borrows Advertisement as Advertisement */
var Advertisement = module.exports.Advertisement = require('./advertisement'); //just for convenience

/**
* Create a browser instance
* @method
* @param {string} [serviceType] - The Service type to browse for. Defaults to ServiceType.wildcard
* @return {Browser}
*/
Mdns.prototype.createBrowser = function browserCreated(serviceType) {
if (typeof serviceType === 'undefined') {
serviceType = st.ServiceType.wildcard;
}
return new Browser(this.networking, serviceType);
};


Mdns.prototype.excludeInterface = function (iface) {
if (this.networking.started) {
throw new Error('can not exclude interfaces after start');
}
if (iface === '0.0.0.0') {
this.networking.INADDR_ANY = false;
}
else {
var err = new Error('Not a supported interface');
err.interface = iface;
}
};


/**
* Create a service instance
* @method
* @param {string|ServiceType} serviceType - The service type to register
* @param {number} [port] - The port number for the service
* @param {object} [options] - ...
* @return {Advertisement}
*/
Mdns.prototype.createAdvertisement =
function advertisementCreated(serviceType, port, options) {
return new Advertisement(
this.networking, serviceType, port, options);
};


/** @property {module:ServiceType~ServiceType} */
Mdns.prototype.ServiceType = st.ServiceType;

/** @property {module:ServiceType.makeServiceType} */
Mdns.prototype.makeServiceType = st.makeServiceType;

/** @function */
Mdns.prototype.tcp = st.protocolHelper('tcp');

/** @function */
Mdns.prototype.udp = st.protocolHelper('udp');

5 changes: 5 additions & 0 deletions lib/networking.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var Networking = module.exports = function (options) {
this.connections = [];
this.started = false;
this.users = [];
this.interfaces = {};
this.INADDR_ANY = typeof this.options.INADDR_ANY === 'undefined' ?
true : this.options.INADDR_ANY;
};
Expand All @@ -46,6 +47,10 @@ Networking.prototype.start = function () {
continue;
}
debug('interface', key, iface.address);
if (!this.interfaces.hasOwnProperty(key)) {
this.interfaces[key] = [];
}
this.interfaces[key].push(iface);
this.createSocket(index++, key,
iface.address, 0, this.bindToAddress.bind(this));
}
Expand Down
10 changes: 7 additions & 3 deletions lib/packetfactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ module.exports.buildQDPacket = function () {
return packet;
};

module.exports.buildANPacket = function (ttl) {
module.exports.buildANPacket = function (ttl, networking) {
if (typeof this.nameSuffix !== 'string') {
throw new Error('nameSuffix is missing');
}
if (typeof this.port !== 'number' && this.port < 1) {
throw new Error('port is missing or bad value');
}
//use from networking if possible
var interfaces = networking ? networking.interfaces : os.networkInterfaces();

var packet =
new DNSPacket(DNSPacket.Flag.RESPONSE | DNSPacket.Flag.AUTHORATIVE);
var name = this.options.name + this.nameSuffix;
Expand All @@ -33,7 +36,7 @@ module.exports.buildANPacket = function (ttl) {
var serviceType = this.serviceType.toString() + '.' + domain;
var cl = DNSRecord.Class.IN | DNSRecord.Class.FLUSH;

debug('alias:', this.alias);
debug('#buildANPacket, alias:', this.alias);

packet.answer.push({
name: this.alias,
Expand Down Expand Up @@ -68,11 +71,12 @@ module.exports.buildANPacket = function (ttl) {
ttl: ttl,
data:serviceType});

var interfaces = os.networkInterfaces();

var ifaceFilter = this.options.networkInterface;
var address;
var i;
for (var key in interfaces) {
debug('#buildANPacket, key', key);
if (typeof ifaceFilter === 'undefined' || key === ifaceFilter) {
for (i = 0; i < interfaces[key].length; i++) {
var iface = interfaces[key][i];
Expand Down
Loading