diff --git a/index.html b/index.html index d5a69c6..e0e4018 100644 --- a/index.html +++ b/index.html @@ -27,6 +27,13 @@ +
+

Device Discovery

+ +
+
+ +
diff --git a/index.js b/index.js index eb097aa..c3c0dd9 100644 --- a/index.js +++ b/index.js @@ -36,6 +36,7 @@ function createWindow () { require('./progress').init(win); require('./drag-drop-main').init(win); require('./startup-main').init(win); + require('./mdns-main').init(win); // // Open the DevTools. // win.webContents.openDevTools(); diff --git a/mdns-main.js b/mdns-main.js new file mode 100644 index 0000000..efe222d --- /dev/null +++ b/mdns-main.js @@ -0,0 +1,90 @@ +'use strict'; + +var electron = require('electron'); +var dns = require('dns-suite'); +var ipc = electron.ipcMain; +var win; +var socket; +var mdnsPort = 5353; +var broadcastAddr = '224.0.0.251'; +var queryname = '_cloud._tcp.local'; + +function sendDeviceQuery() { + var id = require('crypto').randomBytes(2).readUInt16LE(); + var rpacket = { + header: { + id: id, + qr: 0, + opcode: 0, + aa: 0, + tc: 0, + rd: 0, + ra: 0, + res1: 0, + res2: 0, + res3: 0, + rcode: 0, + }, + question: [ + { + name: queryname, + typeName: 'PTR', + className: 'IN', + }, + ], + }; + + var buf = dns.DNSPacket.write(rpacket); + socket.send(buf, mdnsPort, broadcastAddr, function () { + console.log('sent mDNS query', buf.toString('hex')); + }); +} + +function handleAnswer(message/*, rinfo*/) { + // console.log('received %d bytes from %s:%d', message.length, rinfo.address, rinfo.port); + + var packet; + try { + packet = dns.DNSPacket.parse(message); + } catch (error) { + // The majority of the packets collected just listening to our local network seem to + // throw exceptions, so don't bother logging them. + return; + } + + + // We are only interested in responses + if (packet.header.qr !== 1) { + return; + } + // And we only want the responses to the question we send (should be sent back in response) + if (packet.question.length !== 1 || packet.question[0].name !== queryname) { + return; + } + win.webContents.send('deviceFound', packet); +} + +function init(window) { + if (win) { + console.error("can't initialize device discovery multiple times"); + return; + } + win = window; + + socket = require('dgram').createSocket({ type: 'udp4', reuseAddr: true }); + socket.on('message', handleAnswer); + + socket.bind(mdnsPort, function () { + var addr = this.address(); + console.log('mDNS device discovery bound on %s:%d', addr.address, addr.port); + + socket.setBroadcast(true); + socket.addMembership(broadcastAddr); + }); + + ipc.on('startDeviceScan', sendDeviceQuery); +} + +module.exports = { + init: init, +}; diff --git a/mdns-render.js b/mdns-render.js new file mode 100644 index 0000000..95c978e --- /dev/null +++ b/mdns-render.js @@ -0,0 +1,14 @@ +'use strict'; + +var electron = require('electron'); +var ipc = electron.ipcRenderer; + +ipc.on('deviceFound', function (e, packet) { + console.log(JSON.stringify(packet)); +}); + +document.body.addEventListener('click', function (ev) { + if (ev.target.classList.contains('query-devices')) { + ipc.send('startDeviceScan'); + } +}); diff --git a/package.json b/package.json index 53ae05d..ed1ab29 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "electron-packager": "^8.6.0" }, "dependencies": { - "auto-launch": "^5.0.1" + "auto-launch": "^5.0.1", + "dns-suite": "git+https://git@git.daplie.com:Daplie/dns-suite#v1" } }