diff --git a/Documentation/UPnP-XSD/device.xsd b/Documentation/UPnP-XSD/device.xsd new file mode 100644 index 0000000..e3b8b85 --- /dev/null +++ b/Documentation/UPnP-XSD/device.xsd @@ -0,0 +1,94 @@ + + + + + + XML Schema for UPnP device descriptions in real XSD format + (not like the XDR one from Microsoft) + Created by Michael Weinrich 2007 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/skyscraper8/Program.cs b/skyscraper8/Program.cs index cccc75f..9e6acfa 100644 --- a/skyscraper8/Program.cs +++ b/skyscraper8/Program.cs @@ -39,7 +39,13 @@ namespace skyscraper5 private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); private static void IntegrationTest() { - //List ssdpDevices = SsdpClient.GetSsdpDevices(1000).ToList(); + List ssdpDevices = SsdpClient.GetSsdpDevices(1000).ToList(); + foreach (SsdpDevice ssdpDevice in ssdpDevices) + { + Console.WriteLine("SSDP device: {0}", ssdpDevice.Server); + } + + Console.WriteLine("yeet!"); /*RtspClient rtspClient = new RtspClient("172.20.20.121", 554); rtspClient.AutoReconnect = true; RtspOptionsResponse options = rtspClient.GetOptions("/"); diff --git a/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs b/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs index 9d75bb6..8933343 100644 --- a/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs +++ b/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs @@ -44,6 +44,7 @@ namespace skyscraper8.SimpleServiceDiscoveryProtocol DateTime timeStarted = DateTime.Now; while (true) { + bool yielded = false; for (int i = 0; i < udpSockets.Length; i++) { if (udpSockets[i] == null) @@ -57,12 +58,16 @@ namespace skyscraper8.SimpleServiceDiscoveryProtocol if (recvBytes > 0) { string s = Encoding.UTF8.GetString(buffer, 0, recvBytes); - Console.WriteLine(s); + //Console.WriteLine(s); yield return new SsdpDevice(s); + yielded = true; } } } + if (yielded) + continue; + Thread.Sleep(1); if ((DateTime.Now - timeStarted).TotalMilliseconds >= timeout) break; diff --git a/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpDevice.cs b/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpDevice.cs index 6adaaa7..4358fff 100644 --- a/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpDevice.cs +++ b/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpDevice.cs @@ -1,17 +1,125 @@ -using System; +using log4net; +using skyscraper5.Skyscraper; +using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Text; using System.Threading.Tasks; namespace skyscraper8.SimpleServiceDiscoveryProtocol { - internal class SsdpDevice + internal class SsdpDevice : Validatable { + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + public SsdpDevice(string notification) { StringReader sr = new StringReader(notification); - throw new NotImplementedException(notification); + string httpHeaderLine = sr.ReadLine(); + int indexOf = httpHeaderLine.IndexOf(' '); + string protocol = httpHeaderLine.Substring(0, indexOf); + httpHeaderLine = httpHeaderLine.Substring(indexOf + 1); + if (!protocol.StartsWith("HTTP")) + { + Valid = false; + return; + } + + HttpStatusCode = int.Parse(httpHeaderLine.Substring(0, 3)); + httpHeaderLine = httpHeaderLine.Substring(4); + + string line = httpHeaderLine; + while (!string.IsNullOrEmpty(line = sr.ReadLine())) + { + int seperator = line.IndexOf(": "); + if (seperator == -1) + continue; + string key = line.Substring(0, seperator); + string value = line.Substring(seperator + 2); + key = key.ToLowerInvariant(); + switch (key) + { + case "cache-control": + this.CacheControl = value; + break; + case "st": + this.SearchTarget = value; + break; + case "usn": + this.UniqueServiceName = value; + break; + case "server": + Server = value; + break; + case "location": + Location = value; + break; + case "opt": + Options = value; + break; + case "01-nls": + //Same as BOOT ID + break; + case "bootid.upnp.org": + BootId = value; + break; + case "configid.upnp.org": + ConfigId = value; + break; + case "deviceid.ses.com": + SatIpDeviceId = value; + break; + case "date": + Date = value; + break; + case "x-user-agent": + UserAgent = value; + break; + case "content-length": + //Irrelevant. Always 0, because these thingies dont contain any http payload. + break; + default: + logger.WarnFormat("Don't know how to format: {0}", line); + break; + } + } + + Valid = true; } + + public string UserAgent { get; set; } + + public string Date { get; set; } + + public string SatIpDeviceId { get; set; } + + public string ConfigId { get; set; } + + public string BootId { get; set; } + + + public string Options { get; set; } + + /// + /// This is an URL to an XML file + /// + public string Location { get; set; } + + /// + /// This just says what software is running on the device, not what it actually is. + /// + public string Server { get; set; } + + /// + /// This can only be used to identify one specific device, not a device type. + /// + public string UniqueServiceName { get; set; } + + public string SearchTarget { get; set; } + + public string CacheControl { get; private set; } + + public int HttpStatusCode { get; private set; } } }