/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; |
} |
} |
} |
} |
/trunk/WingMan/Properties/Strings.Designer.cs |
@@ -151,6 +151,16 @@ |
} |
|
/// <summary> |
/// Looks up a localized string similar to Failed creating automatic port mapping, please ensure that the port is routed through the firewall properly. |
/// </summary> |
internal static string Failed_creating_automatic_port_mapping_please_make_sure_the_port_is_routed_properly { |
get { |
return ResourceManager.GetString("Failed_creating_automatic_port_mapping_please_make_sure_the_port_is_routed_proper" + |
"ly", resourceCulture); |
} |
} |
|
/// <summary> |
/// Looks up a localized string similar to Failed loading autocomplete source. |
/// </summary> |
internal static string Failed_loading_autocomplete_source { |
@@ -241,6 +251,24 @@ |
} |
|
/// <summary> |
/// Looks up a localized string similar to Failed to create PMP port mapping. |
/// </summary> |
internal static string Failed_to_create_PMP_port_mapping { |
get { |
return ResourceManager.GetString("Failed_to_create_PMP_port_mapping", resourceCulture); |
} |
} |
|
/// <summary> |
/// Looks up a localized string similar to Failed to create UPnp port mapping. |
/// </summary> |
internal static string Failed_to_create_UPnP_port_mapping { |
get { |
return ResourceManager.GetString("Failed_to_create_UPnP_port_mapping", resourceCulture); |
} |
} |
|
/// <summary> |
/// Looks up a localized string similar to Lobby message. |
/// </summary> |
internal static string Lobby_message { |
/trunk/WingMan/Properties/Strings.resx |
@@ -147,6 +147,9 @@ |
<data name="Executing_binding_from_remote_client" xml:space="preserve"> |
<value>Executing binding from remote client</value> |
</data> |
<data name="Failed_creating_automatic_port_mapping_please_make_sure_the_port_is_routed_properly" xml:space="preserve"> |
<value>Failed creating automatic port mapping, please ensure that the port is routed through the firewall properly</value> |
</data> |
<data name="Failed_loading_autocomplete_source" xml:space="preserve"> |
<value>Failed loading autocomplete source</value> |
</data> |
@@ -177,6 +180,12 @@ |
<data name="Failed_to_authenticate_with_server" xml:space="preserve"> |
<value>Failed to authenticate with server</value> |
</data> |
<data name="Failed_to_create_PMP_port_mapping" xml:space="preserve"> |
<value>Failed to create PMP port mapping</value> |
</data> |
<data name="Failed_to_create_UPnP_port_mapping" xml:space="preserve"> |
<value>Failed to create UPnp port mapping</value> |
</data> |
<data name="Lobby_message" xml:space="preserve"> |
<value>Lobby message</value> |
</data> |
/trunk/WingMan/WingManForm.cs |
@@ -15,6 +15,7 @@ |
using WingMan.AutoCompletion; |
using WingMan.Bindings; |
using WingMan.Communication; |
using WingMan.Discovery; |
using WingMan.Lobby; |
using WingMan.Properties; |
using WingMan.Utilities; |
@@ -30,6 +31,10 @@ |
FormTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); |
FormCancellationTokenSource = new CancellationTokenSource(); |
|
// Set up discovery. |
Discovery = new Discovery.Discovery(FormCancellationTokenSource, FormTaskScheduler); |
Discovery.OnPortMapFailed += OnDiscoveryPortMapFailed; |
|
// Set up autocompletion. |
AutoCompletion = new AutoCompletion.AutoCompletion(FormTaskScheduler, FormCancellationTokenSource.Token); |
AutoCompletion.OnSaveFailed += AutoCompletionOnSaveFailed; |
@@ -96,6 +101,7 @@ |
KeySimulator.OnMouseKeyBindingExecuting += OnMouseKeyBindingExecuting; |
} |
|
private static Discovery.Discovery Discovery { get; set; } |
private static AutoCompletion.AutoCompletion AutoCompletion { get; set; } |
private static CancellationTokenSource FormCancellationTokenSource { get; set; } |
|
@@ -125,6 +131,21 @@ |
|
public KeySimulator KeySimulator { get; set; } |
|
public void OnDiscoveryPortMapFailed(object sender, DiscoveryFailedEventArgs args) |
{ |
switch (args.Type) |
{ |
case DiscoveryType.UPnP: |
ActivityTextBox.AppendText( |
$"{Strings.Failed_to_create_UPnP_port_mapping}{Environment.NewLine}"); |
break; |
case DiscoveryType.PMP: |
ActivityTextBox.AppendText( |
$"{Strings.Failed_to_create_PMP_port_mapping}{Environment.NewLine}"); |
break; |
} |
} |
|
private void LocalCheckedListBoxBindingSourceOnListChanged(object sender, ListChangedEventArgs e) |
{ |
// Check items |
@@ -342,6 +363,12 @@ |
|
StoreConnectionAutocomplete(); |
|
// Try to reserve port: try UPnP followed by PMP. |
if (!await Discovery.CreateMapping(DiscoveryType.UPnP, port) && |
!await Discovery.CreateMapping(DiscoveryType.PMP, port)) |
ActivityTextBox.AppendText( |
$"{Strings.Failed_creating_automatic_port_mapping_please_make_sure_the_port_is_routed_properly}{Environment.NewLine}"); |
|
// Start the MQTT server. |
if (!await MqttCommunication |
.Start(MqttCommunicationType.Server, ipAddress, port, nick, password)) |