1
votes

I'm trying to implement a UPnP discovery service tool (SSDP protocol), I did something similar in python following this post: https://www.electricmonk.nl/log/2016/07/05/exploring-upnp-with-python/ and I would like to port it to node (v. 8.6.0) and typescript however I'm getting the following error when I try to send the message (socket.send(...)):

{ Error: send EADDRNOTAVAIL 239.255.255.250:1900
    at Object._errnoException (util.js:1019:11)
    at _exceptionWithHostPort (util.js:1041:20)
    at SendWrap.afterSend [as oncomplete] (dgram.js:475:11)
  code: 'EADDRNOTAVAIL',
  errno: 'EADDRNOTAVAIL',
  syscall: 'send',
  address: '239.255.255.250',
  port: 1900 }

I've found a snippet of code for node, that makes this exact thing (https://coolaj86.com/articles/adventures-in-upnp-with-node-js/) and I think that my code is quite equivalent however I cannot see why my code isn't working

const dgram = require('dgram');
const socket = dgram.createSocket('udp4');

let msg_txt = 'M-SEARCH * HTTP/1.1\r\n' +
    'HOST:239.255.255.250:1900\r\n' +
    'ST:upnp:rootdevice\r\n' +
    'MX:2\r\n' +
    'MAN:"ssdp:discover"\r\n\r\n';

const message = Buffer.from(msg_txt);

socket.on('message', (msg: Buffer, info: any) => {
    console.log(msg.toString());
});

socket.bind({
    address: '239.255.255.250',
    port: 1900
}, (err) => {
    !!err && console.error(err);
});

socket.on('listening', () => {
    console.log('Sending msg...');
    socket.send(message, 0, message.length, 1900, '239.255.255.250', (err) => {
        !!err && console.error(err); // err != null
    });
});

I suspect that is a typical one-line-problem but after a while I couldn't find it out, any help is welcome.

2

2 Answers

0
votes

I saw it, in node the API is a bit different, the binding should be against the '0.0.0.0' iface and the port 0 (for a random number), so changing the binding command to the following code just fix it:

socket.bind({
    address: '0.0.0.0',
    port: 0
}, (err) => {
    !!err && console.error(err);
});

In python I called to socket.recvfrom() method to get the UPnP devices responses, there is not an explicit socket binding.

0
votes

For what it's worth, I had a similar setup using Node 10 on Windows and creating a udp4 socket on localhost. Weirdly enough, the setup described in the accepted answer worked on every OS and Node version except Node 10 on Windows in my CI tests. In order to get things to work, I had to explicitly bind to the address localhost instead of 0.0.0.0, like so:

const socket = dgram.createSocket('udp4').unref();
socket.bind({
    address: 'localhost',
    port: 0
}, (err) => {
    !!err && console.error(err);
});