Yortw / RSSDP

Really Simple Service Discovery Protocol - a 100% .Net implementation of the SSDP protocol for publishing custom/basic devices, and discovering all device types on a network.
http://yortw.github.io/RSSDP/
MIT License
288 stars 67 forks source link

RSSDP doesn't work #97

Closed linxzhang closed 5 years ago

linxzhang commented 5 years ago

Hi All, Anyone encouter below problem under Windows 10 (.Net Framework 4.7.2)? Scenario I:

  1. it has 2 network adapters, one is WIFI connecting LAN1, another is Ethernet, connecting LAN2.
  2. there are several UPnP devices at each different LAN (LAN1 & LAN2)
  3. RSSDP can not find all UPnP devices on both LANs, just search only one LAN, however Intel UPnP tools: Device Spy works pretty OK on both LAN.

Scenario II:

  1. Disable WIFI adapter.
  2. enable virtual network adapters (Virtual Box installed) or Wireshark Npcap loopback Adapter.
  3. RSSDP can not find any UPnP devices! while Intel UPnP tools works OK too.

Scenario III:

  1. Disable all network adapters except Ethernet adapter.
  2. RSSDP search and find UPnP devices.

Anyone knows how to fix this issue!

Yortw commented 5 years ago

Hi there,

Short (likely/probable) answer: RSSDP is a library that operates a slightly lower level of abstraction than the UPnP Device Spy utility. Device Spy searches multiple/all adapters by default. RSSDP will only search one adapter per 'SsdpLocator' instance. If you construct the SsdpLocator with a local IP, it will search on the adapter associated with that address. If you do not, then RSSDP passes the IPAddress.Any value to the .Net sockets system, and while I don't know the exact details of how that works it would seem .Net tries to pick what it thinks is the best adapter for your needs - and often gets that wrong. Certainly if you need to search multiple adapters, it's only ever going to pick one, so won't ever be 'correct'.

This would explain scenario I where you only see the devices from one adapter. It may also explain scenario 2, as if you're using the default IPAddress.Any binding then .Net may well choose one of the virtual adapters to search and won't find anything on it. If I understand your scenario 3 correctly, then this is also matches this explanation, as with only one adapter enabled that is the one .Net will choose.

To solve this you need to do two things;

  1. Construct multiple instances of the SsdpLocator (one for each adapter) and search on each of them, then combine the results (deduping if needed/wanted - it's possible the same device might publish on two different networks, do you need both entries? That's up to your app to decide).

  2. When constructing each instance, specify the local IP of the adapter to bind it to, so each searches a different network.

tl;dr Re scenario I: If you examine the code for the Intel UPnP tools far enough, you'll end up in the method

c# FindDeviceAsync(String SearchTarget, IPEndPoint RemoteEP)

in a class called UPnPControlPoint. This method is normally called from an overload of the same method, which calls this one once for IPv4 adapters, and then again for IPv6 adapters twice using different ports.

If you examine the code in the specific overload mentioned above, it loops through all adapters of the type & port specified and searches on each of them in turn;

`c# // snip

        IPAddress[] LocalAddresses = NetInfo.GetLocalAddresses();

        foreach (IPAddress localaddr in LocalAddresses)
        {
           // *snip*
                if (RemoteEP.AddressFamily != session.Client.AddressFamily) continue;
                if ((RemoteEP.AddressFamily == AddressFamily.InterNetworkV6) && ((IPEndPoint)session.Client.LocalEndPoint).Address.IsIPv6LinkLocal == true && RemoteEP != Utils.UpnpMulticastV6EndPoint2) continue;
                if ((RemoteEP.AddressFamily == AddressFamily.InterNetworkV6) && ((IPEndPoint)session.Client.LocalEndPoint).Address.IsIPv6LinkLocal == false && RemoteEP != Utils.UpnpMulticastV6EndPoint1) continue;
            //*snip*

                session.Send(buffer, buffer.Length, RemoteEP);
                session.Send(buffer, buffer.Length, RemoteEP);
        }

`

So Device Spy is searching every adapter in your machine all at once.

In Rssdp each SsdpLocator only searches on one adapter, by design. Some apps only want to search one/some networks and not all. If you want to use Rssdp to search all adapters, you need to create one per adapter the same way as the UPnP library creates and calls search on multiple 'session' objects internally.

As for your other issues, I suspect they may be caused by not specifying a local IP when creating the SsdpLocator instances (it's hard to tell without seeing any sample code, but this would fit the symptoms). When you don't specify an local IP address for the locator objects explicitly, .Net (or Windows, not sure which) will pick one based on it's own rules (I don't know what those rules are). The system won't always pick the same adapter, seems prone to picking a useless adapter (one with a self assigned address, one that is enabled but not connected, virtual adapters on networks with no other devices etc). In any case, if you need multiple adapters it can't do the right thing because it will only pick one adapter and you need to search more than one.

Hope this helps. Unfortunately I don't have any other ideas, everything works fine for me on multiple machines/networks when I follow the above rules (create one locator object per local ip address and search all of them). As mentioned, I examined the UPnP tool source code, and it definitely explicitly searches each adapter internally, so different design but is doing the multiple searches as I'm suggesting you do with Rssdp, it's just more manual with this lib.

Good luck.

linxzhang commented 5 years ago

Thanks for your more detail description! In fact, after submit this "issue" I had seen FAQ that explains this too.