Skip to content

Instantly share code, notes, and snippets.

@codebutler
Created May 30, 2010 03:28
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save codebutler/418752 to your computer and use it in GitHub Desktop.
Save codebutler/418752 to your computer and use it in GitHub Desktop.
//
// UPnP.cs: UPnP Device Discovery Test.
//
// Authors:
// Eric Butler <eric@extremeboredom.net>
//
// (C) 2006 FileFind.net (http://filefind.net)
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Timers;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace FileFind.UPnP
{
public class Test
{
public static void Main ()
{
new Test ();
}
UPnPDiscovery discovery;
Gtk.TreeStore store;
Gtk.TreeView tree;
public Test ()
{
Gtk.Application.Init ();
discovery = new UPnPDiscovery ();
Gtk.Window window = new Gtk.Window ("UPnP Discovery");
window.SetSizeRequest (500, 500);
store = new Gtk.TreeStore (typeof (string));
tree = new Gtk.TreeView ();
tree.HeadersVisible = false;
Gtk.TreeViewColumn column = tree.AppendColumn ("Text", new Gtk.CellRendererText (), "text", 0);
column.Expand = true;
tree.Model = store;
window.Add (tree);
window.ShowAll ();
discovery.DevicesChanged += delegate { Gtk.Application.Invoke ( delegate (object o, EventArgs args) { OnDevicesChanged (o, args); } ); };
discovery.Start ();
Gtk.Application.Run ();
}
private void OnDevicesChanged (object o, EventArgs args)
{
// Rebuild the tree
store.Clear ();
foreach (RootDevice rootDevice in discovery.RootDevices.Values) {
Gtk.TreeIter deviceIter = store.AppendValues (rootDevice.ToString() + " [" + rootDevice.UUID + "]");
PopulateDevice (rootDevice, deviceIter);
}
}
private void PopulateDevice (Device device, Gtk.TreeIter deviceIter)
{
Gtk.TreeIter iter;
if (device is RootDevice) {
RootDevice rootDevice = (RootDevice)device;
if (rootDevice.Devices.Count > 0) {
iter = store.AppendValues (deviceIter, "Embeded Devices");
foreach (Device embededDevice in rootDevice.Devices.Values) {
tree.ExpandAll ();
Gtk.TreeIter embededDeviceIter = store.AppendValues (iter, embededDevice.Type + " [" + embededDevice.UUID + "]");
PopulateDevice (embededDevice, embededDeviceIter);
}
}
}
if (device.Services.Count > 0) {
iter = store.AppendValues (deviceIter, "Services");
foreach (Service service in device.Services) {
tree.ExpandAll ();
store.AppendValues (iter, service.Type);
}
}
tree.ExpandAll ();
}
}
public class UPnPDiscovery
{
public event EventHandler DevicesChanged;
Dictionary <string, RootDevice> devices = new Dictionary <string, RootDevice> ();
public Dictionary <string, RootDevice> RootDevices {
get {
return devices;
}
}
IPEndPoint remoteEndPoint = new IPEndPoint (IPAddress.Parse("239.255.255.250"), 1900);
Socket socket;
UdpClient client;
Thread unicastThread;
Thread multicastThread;
System.Timers.Timer searchTimer;
public UPnPDiscovery ()
{
searchTimer = new System.Timers.Timer (30000);
socket = new Socket (AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
client = new UdpClient (1900);
client.JoinMulticastGroup (IPAddress.Parse ("239.255.255.250"));
}
public void Start ()
{
BroadcastSearch (null, null);
searchTimer.Elapsed += new ElapsedEventHandler (BroadcastSearch);
searchTimer.Start ();
unicastThread = new Thread (new ThreadStart (UnicastListener));
unicastThread.Start ();
multicastThread = new Thread (new ThreadStart (MulticastListener));
multicastThread.Start ();
}
public void Stop ()
{
searchTimer.Stop ();
unicastThread.Abort ();
multicastThread.Abort ();
}
private void BroadcastSearch (object o, System.Timers.ElapsedEventArgs args)
{
StringBuilder builder = new StringBuilder ();
builder.Append ("M-SEARCH * HTTP/1.1\r\n");
builder.Append ("Host:239.255.255.250:1900\r\n");
builder.Append ("Man:\"ssdp:discover\"\r\n");
//builder.Append ("ST:upnp:rootdevice\r\n");
builder.Append ("ST:ssdp:all\r\n");
builder.Append ("MX:3\r\n");
builder.Append ("\r\n");
builder.Append ("\r\n");
byte[] data = Encoding.ASCII.GetBytes (builder.ToString ());
lock (socket)
socket.SendTo (data, remoteEndPoint);
}
private void MulticastListener ()
{
while (true) {
IPEndPoint ep = null;
byte[] data = client.Receive (ref ep);
//Console.WriteLine ("Multicast Received: " + data.Length);
string message = Encoding.ASCII.GetString (data, 0, data.Length);
ProcessMessage (message);
}
}
private void UnicastListener ()
{
while (true) {
//Console.WriteLine ("Receiving...");
byte[] data = new byte [8192];
EndPoint ep = (EndPoint)remoteEndPoint;
int bytesReceived = 0;
lock (socket)
bytesReceived = socket.ReceiveFrom (data, ref ep);
//Console.WriteLine ("Received: " + data.Length);
string message = Encoding.ASCII.GetString (data, 0, bytesReceived);
ProcessMessage (message);
}
}
private void ProcessMessage (string message)
{
Dictionary <string, string> headers = new Dictionary <string, string> ();
// Fuck this
message = message.Replace ("\r", "");
string[] lines = message.Split (new char[] { '\n' });
if (lines[0].StartsWith ("HTTP/") | lines[0].StartsWith ("NOTIFY ")) {
for (int x = 1; x < lines.Length; x++) {
string line = lines[x];
if (line.Trim() != "") {
string key = line.Substring (0, line.IndexOf (":")).Trim().ToLower();
string val = line.Substring (line.IndexOf (":") +1).Trim();
//Console.WriteLine (key + "==" + val);
headers.Add (key, val);
}
}
} else if (lines[0].StartsWith ("NOTIFY ")) {
//TODO: Do anything here?
Console.WriteLine ("GOT NOTIFICATION !!!");
Console.WriteLine (message);
return;
} else if (lines[0].StartsWith ("M-SEARCH ")) {
// do anything here?
return;
} else {
throw new Exception ("WTF!?!?!?! " + lines[0]);
}
string usn = headers ["usn"].ToString ();
string[] usnItems = usn.Split (':');
string uuid = usnItems [1];
Console.WriteLine ("USN ITEMS: " + usnItems.Length);
if (usnItems.Length == 5) {
if (headers["nts"] == "ssdp:alive") {
if (usnItems[usnItems.Length-1] == "rootdevice") {
RootDevice device = new RootDevice (headers ["location"], uuid);
if (devices.ContainsKey (device.Location))
devices.Remove (device.Location);
devices.Add (device.Location, device);
if (DevicesChanged != null)
DevicesChanged (this, null);
} else {
throw new Exception ("WTF IS THIS THING?!");
}
} else if (headers["nts"] == "ssdp:byebye") {
Console.WriteLine ("DELETE SOMETHING!!!");
} else {
throw new Exception ("WAT !! " + headers["nts"]);
}
} else if (usnItems.Length == 8) {
if (usnItems[usnItems.Length-3] == "service") {
string serviceType = usnItems[usnItems.Length-2];
Device device = devices [headers["location"]];
if ((device as RootDevice).Devices.ContainsKey (uuid) == true)
device = (device as RootDevice).Devices [uuid];
device.Services.Add (new Service (uuid, serviceType));
if (DevicesChanged != null)
DevicesChanged (this, null);
} else if (usnItems[usnItems.Length-3] == "device") {
string deviceType = usnItems[usnItems.Length-2];
RootDevice device = devices [headers["location"]];
if (device.UUID == uuid) {
device.Type = deviceType;
} else {
if (device.Devices.ContainsKey (uuid) == false)
device.Devices.Add (uuid, new Device (uuid, deviceType));
else
device.Devices [uuid].Type = deviceType;
}
if (DevicesChanged != null)
DevicesChanged (this, null);
}
} else if (usnItems.Length == 2) {
RootDevice rootDevice = devices [headers["location"]];
if (rootDevice.UUID != uuid) {
if (rootDevice.Devices.ContainsKey (uuid) == false) {
rootDevice.Devices.Add (uuid, new Device (uuid, "UNKNOWN"));
}
}
} else {
throw new Exception ("Unknown length: " + usnItems.Length + " " + usn);
}
}
}
public class RootDevice : Device
{
string location;
public Dictionary <string, Device> Devices = new Dictionary <string, Device> ();
public string Location {
get {
return location;
}
}
public RootDevice (string location, string uuid) : base (uuid, "rootdevice")
{
this.location = location;
}
public string ToString ()
{
if (Type == "")
return location;
else
return Type;
}
}
public class Device
{
public List <Service> Services = new List <Service> ();
string uuid;
string deviceType;
public string Type {
get {
return deviceType;
}
set {
deviceType = value;
}
}
public string UUID {
get {
return uuid;
}
}
public Device (string uuid, string deviceType)
{
this.uuid = uuid;
this.deviceType = deviceType;
}
}
public class Service
{
string uuid;
string type;
public string Type {
get {
return type;
}
}
public string UUID {
get {
return uuid;
}
}
public Service (string uuid, string type)
{
this.uuid = uuid;
this.type = type;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment