1 #region Copyright & License Information
2 /*
3  * Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
4  * This file is part of OpenRA, which is free software. It is made
5  * available to you under the terms of the GNU General Public License
6  * as published by the Free Software Foundation, either version 3 of
7  * the License, or (at your option) any later version. For more
8  * information, see COPYING.
9  */
10 #endregion
11 
12 using System;
13 using System.Diagnostics;
14 using System.Net;
15 using System.Threading;
16 using System.Threading.Tasks;
17 
18 using Open.Nat;
19 
20 namespace OpenRA.Network
21 {
22 	public enum UPnPStatus { Enabled, Disabled, NotSupported }
23 
24 	public class UPnP
25 	{
26 		static NatDevice natDevice;
27 		static Mapping mapping;
28 		static bool initialized;
29 
30 		public static IPAddress ExternalIP { get; private set; }
31 		public static UPnPStatus Status
32 		{
33 			get
34 			{
35 				return initialized ? natDevice != null ?
36 					UPnPStatus.Enabled : UPnPStatus.NotSupported : UPnPStatus.Disabled;
37 			}
38 		}
39 
DiscoverNatDevices(int timeout)40 		public static async Task DiscoverNatDevices(int timeout)
41 		{
42 			initialized = true;
43 
44 			NatDiscoverer.TraceSource.Switch.Level = SourceLevels.Verbose;
45 			var logChannel = Log.Channel("nat");
46 			NatDiscoverer.TraceSource.Listeners.Add(new TextWriterTraceListener(logChannel.Writer));
47 
48 			var natDiscoverer = new NatDiscoverer();
49 			var token = new CancellationTokenSource(timeout);
50 			natDevice = await natDiscoverer.DiscoverDeviceAsync(PortMapper.Upnp, token);
51 			try
52 			{
53 				ExternalIP = await natDevice.GetExternalIPAsync();
54 			}
55 			catch (Exception e)
56 			{
57 				Console.WriteLine("Getting the external IP from NAT device failed: {0}", e.Message);
58 				Log.Write("nat", e.StackTrace);
59 			}
60 		}
61 
ForwardPort(int listen, int external)62 		public static async Task ForwardPort(int listen, int external)
63 		{
64 			mapping = new Mapping(Protocol.Tcp, listen, external, "OpenRA");
65 			try
66 			{
67 				await natDevice.CreatePortMapAsync(mapping);
68 			}
69 			catch (Exception e)
70 			{
71 				Console.WriteLine("Port forwarding failed: {0}", e.Message);
72 				Log.Write("nat", e.StackTrace);
73 			}
74 		}
75 
RemovePortForward()76 		public static async Task RemovePortForward()
77 		{
78 			try
79 			{
80 				await natDevice.DeletePortMapAsync(mapping);
81 			}
82 			catch (Exception e)
83 			{
84 				Console.WriteLine("Port removal failed: {0}", e.Message);
85 				Log.Write("nat", e.StackTrace);
86 			}
87 		}
88 	}
89 }
90