Built a small SSDP Client.
This commit is contained in:
parent
a79c8a5f20
commit
887d983594
94
Documentation/UPnP-XSD/device.xsd
Normal file
94
Documentation/UPnP-XSD/device.xsd
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<xs:schema
|
||||||
|
targetNamespace="urn:schemas-upnp-org:device-1-0"
|
||||||
|
xmlns:tns="urn:schemas-upnp-org:device-1-0"
|
||||||
|
xmlns="urn:schemas-upnp-org:device-1-0"
|
||||||
|
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns:dlna="urn:schemas-dlna-org:device-1-0"
|
||||||
|
attributeFormDefault="qualified" elementFormDefault="qualified">
|
||||||
|
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
XML Schema for UPnP device descriptions in real XSD format
|
||||||
|
(not like the XDR one from Microsoft)
|
||||||
|
Created by Michael Weinrich 2007
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:element name="root">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="specVersion" type="SpecVersionType" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="URLBase" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="device" type="DeviceType" minOccurs="1" maxOccurs="1" />
|
||||||
|
</xs:all>
|
||||||
|
<xs:anyAttribute/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
|
||||||
|
<xs:complexType name="SpecVersionType">
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="major" type="xs:int" minOccurs="1" />
|
||||||
|
<xs:element name="minor" type="xs:int" minOccurs="1"/>
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="DeviceType">
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="deviceType" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="friendlyName" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="manufacturer" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="manufacturerURL" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="modelDescription" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="modelName" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="modelNumber" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="modelURL" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="serialNumber" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="UDN" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="UPC" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="iconList" type="IconListType" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="serviceList" type="ServiceListType" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="deviceList" type="DeviceListType" minOccurs="0" maxOccurs="1" />
|
||||||
|
<xs:element name="presentationURL" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="IconListType">
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="icon" minOccurs="1" maxOccurs="unbounded">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="mimetype" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="width" type="xs:int" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="height" type="xs:int" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="depth" type="xs:int" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="url" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="ServiceListType">
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="service" minOccurs="1" maxOccurs="unbounded">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="serviceType" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="serviceId" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="SCPDURL" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="controlURL" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||||
|
<xs:element name="eventSubURL" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="DeviceListType">
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="device" type="DeviceType" minOccurs="1" maxOccurs="unbounded"/>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
|
</xs:schema>
|
||||||
@ -39,7 +39,13 @@ namespace skyscraper5
|
|||||||
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
|
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
|
||||||
private static void IntegrationTest()
|
private static void IntegrationTest()
|
||||||
{
|
{
|
||||||
//List<SsdpDevice> ssdpDevices = SsdpClient.GetSsdpDevices(1000).ToList();
|
List<SsdpDevice> 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 rtspClient = new RtspClient("172.20.20.121", 554);
|
||||||
rtspClient.AutoReconnect = true;
|
rtspClient.AutoReconnect = true;
|
||||||
RtspOptionsResponse options = rtspClient.GetOptions("/");
|
RtspOptionsResponse options = rtspClient.GetOptions("/");
|
||||||
|
|||||||
@ -44,6 +44,7 @@ namespace skyscraper8.SimpleServiceDiscoveryProtocol
|
|||||||
DateTime timeStarted = DateTime.Now;
|
DateTime timeStarted = DateTime.Now;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
bool yielded = false;
|
||||||
for (int i = 0; i < udpSockets.Length; i++)
|
for (int i = 0; i < udpSockets.Length; i++)
|
||||||
{
|
{
|
||||||
if (udpSockets[i] == null)
|
if (udpSockets[i] == null)
|
||||||
@ -57,12 +58,16 @@ namespace skyscraper8.SimpleServiceDiscoveryProtocol
|
|||||||
if (recvBytes > 0)
|
if (recvBytes > 0)
|
||||||
{
|
{
|
||||||
string s = Encoding.UTF8.GetString(buffer, 0, recvBytes);
|
string s = Encoding.UTF8.GetString(buffer, 0, recvBytes);
|
||||||
Console.WriteLine(s);
|
//Console.WriteLine(s);
|
||||||
yield return new SsdpDevice(s);
|
yield return new SsdpDevice(s);
|
||||||
|
yielded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (yielded)
|
||||||
|
continue;
|
||||||
|
|
||||||
Thread.Sleep(1);
|
Thread.Sleep(1);
|
||||||
if ((DateTime.Now - timeStarted).TotalMilliseconds >= timeout)
|
if ((DateTime.Now - timeStarted).TotalMilliseconds >= timeout)
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -1,17 +1,125 @@
|
|||||||
using System;
|
using log4net;
|
||||||
|
using skyscraper5.Skyscraper;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace skyscraper8.SimpleServiceDiscoveryProtocol
|
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)
|
public SsdpDevice(string notification)
|
||||||
{
|
{
|
||||||
StringReader sr = new StringReader(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; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is an URL to an XML file
|
||||||
|
/// </summary>
|
||||||
|
public string Location { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This just says what software is running on the device, not what it actually is.
|
||||||
|
/// </summary>
|
||||||
|
public string Server { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This can only be used to identify one specific device, not a device type.
|
||||||
|
/// </summary>
|
||||||
|
public string UniqueServiceName { get; set; }
|
||||||
|
|
||||||
|
public string SearchTarget { get; set; }
|
||||||
|
|
||||||
|
public string CacheControl { get; private set; }
|
||||||
|
|
||||||
|
public int HttpStatusCode { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user