| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 | 
							- var packet = require('dns-packet')
 
- var dgram = require('dgram')
 
- var thunky = require('thunky')
 
- var events = require('events')
 
- var os = require('os')
 
- var noop = function () {}
 
- module.exports = function (opts) {
 
-   if (!opts) opts = {}
 
-   var that = new events.EventEmitter()
 
-   var port = typeof opts.port === 'number' ? opts.port : 5353
 
-   var type = opts.type || 'udp4'
 
-   var ip = opts.ip || opts.host || (type === 'udp4' ? '224.0.0.251' : null)
 
-   var me = {address: ip, port: port}
 
-   var memberships = {}
 
-   var destroyed = false
 
-   var interval = null
 
-   if (type === 'udp6' && (!ip || !opts.interface)) {
 
-     throw new Error('For IPv6 multicast you must specify `ip` and `interface`')
 
-   }
 
-   var socket = opts.socket || dgram.createSocket({
 
-     type: type,
 
-     reuseAddr: opts.reuseAddr !== false,
 
-     toString: function () {
 
-       return type
 
-     }
 
-   })
 
-   socket.on('error', function (err) {
 
-     if (err.code === 'EACCES' || err.code === 'EADDRINUSE') that.emit('error', err)
 
-     else that.emit('warning', err)
 
-   })
 
-   socket.on('message', function (message, rinfo) {
 
-     try {
 
-       message = packet.decode(message)
 
-     } catch (err) {
 
-       that.emit('warning', err)
 
-       return
 
-     }
 
-     that.emit('packet', message, rinfo)
 
-     if (message.type === 'query') that.emit('query', message, rinfo)
 
-     if (message.type === 'response') that.emit('response', message, rinfo)
 
-   })
 
-   socket.on('listening', function () {
 
-     if (!port) port = me.port = socket.address().port
 
-     if (opts.multicast !== false) {
 
-       that.update()
 
-       interval = setInterval(that.update, 5000)
 
-       socket.setMulticastTTL(opts.ttl || 255)
 
-       socket.setMulticastLoopback(opts.loopback !== false)
 
-     }
 
-   })
 
-   var bind = thunky(function (cb) {
 
-     if (!port) return cb(null)
 
-     socket.once('error', cb)
 
-     socket.bind(port, opts.interface, function () {
 
-       socket.removeListener('error', cb)
 
-       cb(null)
 
-     })
 
-   })
 
-   bind(function (err) {
 
-     if (err) return that.emit('error', err)
 
-     that.emit('ready')
 
-   })
 
-   that.send = function (value, rinfo, cb) {
 
-     if (typeof rinfo === 'function') return that.send(value, null, rinfo)
 
-     if (!cb) cb = noop
 
-     if (!rinfo) rinfo = me
 
-     bind(onbind)
 
-     function onbind (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)
 
-     }
 
-   }
 
-   that.response =
 
-   that.respond = function (res, rinfo, cb) {
 
-     if (Array.isArray(res)) res = {answers: res}
 
-     res.type = 'response'
 
-     res.flags = (res.flags || 0) | packet.AUTHORITATIVE_ANSWER
 
-     that.send(res, rinfo, cb)
 
-   }
 
-   that.query = function (q, type, rinfo, cb) {
 
-     if (typeof type === 'function') return that.query(q, null, null, type)
 
-     if (typeof type === 'object' && type && type.port) return that.query(q, null, type, rinfo)
 
-     if (typeof rinfo === 'function') return that.query(q, type, null, rinfo)
 
-     if (!cb) cb = noop
 
-     if (typeof q === 'string') q = [{name: q, type: type || 'ANY'}]
 
-     if (Array.isArray(q)) q = {type: 'query', questions: q}
 
-     q.type = 'query'
 
-     that.send(q, rinfo, cb)
 
-   }
 
-   that.destroy = function (cb) {
 
-     if (!cb) cb = noop
 
-     if (destroyed) return process.nextTick(cb)
 
-     destroyed = true
 
-     clearInterval(interval)
 
-     socket.once('close', cb)
 
-     socket.close()
 
-   }
 
-   that.update = function () {
 
-     var ifaces = opts.interface ? [].concat(opts.interface) : allInterfaces()
 
-     var updated = false
 
-     for (var i = 0; i < ifaces.length; i++) {
 
-       var addr = ifaces[i]
 
-       if (memberships[addr]) continue
 
-       memberships[addr] = true
 
-       updated = true
 
-       try {
 
-         socket.addMembership(ip, addr)
 
-       } catch (err) {
 
-         that.emit('warning', err)
 
-       }
 
-     }
 
-     if (!updated || !socket.setMulticastInterface) return
 
-     socket.setMulticastInterface(opts.interface || defaultInterface())
 
-   }
 
-   return that
 
- }
 
- function defaultInterface () {
 
-   var networks = os.networkInterfaces()
 
-   var names = Object.keys(networks)
 
-   for (var i = 0; i < names.length; i++) {
 
-     var net = networks[names[i]]
 
-     for (var j = 0; j < net.length; j++) {
 
-       var iface = net[j]
 
-       if (iface.family === 'IPv4' && !iface.internal) return iface.address
 
-     }
 
-   }
 
-   return '127.0.0.1'
 
- }
 
- function allInterfaces () {
 
-   var networks = os.networkInterfaces()
 
-   var names = Object.keys(networks)
 
-   var res = []
 
-   for (var i = 0; i < names.length; i++) {
 
-     var net = networks[names[i]]
 
-     for (var j = 0; j < net.length; j++) {
 
-       var iface = net[j]
 
-       if (iface.family === 'IPv4') {
 
-         res.push(iface.address)
 
-         // could only addMembership once per interface (https://nodejs.org/api/dgram.html#dgram_socket_addmembership_multicastaddress_multicastinterface)
 
-         break
 
-       }
 
-     }
 
-   }
 
-   return res
 
- }
 
 
  |