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.
Install / Use
/learn @Yortw/RSSDPREADME
(Really) Simple Service Discovery Protocol For .Net
What is RSSDP ?
RSSDP is a 100% .Net implementation of the Simple Service Discovery (SSDP) protocol that is part of the Universal Plug and Play (UPnP) standard. SSDP allows you to discover devices and services on a (local) network.
RSSDP is designed primarily to publish and discover custom or 'basic' devices, and as such does not implement the full UPnP device architecture. If you are looking to build a device for which a full UPnP device schema exists, this is not the library for you (sorry! though I guess you can fork and extend if you like). If you are looking for a way to discover a custom service (such as a proprietary REST or SOAP service) from a device, RSSDP might be the solution for you.
Supported Platforms
Currently;
- .Net Desktop Framework 4.8/4.81
- .NET 6.0, 8.0+
- .NET 8.0-android
- .Net Standard 2.0 for any other compatible framework
Note: iOS should be supported by one of these targets (most likely Net 8.0) but I currently lack the hardware to test on.
Build Status
How do I use RSSDP?
We got your samples right here
There is a sample console applicaton included in the repository. If you don't want to "read the source, Luke", then here's some tips and examples to get you started. You can also check out our FAQ and our API Reference documentation.
One common gotcha to look out for: SSDP root devices must publish an xml document describing themselves and any embedded devices, and this document must be published on a url that can be accessed via an HTTP GET. RSSDP will return devices in search results and notifications regardless of whether this document is actually accessible (it is up to you to retrieve the document if you care, and handle any exceptions that occur doing so). However, many other SSDP device locators (such as Intel's Device Spy application) will not report devices if the url cannot be accessed, the document is invalid, or data in the document (such as the UUID) does not match the associated notification or search request. For this reason, if you are using another tool to locate devices published with RSSDP, ensure you are publishing a correct document on the url specified in the Location property of your root device, or else the device may not be found.
Install the Nuget package like this;
PM> Install-Package Rssdp
Or reference the Rssdp.Portable.dll assembly AND the assembly that matches your app's platform, i.e Rssdp.NetFX40.dll for .Net 4+.
Publishing a Device
Only three steps to do this. Create a device definition, create a publisher, add the device to the publisher;
using Rssdp;
// Declare \_Publisher as a field somewhere, so it doesn't get GCed after the method finishes.
private SsdpDevicePublisher _Publisher;
// Call this method from somewhere to actually do the publish.
public void PublishDevice()
{
// As this is a sample, we are only setting the minimum required properties.
var deviceDefinition = new SsdpRootDevice()
{
CacheLifetime = TimeSpan.FromMinutes(30), //How long SSDP clients can cache this info.
Location = new Uri("http://mydevice/descriptiondocument.xml"), // Must point to the URL that serves your devices UPnP description document.
DeviceTypeNamespace = "my-namespace",
DeviceType = "MyCustomDevice",
FriendlyName = "Custom Device 1",
Manufacturer = "Me",
ModelName = "MyCustomDevice",
Uuid = GetPersistentUuid() // This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.
};
}
//Note, you can use deviceDefinition.ToDescriptionDocumentText() to retrieve the data to
//return from the Location end point, you just need to get that data to your service
//implementation somehow. Depends on how you've implemented your service.
_Publisher = new SsdpDevicePublisher();
_Publisher.AddDevice(deviceDefinition);
Discovering Devices
Basically, just create an SsdpDeviceLocator object and call the search method. By default the method will search for all devices, but you can specify a search target string in the following formats;
- ssdp:all
- upnp:rootdevice
- uuid:<device's unique identifier>
- urn:<fully qualified device type>
The format of a fully qualified device type is; urn:<device namespace>:device:<device type>:<device version>
i.e
- uuid:CAA42739-8F87-4463-B747-6F6DDB301A06
- urn:schemas-upnp-org:device:Basic:1
Simple Search
Simple search is easy but requires you to wait for the full search to finish before getting any results back. This is asynchronous and returns a task which you can choose to wait on (or not), but you must wait for the task to complete before accessing the results.
using Rssdp;
//Call this method from somewhere to begin the search.
public async void SearchForDevices()
{
// This code goes in a method somewhere.
using (var deviceLocator = new SsdpDeviceLocator())
{
var foundDevices = await deviceLocator.SearchAsync(); // Can pass search arguments here (device type, uuid). No arguments means all devices.
foreach (var foundDevice in foundDevices)
{
// Device data returned only contains basic device details and location ]
// of full device description.
Console.WriteLine("Found " + foundDevice.Usn + " at " + foundDevice.DescriptionLocation.ToString());
// Can retrieve the full device description easily though.
var fullDevice = await foundDevice.GetDeviceInfo();
Console.WriteLine(fullDevice.FriendlyName);
Console.WriteLine();
}
}
}
Event Driven Search & Discovery via Notifications
Event driven search is the same as 'simple' search but instead of looking at the task return value, you subscribe to the DeviceAvailable and DeviceUnavailable events to handle results. These events are raised each time a search response is received, as well as whenever a status notification is broadcast from a device. By responding to the events you can process results sooner than waiting for all results to come back from a completed task. You can also monitor for new devices arriving on the network or existing devices disappearing without having to repeatedly call search. Notifications can also be used in conjunction with simple search, just call the StartListeningForNotifications method before searching and handle the events.
using Rssdp;
// Define _DeviceLocator as a field so it doesn't get GCed after the method ends, and it can
// continue to listen for notifications until it is explicitly stopped
// (with a call to _DeviceLocator.StopListeningForNotifications();)
private SsdpDeviceLocator _DeviceLocator;
// Call this method from somewhere in your code to start the search.
public void BeginSearch()
{
_DeviceLocator = new SsdpDeviceLocator();
// (Optional) Set the filter so we only see notifications for devices we care about
// (can be any search target value i.e device type, uuid value etc - any value that appears in the
// DiscoverdSsdpDevice.NotificationType property or that is used with the searchTarget parameter of the Search method).
_DeviceLocator.NotificationFilter = "upnp:rootdevice";
// Connect our event handler so we process devices as they are found
_DeviceLocator.DeviceAvailable += deviceLocator_DeviceAvailable;
// Enable listening for notifications (optional)
_DeviceLocator.StartListeningForNotifications();
// Perform a search so we don't have to wait for devices to broadcast notifications
// again to get any results right away (notifications are broadcast periodically).
_DeviceLocator.SearchAsync();
Console.ReadLine();
}
// Process each found device in the event handler
async static void deviceLocator_DeviceAvailable(object sender, DeviceAvailableEventArgs e)
{
//Device data returned only contains basic device details and location of full device description.
Console.WriteLine("Found " + e.DiscoveredDevice.Usn + " at " + e.DiscoveredDevice.DescriptionLocation.ToString());
//Can retrieve the full device description easily though.
var fullDevice = await e.DiscoveredDevice.GetDeviceInfo();
Console.WriteLine(fullDevice.FriendlyName);
Console.WriteLine();
}
IPV6 support
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");
Android Permissions
The RSSDP package tests solution in this repo contains a working (device search) Android sample which can be used as a reference. You'll require the following permissions in your AndroidManifest.xml file;
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
iOS Permissions
iOS requires apps to declare the types of network services they intend to use in their Info.plist file. I don't have the hardware to test this so I can't provide a guaranteed working example, but the MAUI project in the Rssdp package tests solution contains an iOS project which may be of some
