WingMan

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 31  →  ?path2? @ 32
/trunk/WingMan/Discovery/Discovery.cs
@@ -0,0 +1,99 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Open.Nat;
 
namespace WingMan.Discovery
{
public class Discovery : IDisposable
{
public delegate void PortMapFailed(object sender, DiscoveryFailedEventArgs args);
 
public Discovery()
{
NatDiscoverer = new NatDiscoverer();
}
 
public Discovery(CancellationTokenSource cancellationTokenSource, TaskScheduler taskScheduler) : this()
{
CancellationTokenSource = cancellationTokenSource;
TaskScheduler = taskScheduler;
}
 
private static CancellationTokenSource CancellationTokenSource { get; set; }
private static NatDiscoverer NatDiscoverer { get; set; }
private static TaskScheduler TaskScheduler { get; set; }
 
private static CancellationTokenSource UPnPCancellationTokenSource { get; set; }
private static CancellationTokenSource PMPCancellationTokenSource { get; set; }
 
public void Dispose()
{
PMPCancellationTokenSource?.Dispose();
PMPCancellationTokenSource = null;
 
PMPCancellationTokenSource?.Dispose();
PMPCancellationTokenSource = null;
}
 
public event PortMapFailed OnPortMapFailed;
 
public async Task<bool> CreateMapping(DiscoveryType type, int port)
{
switch (type)
{
case DiscoveryType.UPnP:
return await CreateUPnPMapping(port);
case DiscoveryType.PMP:
return await CreatePMPPortMapping(port);
default:
throw new ArgumentException("Unknown disocvery type");
}
}
 
private async Task<bool> CreateUPnPMapping(int port)
{
try
{
UPnPCancellationTokenSource = new CancellationTokenSource();
var linkedCancellationTokenSource =
CancellationTokenSource.CreateLinkedTokenSource(UPnPCancellationTokenSource.Token,
CancellationTokenSource.Token);
var device = await NatDiscoverer.DiscoverDeviceAsync(PortMapper.Upnp, linkedCancellationTokenSource);
await device.CreatePortMapAsync(new Mapping(Protocol.Tcp, port, port, "WingMan Host"));
 
return true;
}
catch (Exception ex)
{
await Task.Delay(0, CancellationTokenSource.Token).ContinueWith(_ =>
OnPortMapFailed?.Invoke(this, new DiscoveryFailedEventArgs(DiscoveryType.UPnP, ex)),
CancellationTokenSource.Token, TaskContinuationOptions.None, TaskScheduler);
 
return false;
}
}
 
private async Task<bool> CreatePMPPortMapping(int port)
{
try
{
PMPCancellationTokenSource = new CancellationTokenSource();
var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(
PMPCancellationTokenSource.Token,
CancellationTokenSource.Token);
var device = await NatDiscoverer.DiscoverDeviceAsync(PortMapper.Pmp, linkedCancellationTokenSource);
await device.CreatePortMapAsync(new Mapping(Protocol.Tcp, port, port, "WingMan Host"));
return true;
}
catch (Exception ex)
{
await Task.Delay(0, CancellationTokenSource.Token).ContinueWith(_ =>
OnPortMapFailed?.Invoke(this, new DiscoveryFailedEventArgs(DiscoveryType.PMP, ex)),
CancellationTokenSource.Token, TaskContinuationOptions.None, TaskScheduler);
 
return false;
}
}
}
}