{"id":24557627,"url":"https://github.com/yortw/rssdp","last_synced_at":"2026-01-07T06:25:59.285Z","repository":{"id":25550004,"uuid":"28983015","full_name":"Yortw/RSSDP","owner":"Yortw","description":"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.","archived":false,"fork":false,"pushed_at":"2023-12-11T14:06:37.000Z","size":15048,"stargazers_count":290,"open_issues_count":25,"forks_count":68,"subscribers_count":26,"default_branch":"master","last_synced_at":"2025-05-16T06:03:32.824Z","etag":null,"topics":["c-sharp","discovering-devices","sdp","service-discovery","service-discovery-protocol","upnp"],"latest_commit_sha":null,"homepage":"http://yortw.github.io/RSSDP/","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Yortw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-01-08T19:49:09.000Z","updated_at":"2025-02-26T11:41:45.000Z","dependencies_parsed_at":"2024-11-11T22:42:14.551Z","dependency_job_id":null,"html_url":"https://github.com/Yortw/RSSDP","commit_stats":{"total_commits":150,"total_committers":15,"mean_commits":10.0,"dds":0.5533333333333333,"last_synced_commit":"2f9039eaa90fd7794b35a5744251130f79632c45"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yortw%2FRSSDP","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yortw%2FRSSDP/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yortw%2FRSSDP/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yortw%2FRSSDP/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Yortw","download_url":"https://codeload.github.com/Yortw/RSSDP/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254478186,"owners_count":22077675,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-sharp","discovering-devices","sdp","service-discovery","service-discovery-protocol","upnp"],"created_at":"2025-01-23T05:18:26.590Z","updated_at":"2026-01-07T06:25:59.279Z","avatar_url":"https://github.com/Yortw.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿# (Really) Simple Service Discovery Protocol For .Net\n\n## What is RSSDP ?\nRSSDP 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\nto discover devices and services on a (local) network.\n\nRSSDP 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 \nlooking 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).\nIf 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.\n\n[![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/Yortw/RSSDP/blob/master/LICENSE) \n\n## Supported Platforms\nCurrently;\n\n* .Net Desktop Framework 4.8/4.81\n* .NET 6.0, 8.0+\n* .NET 8.0-android\n* .Net Standard 2.0 for any other compatible framework\n\nNote: iOS should be supported by one of these targets (most likely Net 8.0) but I currently lack the hardware to test on.\n\n## Build Status\n ![NuGet Publish](https://github.com/Yortw/RSSDP/actions/workflows/nuget-publish.yml/badge.svg) ![PR Gate](https://github.com/Yortw/RSSDP/actions/workflows/pr-gate.yml/badge.svg?branch=main)\n\n## How do I use RSSDP?\n*We got your samples right here*\n\nThere 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](https://github.com/Yortw/RSSDP/wiki/Frequently-Asked-Questions) and our [API Reference documentation](http://yortw.github.io/RSSDP/api/Rssdp.html).\n\n**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.\nRSSDP 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).\nHowever, 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 \nmatch 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\nproperty of your root device, or else the device may not be found. \n\nInstall the Nuget package like this;\n\n```powershell\n    PM\u003e Install-Package Rssdp\n```\n\n[![NuGet Badge](https://buildstats.info/nuget/RSSDP)](https://www.nuget.org/packages/RSSDP/)\n\nOr reference the Rssdp.Portable.dll assembly AND the assembly that matches your app's platform, i.e Rssdp.NetFX40.dll for .Net 4+.\n\n### Publishing a Device\nOnly three steps to do this. Create a device definition, create a publisher, add the device to the publisher;\n\n```C#\n\nusing Rssdp;\n// Declare \\_Publisher as a field somewhere, so it doesn't get GCed after the method finishes.\nprivate SsdpDevicePublisher _Publisher;\n\n// Call this method from somewhere to actually do the publish.\npublic void PublishDevice()\n{\n    // As this is a sample, we are only setting the minimum required properties.\n    var deviceDefinition = new SsdpRootDevice()\n    {\n    \tCacheLifetime = TimeSpan.FromMinutes(30), //How long SSDP clients can cache this info.\n    \tLocation = new Uri(\"http://mydevice/descriptiondocument.xml\"), // Must point to the URL that serves your devices UPnP description document. \n    \tDeviceTypeNamespace = \"my-namespace\",\n    \tDeviceType = \"MyCustomDevice\",\n    \tFriendlyName = \"Custom Device 1\",\n    \tManufacturer = \"Me\",\n    \tModelName = \"MyCustomDevice\",\n    \tUuid = GetPersistentUuid() // This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.\n    };\n}\n\n//Note, you can use deviceDefinition.ToDescriptionDocumentText() to retrieve the data to \n//return from the Location end point, you just need to get that data to your service\n//implementation somehow. Depends on how you've implemented your service.\n\n_Publisher = new SsdpDevicePublisher();\n_Publisher.AddDevice(deviceDefinition);    \n```\n\n### Discovering Devices\nBasically, 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;\n\n* ssdp:all\n* upnp:rootdevice\n* uuid:\u0026lt;device's unique identifier\u0026gt;\n* urn:\u0026lt;fully qualified device type\u0026gt;\n\nThe format of a fully qualified device type is;\nurn:\u0026lt;device namespace\u0026gt;:device:\u0026lt;device type\u0026gt;:\u0026lt;device version\u0026gt;\n\ni.e\n\n* uuid:CAA42739-8F87-4463-B747-6F6DDB301A06\n* urn:schemas-upnp-org:device:Basic:1\n\n#### Simple Search\nSimple search is easy but requires you to wait for the full search to finish before getting any results back. \nThis 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.\n\n```C#\nusing Rssdp;\n\n//Call this method from somewhere to begin the search.\npublic async void SearchForDevices()\n{\n    // This code goes in a method somewhere.\n    using (var deviceLocator = new SsdpDeviceLocator())\n    {\n        var foundDevices = await deviceLocator.SearchAsync(); // Can pass search arguments here (device type, uuid). No arguments means all devices.\n\n        foreach (var foundDevice in foundDevices)\n        {\n        \t// Device data returned only contains basic device details and location ]\n        \t// of full device description.\n        \tConsole.WriteLine(\"Found \" + foundDevice.Usn + \" at \" + foundDevice.DescriptionLocation.ToString());\n            \n        \t// Can retrieve the full device description easily though.\n        \tvar fullDevice = await foundDevice.GetDeviceInfo();\n        \tConsole.WriteLine(fullDevice.FriendlyName);\n        \tConsole.WriteLine();\n        }\n    }\n}\n```\n\n#### Event Driven Search \u0026 Discovery via Notifications\nEvent 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.\nThese 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 \ncan 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 \nwithout 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.\n\n```C#\nusing Rssdp;\n// Define _DeviceLocator as a field so it doesn't get GCed after the method ends, and it can\n// continue to listen for notifications until it is explicitly stopped \n// (with a call to _DeviceLocator.StopListeningForNotifications();)\nprivate SsdpDeviceLocator _DeviceLocator;\n\n// Call this method from somewhere in your code to start the search.\npublic void BeginSearch()\n{\n    _DeviceLocator = new SsdpDeviceLocator();\n\n    // (Optional) Set the filter so we only see notifications for devices we care about \n    // (can be any search target value i.e device type, uuid value etc - any value that appears in the \n    // DiscoverdSsdpDevice.NotificationType property or that is used with the searchTarget parameter of the Search method).\n    _DeviceLocator.NotificationFilter = \"upnp:rootdevice\";\n\n    // Connect our event handler so we process devices as they are found\n    _DeviceLocator.DeviceAvailable += deviceLocator_DeviceAvailable;\n\n    // Enable listening for notifications (optional)\n    _DeviceLocator.StartListeningForNotifications();\n\n    // Perform a search so we don't have to wait for devices to broadcast notifications \n    // again to get any results right away (notifications are broadcast periodically).\n    _DeviceLocator.SearchAsync();\n\n    Console.ReadLine();\n}\n\n// Process each found device in the event handler\nasync static void deviceLocator_DeviceAvailable(object sender, DeviceAvailableEventArgs e)\n{\n\t//Device data returned only contains basic device details and location of full device description.\n\tConsole.WriteLine(\"Found \" + e.DiscoveredDevice.Usn + \" at \" + e.DiscoveredDevice.DescriptionLocation.ToString());\n    \n\t//Can retrieve the full device description easily though.\n\tvar fullDevice = await e.DiscoveredDevice.GetDeviceInfo();\n\tConsole.WriteLine(fullDevice.FriendlyName);\n\tConsole.WriteLine();\n}\n```\n\n#### IPV6 support\n\n```C#\nvar devicePublisher = new SsdpDevicePublisher(IPAddress.IPv6Any.ToString());\nvar devicePublisher = new SsdpDevicePublisher(\"fe80::dc06:c198:7078:afdd\");\nvar deviceLocator = new SsdpDeviceLocator(\"fe80::dc06:c198:7078:afdd\");\n```\n\n### Android Permissions\nThe RSSDP package tests solution in this repo contains a working (device search) Android sample which can be used as a reference.\nYou'll require the following permissions in your AndroidManifest.xml file;\n```xml\n\u003cuses-permission android:name=\"android.permission.INTERNET\" /\u003e\n\u003cuses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" /\u003e\n\u003cuses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" /\u003e\n\u003cuses-permission android:name=\"android.permission.CHANGE_WIFI_MULTICAST_STATE\" /\u003e\n```\n\n#### iOS Permissions\niOS 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, \nbut the MAUI project in the Rssdp package tests solution contains an iOS project which may be of some help.\n\niOS requires explicit privacy text and an entitlement to use UDP multicast (needed by SSDP on 239.255.255.250:1900). Configure the following:\n\n- Add `NSLocalNetworkUsageDescription` to `Info.plist` with a human-readable reason. iOS will prompt the user to allow local network access.\n- Add the Multicast Networking entitlement (`com.apple.developer.networking.multicast`) in your app entitlements and set it to true.\n\nExample `Info.plist` entries:\n\n```xml\n\u003ckey\u003eNSLocalNetworkUsageDescription\u003c/key\u003e\n\u003cstring\u003eThis app discovers local devices using SSDP multicast.\u003c/string\u003e\n```\n\nExample `Entitlements.plist` entries:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\n\u003cplist version=\"1.0\"\u003e\n  \u003cdict\u003e\n    \u003ckey\u003ecom.apple.developer.networking.multicast\u003c/key\u003e\n    \u003ctrue/\u003e\n  \u003c/dict\u003e\n\u003c/plist\u003e\n```\n\nNotes:\n\n- Test on a physical device; the iOS simulator does not fully support multicast networking.\n- Ensure the device is on a Wi‑Fi network that permits multicast/broadcast. Some routers/APs block multicast by default.\n- For IPv6 networks, create `SsdpDeviceLocator` or `SsdpDevicePublisher` with an IPv6 address if needed (see IPv6 support section above).\n\n#### Migrating from older versions of RSSDP\nV5 introduces some breaking changes. These should be pretty minor and mostly revolve around improving nullability support. You'll find some classes no longer have parameterless constructors, and some properties are now read-only.\nIf you're just searching for devices you probably won't notice. If you're publishing devices you'll likely notice *SsdpDeviceProperty** now requires the Namespace and Name properties to be passed via contructor, i.e\n\n```C#\nnew Rssdp.SsdpDeviceProperty() { Namespace = \"my-system\", Name = \"TenantIdentifier\", Value = \"mytenant\" };\n```\n\nbecomes \n\n```C#\nnew Rssdp.SsdpDeviceProperty(\"my-system\", \"TenantIdentifier\") { Value = \"mytenant\" };\n```\n\nThe following classes have a similar breaking change but are typically instantiated internally, so most clients won't be affected;\n\n* UdpEndpoint\n* DiscoveredSsdpDevice\n\n## Why RSSDP?\n*Aren't there already lots of SSDP implementations?*\n\nI needed to find a custom/proprietary service on local networks from a mobile device. I decided this had been done before and I shouldn't re-invent the wheel so I started looking for \nexisting, standard protocols that did this. I decided Zeroconf and SSDP seemed like the best two, and Zeroconf looked like the more efficient, less overhead option. Unfortunately I also need a solution where\n\n* I could publish a device. Many other libraries only focus on discovery.\n* the library supported a number of .Net platforms, including (initially) some that were already old or niche.\n* the API was consistent across platforms so I can write as little code with as little conditional compilation as possible (especially in Xamarin Forms/now MAUI projects).\n* the library wasn't massive and didn't have huge numbers of dependencies, I want to keep my deployment footprint as small as possible.\n* the library guided me (at least a little) towards publishing devices correctly, i.e correct device types, not leaving out required fields etc.\n\nSadly, I couldn't find a .Net implementation that met the criteria (I found some Node.Js and implementations in other languages that might have worked, but not in my environment/with my tools). Maybe I didn't look hard enough \nbut that's where I ended up. Having failed on Zeroconf I went looking for SSDP implementations that met the same goals, and had exactly the same problem. I then looked at implementing each protocol and while Zeroconf looked \nbetter overall, it *seemed* less well documented and harder to implement. At the point where I decided this wheel needed reinventing** I chose SSDP.\n\n ** Have you ever thought about how many different, useful, kinds of wheel there are in the world? Train wheels won't work on a bicycle, and bicycle wheels won't work on a car etc. Often people who say don't re-invent the wheel \nhaven't really considered how many variations of a wheel might be needed.\n\n## References\nReference materials used while writing this library, or that may be useful to people working with RSSDP who are not familiar with SSDP/UPnP device types and protocols.\n\n* [SSDP Draft 1.03 Specification](http://tools.ietf.org/html/draft-cai-ssdp-v1-03 \"SSDP Draft Spec 1.03\")\n* [UPnP 1.0 Specification](http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.0-20080424.pdf \"UPnP 1.0 Spec\")\n* [UPnP 1.1 Specification](http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf \"UPnP 1.1 Spec\")\n* [HTTP 1.1 Specification](http://tools.ietf.org/html/rfc2616 \"HTTP 1.1 Spec\")\n\n* [UPnP Device Types and Descriptions](http://upnp.org/index.php/sdcps-and-certification/standards/sdcps/ \"UPnP Device Types\")\n* [UPnP Developer Tools](http://opentools.homeip.net/dev-tools-for-upnp)\n\n## Contributing\nWe'd love your assistance! Please see the [CONTRIBUTING.md](https://github.com/Yortw/RSSDP/blob/master/CONTRIBUTING.md) file for information on how to contribute.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyortw%2Frssdp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyortw%2Frssdp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyortw%2Frssdp/lists"}