-
Notifications
You must be signed in to change notification settings - Fork 67
Frequently Asked Questions
We're not experts in what Windows Explorer does or doesn't do, but we have noticed a few issues with regards to getting devices published by RSSDP to show in it's network area.
-
Windows Explorer seems to only show certain device types. We're not sure if there is a specific list or if it is any device from the UPnP device schema but if you're using a custom device type and/or schema you're out of luck. If you publish a basic device (full device type = urn:schemas-upnp-org:device:Basic:1) then it should appear.
-
Your XML device description document must be accessible via the URL published in your notifications and search results. This is generally true for most SSDP clients, but it's worth pointing out/double checking.
-
Set the StandardsMode property of the publisher instance to SsdpStandardsMode.Relaxed. This forces the system to do some things that don't appear (to us at least) to be part of the SSDP specification, but Windows Explorer relies on. Basically it enforces the SSDP protocol less strictly, making it play nicely with Windows Explorer and some other systems.
-
Try explicitly refreshing the network node in the Windows Explorer view.
-
Make sure the address used to publish your device is NOT localhost - using localhost definitely won't work if the device is published from another machine, and usually doesn't work even if the publisher is locally hosted. Ensure the published address uses a public IP address or DNS name for the device it's published from.
The most likely cause is the local port you have specified for use by the device locator is in use by another application or service. This is particularly common when port 1900 is used. This is the port reserved for SSDP broadcasts and is often chosen by people for their unicast search port as well. Unfortunately, at least on Windows, if something else (like the Windows SSDP service) has that port open then the search responses sent to that unicast port may be swallowed before reaching your application. Our suggestion is NOT to specify a local port for the device locator, allow the system to choose an unused port to avoid conflicts.
Also see the next section, as that may help too.
In a system with multiple network adapters, sometimes an 'incorrect' adapter is bound instead of the one you'd expect. For example, rather than using your WiFi network, the system might pick a VPN adapter etc. In this case packets are sent/received on the network and you often get no responses, or unexpected/incorrect responses. To solve this you can manualyl specify an IP by passing it to the constructor of a SsdpCommunicationsServer instance, then passing that instance to the publisher/locator instance. For example, the following code forces the locator instance to bind to the network adapter using the address 192.168.1.99;
var locator = new SsdpDeviceLocator(
new Rssdp.Infrastructure.SsdpCommunicationsServer(
new Rssdp.SocketFactory("192.168.1.99")
));
You can also try writing your own code to pick the best adapter automatically. Sometimes a manual implementation works better than the .Net system. Suggested code below (though it may need tweaking for production);
public string GetLocalIpAddress()
{
UnicastIPAddressInformation mostSuitableIp = null;
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (var network in networkInterfaces)
{
if (network.OperationalStatus != OperationalStatus.Up)
continue;
var properties = network.GetIPProperties();
if (properties.GatewayAddresses.Count == 0)
continue;
foreach (var address in properties.UnicastAddresses)
{
if (address.Address.AddressFamily != AddressFamily.InterNetwork)
continue;
if (IPAddress.IsLoopback(address.Address))
continue;
if (!address.IsDnsEligible)
{
if (mostSuitableIp == null)
mostSuitableIp = address;
continue;
}
// The best IP is the IP got from DHCP server
if (address.PrefixOrigin != PrefixOrigin.Dhcp)
{
if (mostSuitableIp == null || !mostSuitableIp.IsDnsEligible)
mostSuitableIp = address;
continue;
}
return address.Address.ToString();
}
}
return mostSuitableIp != null
? mostSuitableIp.Address.ToString()
: "";
}
This shouldn't be a problem with the latest package versions, as we now implement the bait and switch technique. If for some reason (perhaps a platform specific support issue) you can't create the classes in a PCL then try the following;
-
Use dependency injection, this is usually a good idea anyway. Create the instances in your platform specific projects and pass them to your PCL code via the base class type. While not required, we suggest doing this with an IoC container. If you use a container you can even just register the type in the platform project, and the instance won't be created until your code requests it anyway. There really is no harm here.
-
You could create your own instance class (inherit from the base class) with a constructor that takes an ISocketFactory implementation. Unfortunately the socket factory implementations really are platform specific, so while you can now create your concrete type from your PCL code you still need to 'inject' the socket instance... so you might as well have gone with option 1.
Make sure the UWP runtime for your project is at least version 5.2.2, and the package should work fine without any other modifications. If you use an earlier runtime you may get compilation errors about multiple targets for some assemblies used by the runtime.
IF you get an error like the following;
Could not load file or assembly 'System.Runtime.InteropServices.RuntimeInformation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
then edit your project.json and add the following to the 'dependencies' section;
"System.Runtime.InteropServices.RuntimeInformation": "4.0"
Alternatively, add the System.Runtime.InteropServices.RuntimeInformation package via the Nuget UI.
Create your publisher or locator object passing a local IP address, and ensure that address is an IPv6 one. RSSDP will detect that it was given a local IPv6 address and will use the IPv6 broadcast addresses et. When publishing devices, ensure any URL's that contain IP addresses also use the IPv6 version.
IPv6 is NOT supported on WPSL or WinRT (UWP IS supported)
Sample code for creating publisher/locator for use with IPv6 networks;
var devicePublisher = new SsdpDevicePublisher(IPAddress.IPv6Any.ToString());
var devicePublisher = new SsdpDevicePublisher("fe80::dc06:c198:7078:afdd");
var deviceLocator = new SsdpDeviceLocator("fe80::dc06:c198:7078:afdd");
Need strong-naming? Use the assembly strong naming toolkit.
No. Yeelight doesn't actually use SSDP, it uses a custom system based on SSDP but the two are not compatible. For (a little) more information, see Issue #56
Create an SsdpRootDevice instance and set the properties (device type, model, serial number, device id etc) on it to the values you want in the XML. Once done, call the ToDescriptionDocument method of that instance and it will generate the required XML and return it as a string.
You can also create a Upnp10DeviceValidator instance and pass your SsdpRootDevice instance to the GetValidationErrors method and it will tell you if you've missed a required property or set an invalid value.