Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-interface support. #38

Closed
wants to merge 9 commits into from
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ Creates a new `mdns` instance. Options can contain the following
``` js
{
multicast: true // use udp multicasting
interface: '192.168.0.2' // explicitly specify a network interface. defaults to all
interface: '192.168.0.2' // explicitly specify a network interface or array of interfaces**
port: 5353, // set the udp port
ip: '224.0.0.251', // set the udp ip
ttl: 255, // set the multicast ttl
Expand All @@ -123,6 +123,10 @@ Creates a new `mdns` instance. Options can contain the following
}
```

<sup>**</sup> The interface option should be specified on host systems with multiple network
interface options. When not specified a single interface will be automatically chosen for
broadcasting.

#### `mdns.on('query', (packet, rinfo))`

Emitted when a query packet is received.
Expand Down
54 changes: 45 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,39 @@ module.exports = function (opts) {
var ip = opts.ip || opts.host || (type === 'udp4' ? '224.0.0.251' : null)
var me = {address: ip, port: port}
var destroyed = false
var interfaces = opts.interface ? (Array.isArray(opts.interface) ? opts.interface : [opts.interface]) : []
var sendSockets = []

if (type === 'udp6' && (!ip || !opts.interface)) {
if (type === 'udp6' && (!ip || !interfaces.length)) {
throw new Error('For IPv6 multicast you must specify `ip` and `interface`')
}

// create sockets to send messages
for (var si = 0; si <= interfaces.length; si++) {
sendSockets[si] = dgram.createSocket({
type: type,
reuseAddr: opts.reuseAddr !== false,
toString: function () {
return type
}
})

sendSockets[si].on('listening', function () {
if (opts.multicast !== false) {
this.setMulticastTTL(opts.ttl || 255)
this.setMulticastLoopback(opts.loopback !== false)
}
})

sendSockets[si].on('error', function (err) {
if (err.code === 'EACCES' || err.code === 'EADDRINUSE') that.emit('error', err)
else that.emit('warning', err)
})

sendSockets[si].bind(port, interfaces[si] || null)
}

// create socket to listen for messages
var socket = opts.socket || dgram.createSocket({
type: type,
reuseAddr: opts.reuseAddr !== false,
Expand Down Expand Up @@ -48,8 +76,14 @@ module.exports = function (opts) {

socket.on('listening', function () {
if (!port) port = me.port = socket.address().port
if (opts.multicast !== false) {
socket.addMembership(ip, opts.interface)
if (opts.multicast !== false && interfaces.length) {
interfaces.forEach(function (iface) {
try {
socket.addMembership(ip, iface)
} catch (err) {
that.emit('warning', err)
}
})
socket.setMulticastTTL(opts.ttl || 255)
socket.setMulticastLoopback(opts.loopback !== false)
}
Expand All @@ -58,7 +92,7 @@ module.exports = function (opts) {
var bind = thunky(function (cb) {
if (!port) return cb(null)
socket.once('error', cb)
socket.bind(port, opts.interface, function () {
socket.bind(port, function () {
socket.removeListener('error', cb)
cb(null)
})
Expand All @@ -73,11 +107,10 @@ module.exports = function (opts) {
if (typeof rinfo === 'function') return that.send(value, null, rinfo)
if (!cb) cb = noop
if (!rinfo) rinfo = me
bind(function (err) {
if (destroyed) return cb()
if (err) return cb(err)
var message = packet.encode(value)
socket.send(message, 0, message.length, rinfo.port, rinfo.address || rinfo.host, cb)
if (destroyed) return cb()
var message = packet.encode(value)
sendSockets.forEach(function (sendSocket) {
sendSocket.send(message, 0, message.length, rinfo.port, rinfo.address || rinfo.host, cb)
})
}

Expand Down Expand Up @@ -108,6 +141,9 @@ module.exports = function (opts) {
destroyed = true
socket.once('close', cb)
socket.close()
sendSockets.forEach(function (sendSocket) {
sendSocket.close()
})
}

return that
Expand Down