diversario / node-ssdp

node.js SSDP client/server.
MIT License
273 stars 120 forks source link

SSDP server does not respond to mutlicast M-SEARCH requests #76

Open codersaur opened 7 years ago

codersaur commented 7 years ago

Hi,

I am hoping to use node-ssdp server to advertise a custom UPnP-like device on my network. I've got it up and running and I can see that it is sending out multicast SSDP advertisements as expected. However, I also need it to be able to respond to multicast M-SEARCH requests too. Here, it falls down (or at least, there is no documentation explaining how to enable it).

My setup:

var ssdpServer  = require('node-ssdp').Server;
ssdp = new ssdpServer({
    location: require('ip').address() + '/desc.xml'
});
ssdp.addUSN('urn:codersaur-com:device:DeviceType:1');
ssdp.start();

A typical M-SEARCH multicast request (sent from a client):

M-SEARCH * HTTP/1.1 
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 4
ST: codersaur-com:device:DeviceType:1

Doing some debugging, I can see that the ssdpServer is simply ignoring multicast packets.

Following the advice here it seems the solution is to bind the socket to the multicast port (i.e. 1900) only. I have been able to do this by specifying the sourcePort in the configuration parameters to be the same, i.e.:

var ssdpServer  = require('node-ssdp').Server;
ssdp = new ssdpServer({
    location: require('ip').address() + '/desc.xml',
    sourcePort: 1900,
});
ssdp.addUSN('urn:codersaur-com:device:DeviceType:1');
ssdp.start();

The SSDP server now binds to address: 'http://0.0.0.0:1900', ... and is able to respond to multicast M-SEARCH requests properly with a unicast response to the originator of the M-SEARCH request.

However, this leaves me with some questions:

  1. is this the correct way to get node-ssdp to respond to multicast M-SEARCH requests?
  2. would it not be better for node-ssdp to bind two sockets on each interface (one for receiving multicast M-SEARCH requests, and another for sending/receiving all unicast traffic)?
  3. is sourcePort supposed to be used this way? I think there is possibly a mis-match between the code and the documentation as unicastBindPort is mentioned in the readme, but not the code (and vice-versa)?

Thanks, codersaur.

codersaur commented 7 years ago

Also, if this is the recommended way to get node-ssdp to respond to multicast M-SEARCH requests, then it's worth pointing out that it doesn't appear to add an appropriate time delay (as specified by the MX header).

UPnP Device Architecture 1.1

Devices responding to a multicast M-SEARCH SHOULD wait a random period of time between 0 seconds and the number of seconds specified in the MX field value of the search request before responding, in order to avoid flooding the requesting control point with search responses from multiple devices.

marclennox commented 6 years ago

I'm seeing the same thing, unless I use sourcePort: 1900 it won't respond to M-SEARCH requests. Is this expected behaviour?

opichals commented 6 years ago

I am seeing the same thing for M-SEARCH sent from a WeMo Android app (but not from OSX node.js client). The only difference I can see in the packet is that the WeMo app is not using the multicast mac address (the Ethernet.Dst fields):

The node-ssdp did not respond to this packet from the WeMo Android app:

Frame 11: 159 bytes on wire (1272 bits), 159 bytes captured (1272 bits) on interface 0
Ethernet II, Src: LgElectr_YY:YY:YY (d0:13:fd:YY:YY:YY), Dst: Apple_XX:XX:XX (10:40:f3:XX:XX:XX)
Internet Protocol Version 4, Src: 10.0.6.60, Dst: 239.255.255.250
User Datagram Protocol, Src Port: 8008, Dst Port: 1900
Simple Service Discovery Protocol
    M-SEARCH * HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): M-SEARCH * HTTP/1.1\r\n]
        Request Method: M-SEARCH
        Request URI: *
        Request Version: HTTP/1.1
    ST: urn:Belkin:service:basicevent:1\r\n
    MX: 2\r\n
    MAN: "ssdp:discover"\r\n
    HOST: 239.255.255.250:1900\r\n
    \r\n
    [Full request URI: http://239.255.255.250:1900*]
    [HTTP request 2/3]
    [Prev request in frame: 8]
    [Next request in frame: 75]

But then normally responded to the following packet:

Ethernet II, Src: Apple_XX:XX:XX (10:40:f3:XX:XX:XX), Dst: IPv4mcast_7f:ff:fa (01:00:5e:7f:ff:fa)
Internet Protocol Version 4, Src: 10.0.6.65, Dst: 239.255.255.250
User Datagram Protocol, Src Port: 56578, Dst Port: 1900
Simple Service Discovery Protocol
    M-SEARCH * HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): M-SEARCH * HTTP/1.1\r\n]
        Request Method: M-SEARCH
        Request URI: *
        Request Version: HTTP/1.1
    HOST: 239.255.255.250:1900\r\n
    ST: urn:Belkin:service:basicevent:1\r\n
    MAN: "ssdp:discover"\r\n
    MX: 3\r\n
    \r\n
    [Full request URI: http://239.255.255.250:1900*]
    [HTTP request 1/2]
    [Next request in frame: 4]
troppoli commented 5 years ago

I was also having trouble with getting responses to m-search, among other things. For me, changing the default 'ssdpTtl' item in the server config to 2 as the spec suggests from 4, made the server respond.

In your trace above look for 'MX:', that is what ssdpTtl will set.

I also did have to turn on explicitSocketBind when I had more than one interface on win10.

To limit network congestion, the time-to-live (TTL) of each IP packet for each multicast message SHOULD default to 2 and SHOULD be configurable. When the TTL is greater than 1, it is possible for multicast messages to traverse multiple routers; therefore control points and devices using non-AutoIP addresses MUST send an IGMP Join message so that routers will forward multicast messages to them (this is not necessary when using an Auto-IP address, since packets with Auto-IP addresses will not be forwarded by routers).

spec

simonmitchell commented 5 years ago

Also seeing this but nothing here seems to be helping 😞 Is there anything else anyone else tried? I'm on macOS. Seems like the socket.on('message' is never called! @troppoli @opichals