diff --git a/3DView.rbxl b/3DView.rbxl
index 9a1cda5..918eeb7 100644
--- a/3DView.rbxl
+++ b/3DView.rbxl
@@ -28,18 +28,18 @@
[null]
0
- 2.8825047
- 16.8061104
- 19.8420525
- 0.990262866
- -0.0670645982
- 0.121990994
- 3.7252903e-009
- 0.876308203
- 0.481750816
- -0.139210135
- -0.477059931
- 0.8677755
+ 21.9769001
+ 13.1075497
+ -9.91257381
+ -0.342057496
+ -0.313667655
+ 0.885781765
+ -7.45057971e-009
+ 0.942642868
+ 0.333802998
+ -0.939678967
+ 0.114179812
+ -0.322438091
-0.167192921
@@ -324,6 +324,112 @@
end
end
+script.Parent.MouseButton1Down:connect(onClicked)
+ true
+
+
+
+ -
+
+ true
+ true
+ 4288914085
+ 0.400000006
+ 4279970357
+ 0
+ 0
+ 0
+ BackgroundColor
+
+ 1
+ -155
+ 1
+ -75
+
+ false
+
+ 0
+ 150
+ 0
+ 20
+
+ 0
+ 0
+ Change Background Color
+ 4283256141
+ 0
+ false
+ 2
+ 1
+ true
+ 1
+ true
+
+
-
+
+ false
+
+ LocalScript
+ function onClicked()
+ if (game.Lighting.Sky.SkyboxBk == "rbxasset://Sky/blue.jpg") then
+ game.Lighting.Sky.SkyboxBk = "rbxasset://Sky/red.jpg"
+ game.Lighting.Sky.SkyboxDn = "rbxasset://Sky/red.jpg"
+ game.Lighting.Sky.SkyboxFt = "rbxasset://Sky/red.jpg"
+ game.Lighting.Sky.SkyboxLf = "rbxasset://Sky/red.jpg"
+ game.Lighting.Sky.SkyboxRt = "rbxasset://Sky/red.jpg"
+ game.Lighting.Sky.SkyboxUp = "rbxasset://Sky/red.jpg"
+ elseif (game.Lighting.Sky.SkyboxBk == "rbxasset://Sky/red.jpg") then
+ game.Lighting.Sky.SkyboxBk = "rbxasset://Sky/green.jpg"
+ game.Lighting.Sky.SkyboxDn = "rbxasset://Sky/green.jpg"
+ game.Lighting.Sky.SkyboxFt = "rbxasset://Sky/green.jpg"
+ game.Lighting.Sky.SkyboxLf = "rbxasset://Sky/green.jpg"
+ game.Lighting.Sky.SkyboxRt = "rbxasset://Sky/green.jpg"
+ game.Lighting.Sky.SkyboxUp = "rbxasset://Sky/green.jpg"
+ elseif (game.Lighting.Sky.SkyboxBk == "rbxasset://Sky/green.jpg") then
+ game.Lighting.Sky.SkyboxBk = "rbxasset://Sky/orange.jpg"
+ game.Lighting.Sky.SkyboxDn = "rbxasset://Sky/orange.jpg"
+ game.Lighting.Sky.SkyboxFt = "rbxasset://Sky/orange.jpg"
+ game.Lighting.Sky.SkyboxLf = "rbxasset://Sky/orange.jpg"
+ game.Lighting.Sky.SkyboxRt = "rbxasset://Sky/orange.jpg"
+ game.Lighting.Sky.SkyboxUp = "rbxasset://Sky/orange.jpg"
+ elseif (game.Lighting.Sky.SkyboxBk == "rbxasset://Sky/orange.jpg") then
+ game.Lighting.Sky.SkyboxBk = "rbxasset://Sky/black.jpg"
+ game.Lighting.Sky.SkyboxDn = "rbxasset://Sky/black.jpg"
+ game.Lighting.Sky.SkyboxFt = "rbxasset://Sky/black.jpg"
+ game.Lighting.Sky.SkyboxLf = "rbxasset://Sky/black.jpg"
+ game.Lighting.Sky.SkyboxRt = "rbxasset://Sky/black.jpg"
+ game.Lighting.Sky.SkyboxUp = "rbxasset://Sky/black.jpg"
+ elseif (game.Lighting.Sky.SkyboxBk == "rbxasset://Sky/black.jpg") then
+ game.Lighting.Sky.SkyboxBk = "rbxasset://Sky/white.jpg"
+ game.Lighting.Sky.SkyboxDn = "rbxasset://Sky/white.jpg"
+ game.Lighting.Sky.SkyboxFt = "rbxasset://Sky/white.jpg"
+ game.Lighting.Sky.SkyboxLf = "rbxasset://Sky/white.jpg"
+ game.Lighting.Sky.SkyboxRt = "rbxasset://Sky/white.jpg"
+ game.Lighting.Sky.SkyboxUp = "rbxasset://Sky/white.jpg"
+ elseif (game.Lighting.Sky.SkyboxBk == "rbxasset://Sky/white.jpg") then
+ game.Lighting.Sky.SkyboxBk = "rbxasset://Sky/greenscreen.jpg"
+ game.Lighting.Sky.SkyboxDn = "rbxasset://Sky/greenscreen.jpg"
+ game.Lighting.Sky.SkyboxFt = "rbxasset://Sky/greenscreen.jpg"
+ game.Lighting.Sky.SkyboxLf = "rbxasset://Sky/greenscreen.jpg"
+ game.Lighting.Sky.SkyboxRt = "rbxasset://Sky/greenscreen.jpg"
+ game.Lighting.Sky.SkyboxUp = "rbxasset://Sky/greenscreen.jpg"
+ elseif (game.Lighting.Sky.SkyboxBk == "rbxasset://Sky/greenscreen.jpg") then
+ game.Lighting.Sky.SkyboxBk = "rbxasset://Sky/blue.jpg"
+ game.Lighting.Sky.SkyboxDn = "rbxasset://Sky/blue.jpg"
+ game.Lighting.Sky.SkyboxFt = "rbxasset://Sky/blue.jpg"
+ game.Lighting.Sky.SkyboxLf = "rbxasset://Sky/blue.jpg"
+ game.Lighting.Sky.SkyboxRt = "rbxasset://Sky/blue.jpg"
+ game.Lighting.Sky.SkyboxUp = "rbxasset://Sky/blue.jpg"
+ else
+ game.Lighting.Sky.SkyboxBk = "rbxasset://Sky/red.jpg"
+ game.Lighting.Sky.SkyboxDn = "rbxasset://Sky/red.jpg"
+ game.Lighting.Sky.SkyboxFt = "rbxasset://Sky/red.jpg"
+ game.Lighting.Sky.SkyboxLf = "rbxasset://Sky/red.jpg"
+ game.Lighting.Sky.SkyboxRt = "rbxasset://Sky/red.jpg"
+ game.Lighting.Sky.SkyboxUp = "rbxasset://Sky/red.jpg"
+ end
+end
+
script.Parent.MouseButton1Down:connect(onClicked)
true
@@ -331,7 +437,7 @@ script.Parent.MouseButton1Down:connect(onClicked)
- -
+
-
0
10
@@ -341,68 +447,68 @@ script.Parent.MouseButton1Down:connect(onClicked)
true
- -
+
-
CollectionService
true
- -
+
-
PhysicsService
true
- -
+
-
BadgeService
true
- -
+
-
Geometry
true
- -
+
-
RenderHooksService
true
- -
+
-
SocialService
true
- -
+
-
1000
Debris
true
- -
+
-
Instance
true
- -
+
-
Instance
true
- -
+
-
Selection
true
- -
+
-
4286874756
1
@@ -414,7 +520,7 @@ script.Parent.MouseButton1Down:connect(onClicked)
14:00:00
true
-
-
+
-
false
Sky
@@ -429,19 +535,19 @@ script.Parent.MouseButton1Down:connect(onClicked)
- -
+
-
ChangeHistoryService
true
- -
+
-
Instance
true
- -
+
-
Instance
true
diff --git a/Mono.Nat.dll b/Mono.Nat.dll
deleted file mode 100644
index 614b2c2..0000000
Binary files a/Mono.Nat.dll and /dev/null differ
diff --git a/Open.NAT/AUTHORS b/Open.NAT/AUTHORS
new file mode 100644
index 0000000..db51ca0
--- /dev/null
+++ b/Open.NAT/AUTHORS
@@ -0,0 +1,8 @@
+Open.Nat is a Mono.Nat fork
+
+= Mono.Nat authors
+Alan McGovern
+Ben Motmans
+
+= Open.Nat author
+Lucas Ontivero
diff --git a/Open.NAT/LICENSE b/Open.NAT/LICENSE
new file mode 100644
index 0000000..8d02e21
--- /dev/null
+++ b/Open.NAT/LICENSE
@@ -0,0 +1,24 @@
+
+The MIT License
+
+Copyright (C) 2006 Alan McGovern
+Copyright (C) 2007 Ben Motmans
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/Open.NAT/Open.Nat.sln b/Open.NAT/Open.Nat.sln
new file mode 100644
index 0000000..26d76cf
--- /dev/null
+++ b/Open.NAT/Open.Nat.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Express 2013 for Windows Desktop
+VisualStudioVersion = 12.0.31101.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Open.Nat", "Open.Nat\Open.Nat.csproj", "{F5D74163-145F-47BF-83DC-D0E07249C6CA}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documents", "Documents", "{94F0AE28-727F-497A-AC20-EB5B0C5EBA9A}"
+ ProjectSection(SolutionItems) = preProject
+ .gitignore = .gitignore
+ AUTHORS = AUTHORS
+ LICENSE = LICENSE
+ README.md = README.md
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F5D74163-145F-47BF-83DC-D0E07249C6CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F5D74163-145F-47BF-83DC-D0E07249C6CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F5D74163-145F-47BF-83DC-D0E07249C6CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F5D74163-145F-47BF-83DC-D0E07249C6CA}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(OpenDevelopProperties) = preSolution
+ version = 0.1
+ StartupItem = Open.Nat\Open.Nat.csproj
+ name = Open.Nat
+ EndGlobalSection
+EndGlobal
diff --git a/Open.NAT/Open.Nat/AssemblyInfo.cs b/Open.NAT/Open.Nat/AssemblyInfo.cs
new file mode 100644
index 0000000..c92f553
--- /dev/null
+++ b/Open.NAT/Open.Nat/AssemblyInfo.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Open.Nat")]
+[assembly: AssemblyDescription(".NET Library for automatic network address translation")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Open.Nat")]
+[assembly: AssemblyCopyright("Copyright Alan McGovern, Ben Motmans, Lucas Ontivero © 2006-2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: Guid("c8e81e95-9f15-4eb8-8982-3d2c9cd95dee")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.1.0.0")]
+[assembly: CLSCompliant(false)]
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Discovery/ISearcher.cs b/Open.NAT/Open.Nat/Discovery/ISearcher.cs
new file mode 100644
index 0000000..ef90a74
--- /dev/null
+++ b/Open.NAT/Open.Nat/Discovery/ISearcher.cs
@@ -0,0 +1,39 @@
+//
+// Authors:
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections.Generic;
+using System.Net;
+using System.Threading;
+
+namespace Open.Nat
+{
+ internal interface ISearcher
+ {
+ void Search(CancellationToken cancellationToken);
+ IEnumerable Receive();
+ NatDevice AnalyseReceivedResponse(IPAddress localAddress, byte[] response, IPEndPoint endpoint);
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Discovery/Searcher.cs b/Open.NAT/Open.Nat/Discovery/Searcher.cs
new file mode 100644
index 0000000..2508db0
--- /dev/null
+++ b/Open.NAT/Open.Nat/Discovery/Searcher.cs
@@ -0,0 +1,115 @@
+//
+// Authors:
+// Ben Motmans
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2007 Ben Motmans
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Open.Nat
+{
+ internal abstract class Searcher
+ {
+ private readonly List _devices = new List();
+ protected List Sockets;
+ public EventHandler DeviceFound;
+ internal DateTime NextSearch = DateTime.UtcNow;
+
+ public async Task> Search(CancellationToken cancelationToken)
+ {
+ await Task.Factory.StartNew(async _ =>
+ {
+ NatDiscoverer.TraceSource.LogInfo("Searching for: {0}", GetType().Name);
+ while (!cancelationToken.IsCancellationRequested)
+ {
+ Discover(cancelationToken);
+ Receive(cancelationToken);
+ }
+ CloseSockets();
+ }, cancelationToken);
+ return _devices;
+ }
+
+ private void Discover(CancellationToken cancelationToken)
+ {
+ if(DateTime.UtcNow < NextSearch) return;
+
+ foreach (var socket in Sockets)
+ {
+ try
+ {
+ Discover(socket, cancelationToken);
+ }
+ catch (Exception e)
+ {
+ NatDiscoverer.TraceSource.LogError("Error searching {0} - Details:", GetType().Name);
+ NatDiscoverer.TraceSource.LogError(e.ToString());
+ }
+ }
+ }
+
+ private void Receive(CancellationToken cancelationToken)
+ {
+ foreach (var client in Sockets.Where(x=>x.Available>0))
+ {
+ if(cancelationToken.IsCancellationRequested) return;
+
+ var localHost = ((IPEndPoint)client.Client.LocalEndPoint).Address;
+ var receivedFrom = new IPEndPoint(IPAddress.None, 0);
+ var buffer = client.Receive(ref receivedFrom);
+ var device = AnalyseReceivedResponse(localHost, buffer, receivedFrom);
+
+ if (device != null) RaiseDeviceFound(device);
+ }
+ }
+
+
+ protected abstract void Discover(UdpClient client, CancellationToken cancelationToken);
+
+ public abstract NatDevice AnalyseReceivedResponse(IPAddress localAddress, byte[] response, IPEndPoint endpoint);
+
+ public void CloseSockets()
+ {
+ foreach (var udpClient in Sockets)
+ {
+ udpClient.Close();
+ }
+ }
+
+ private void RaiseDeviceFound(NatDevice device)
+ {
+ _devices.Add(device);
+ var handler = DeviceFound;
+ if(handler!=null)
+ handler(this, new DeviceEventArgs(device));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Enums/ProtocolType.cs b/Open.NAT/Open.Nat/Enums/ProtocolType.cs
new file mode 100644
index 0000000..ddb4a20
--- /dev/null
+++ b/Open.NAT/Open.Nat/Enums/ProtocolType.cs
@@ -0,0 +1,43 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace Open.Nat
+{
+ ///
+ /// Protocol to allow/disallow
+ ///
+ public enum Protocol
+ {
+ ///
+ /// Transport Control Protocol
+ ///
+ Tcp,
+ ///
+ /// Datagram Protocol
+ ///
+ Udp
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/EventArgs/DeviceEventArgs.cs b/Open.NAT/Open.Nat/EventArgs/DeviceEventArgs.cs
new file mode 100644
index 0000000..e02ec04
--- /dev/null
+++ b/Open.NAT/Open.Nat/EventArgs/DeviceEventArgs.cs
@@ -0,0 +1,40 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace Open.Nat
+{
+ internal class DeviceEventArgs : System.EventArgs
+ {
+ public DeviceEventArgs(NatDevice device)
+ {
+ Device = device;
+ }
+
+ public NatDevice Device { get; private set; }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Exceptions/MappingException.cs b/Open.NAT/Open.Nat/Exceptions/MappingException.cs
new file mode 100644
index 0000000..d203ee3
--- /dev/null
+++ b/Open.NAT/Open.Nat/Exceptions/MappingException.cs
@@ -0,0 +1,91 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Runtime.Serialization;
+using System.Security.Permissions;
+
+namespace Open.Nat
+{
+ ///
+ ///
+ ///
+ [Serializable]
+ public class MappingException : Exception
+ {
+ ///
+ ///
+ ///
+ public int ErrorCode { get; private set; }
+
+ ///
+ ///
+ ///
+ public string ErrorText { get; private set; }
+
+ #region Constructors
+
+ internal MappingException()
+ {
+ }
+
+ internal MappingException(string message)
+ : base(message)
+ {
+ }
+
+ internal MappingException(int errorCode, string errorText)
+ : base(string.Format("Error {0}: {1}", errorCode, errorText))
+ {
+ ErrorCode = errorCode;
+ ErrorText = errorText;
+ }
+
+ internal MappingException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
+ protected MappingException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+
+ #endregion
+
+ [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
+ public override void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ if (info == null) throw new ArgumentNullException("info");
+
+ ErrorCode = info.GetInt32("errorCode");
+ ErrorText = info.GetString("errorText");
+ base.GetObjectData(info, context);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Exceptions/NatDeviceNotFoundException.cs b/Open.NAT/Open.Nat/Exceptions/NatDeviceNotFoundException.cs
new file mode 100644
index 0000000..d40063d
--- /dev/null
+++ b/Open.NAT/Open.Nat/Exceptions/NatDeviceNotFoundException.cs
@@ -0,0 +1,69 @@
+//
+// Authors:
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Runtime.Serialization;
+
+namespace Open.Nat
+{
+ ///
+ ///
+ ///
+ [Serializable]
+ public class NatDeviceNotFoundException : Exception
+ {
+ ///
+ ///
+ ///
+ public NatDeviceNotFoundException()
+ {
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public NatDeviceNotFoundException(string message)
+ : base(message)
+ {
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public NatDeviceNotFoundException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
+ protected NatDeviceNotFoundException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Finalizer.cs b/Open.NAT/Open.Nat/Finalizer.cs
new file mode 100644
index 0000000..ce3de66
--- /dev/null
+++ b/Open.NAT/Open.Nat/Finalizer.cs
@@ -0,0 +1,37 @@
+//
+// Authors:
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+namespace Open.Nat
+{
+ sealed class Finalizer
+ {
+ ~Finalizer()
+ {
+ NatDiscoverer.TraceSource.LogInfo("Closing ports opened in this session");
+ NatDiscoverer.RenewTimer.Dispose();
+ NatDiscoverer.ReleaseSessionMappings();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Mapping.cs b/Open.NAT/Open.Nat/Mapping.cs
new file mode 100644
index 0000000..29a17f0
--- /dev/null
+++ b/Open.NAT/Open.Nat/Mapping.cs
@@ -0,0 +1,273 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+// Ben Motmans
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+// Copyright (C) 2007 Ben Motmans
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Net;
+
+namespace Open.Nat
+{
+ enum MappingLifetime
+ {
+ Permanent,
+ Session,
+ Manual,
+ ForcedSession
+ }
+
+ ///
+ /// Represents a port forwarding entry in the NAT translation table.
+ ///
+ public class Mapping
+ {
+ private DateTime _expiration;
+ private int _lifetime;
+ internal MappingLifetime LifetimeType { get; set; }
+
+
+ ///
+ /// Gets the mapping's description. It is the value stored in the NewPortMappingDescription parameter.
+ /// The NewPortMappingDescription parameter is a human readable string that describes the connection.
+ /// It is used in sorme web interfaces of routers so the user can see which program is using what port.
+ ///
+ public string Description { get; internal set; }
+ ///
+ /// Gets the private ip.
+ ///
+ public IPAddress PrivateIP { get; internal set; }
+ ///
+ /// Gets the protocol.
+ ///
+ public Protocol Protocol { get; internal set; }
+ ///
+ /// The PrivatePort parameter specifies the port on a client machine to which all traffic
+ /// coming in on PublicPort for the protocol specified by
+ /// Protocol should be forwarded to.
+ ///
+ /// Protocol enum
+ public int PrivatePort { get; internal set; }
+ ///
+ /// Gets the public ip.
+ ///
+ public IPAddress PublicIP { get; internal set; }
+ ///
+ /// Gets the external (visible) port number.
+ /// It is the value stored in the NewExternalPort parameter .
+ /// The NewExternalPort parameter is used to specify the TCP or UDP port on the WAN side of the router which should be forwarded.
+ ///
+ public int PublicPort { get; internal set; }
+ ///
+ /// Gets the lifetime. The Lifetime parameter tells the router how long the portmapping should be active.
+ /// Since most programs don't know this in advance, it is often set to 0, which means 'unlimited' or 'permanent'.
+ ///
+ ///
+ /// All portmappings are release automatically as part of the shutdown process when NatUtility.ReleaseOnShutdown is true.
+ /// Permanent portmappings will not be released if the process ends anormally.
+ /// Since most programs don't know the lifetime in advance, Open.NAT renew all the portmappings (except the permanents) before they expires. So, developers have to close explicitly those portmappings
+ /// they don't want to remain open for the session.
+ ///
+ public int Lifetime
+ {
+ get { return _lifetime; }
+ internal set
+ {
+ switch (value)
+ {
+ case int.MaxValue:
+ LifetimeType = MappingLifetime.Session;
+ _lifetime = 10 * 60; // ten minutes
+ _expiration = DateTime.UtcNow.AddSeconds(_lifetime);;
+ break;
+ case 0:
+ LifetimeType = MappingLifetime.Permanent;
+ _lifetime = 0;
+ _expiration = DateTime.UtcNow;
+ break;
+ default:
+ LifetimeType = MappingLifetime.Manual;
+ _lifetime = value;
+ _expiration = DateTime.UtcNow.AddSeconds(_lifetime);
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Gets the expiration. The property value is calculated using Lifetime property.
+ ///
+ public DateTime Expiration
+ {
+ get { return _expiration; }
+ internal set
+ {
+ _expiration = value;
+ _lifetime = (int)(_expiration - DateTime.UtcNow).TotalSeconds;
+ }
+ }
+
+ internal Mapping(Protocol protocol, IPAddress privateIP, int privatePort, int publicPort)
+ : this(protocol, privateIP, privatePort, publicPort, 0, "Open.Nat")
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The protocol.
+ /// The private ip.
+ /// The private port.
+ /// The public port.
+ /// The lifetime.
+ /// The description.
+ internal Mapping(Protocol protocol, IPAddress privateIP, int privatePort, int publicPort, int lifetime, string description)
+ {
+ Guard.IsInRange(privatePort, 0, ushort.MaxValue, "privatePort");
+ Guard.IsInRange(publicPort, 0, ushort.MaxValue, "publicPort");
+ Guard.IsInRange(lifetime, 0, int.MaxValue, "lifetime");
+ Guard.IsTrue(protocol == Protocol.Tcp || protocol == Protocol.Udp, "protocol");
+
+ Protocol = protocol;
+ PrivateIP = privateIP;
+ PrivatePort = privatePort;
+ PublicIP = IPAddress.None;
+ PublicPort = publicPort;
+ Lifetime = lifetime;
+ Description = description;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The protocol.
+ /// The private port.
+ /// The public port.
+ ///
+ /// This constructor initializes a Permanent mapping. The description by deafult is "Open.NAT"
+ ///
+ public Mapping(Protocol protocol, int privatePort, int publicPort)
+ : this(protocol, IPAddress.None, privatePort, publicPort, 0, "Open.NAT")
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The protocol.
+ /// The private port.
+ /// The public port.
+ /// The description.
+ ///
+ /// This constructor initializes a Permanent mapping.
+ ///
+ public Mapping(Protocol protocol, int privatePort, int publicPort, string description)
+ : this(protocol, IPAddress.None, privatePort, publicPort, int.MaxValue, description)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The protocol.
+ /// The private port.
+ /// The public port.
+ /// The lifetime.
+ /// The description.
+ public Mapping(Protocol protocol, int privatePort, int publicPort, int lifetime, string description)
+ : this(protocol, IPAddress.None, privatePort, publicPort, lifetime, description)
+ {
+ }
+
+ internal Mapping(Mapping mapping)
+ {
+ PrivateIP = mapping.PrivateIP;
+ PrivatePort = mapping.PrivatePort;
+ Protocol = mapping.Protocol;
+ PublicIP = mapping.PublicIP;
+ PublicPort = mapping.PublicPort;
+ LifetimeType = mapping.LifetimeType;
+ Description = mapping.Description;
+ _lifetime = mapping._lifetime;
+ _expiration = mapping._expiration;
+ }
+
+ ///
+ /// Determines whether this instance is expired.
+ ///
+ ///
+ /// Permanent mappings never expires.
+ ///
+ public bool IsExpired ()
+ {
+ return LifetimeType != MappingLifetime.Permanent
+ && LifetimeType != MappingLifetime.ForcedSession
+ && Expiration < DateTime.UtcNow;
+ }
+
+ internal bool ShoundRenew()
+ {
+ return LifetimeType == MappingLifetime.Session && IsExpired();
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ var m = obj as Mapping;
+ if (ReferenceEquals(null, m)) return false;
+ return PublicPort == m.PublicPort && PrivatePort == m.PrivatePort;
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ var hashCode = PublicPort;
+ hashCode = (hashCode * 397) ^ (PrivateIP != null ? PrivateIP.GetHashCode() : 0);
+ hashCode = (hashCode * 397) ^ PrivatePort;
+ return hashCode;
+ }
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ ///
+ /// A that represents this instance.
+ ///
+ public override string ToString()
+ {
+ return string.Format("{0} {1} --> {2}:{3} ({4})",
+ Protocol == Protocol.Tcp ? "Tcp" : "Udp",
+ PublicPort,
+ PrivateIP,
+ PrivatePort,
+ Description);
+ }
+ }
+}
diff --git a/Open.NAT/Open.Nat/NatDevice.cs b/Open.NAT/Open.Nat/NatDevice.cs
new file mode 100644
index 0000000..96797e5
--- /dev/null
+++ b/Open.NAT/Open.Nat/NatDevice.cs
@@ -0,0 +1,186 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+// Ben Motmans
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+// Copyright (C) 2007 Ben Motmans
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Threading.Tasks;
+
+namespace Open.Nat
+{
+ ///
+ /// Represents a NAT device and provides access to the operation set that allows
+ /// open (forward) ports, close ports and get the externa (visible) IP address.
+ ///
+ public abstract class NatDevice
+ {
+ private readonly HashSet _openedMapping = new HashSet();
+ protected DateTime LastSeen { get; private set; }
+
+ internal void Touch()
+ {
+ LastSeen = DateTime.Now;
+ }
+
+ ///
+ /// Creates the port map asynchronous.
+ ///
+ /// The Mapping entry.
+ ///
+ /// device.CreatePortMapAsync(new Mapping(Protocol.Tcp, 1700, 1600));
+ ///
+ /// MappingException
+ public abstract Task CreatePortMapAsync(Mapping mapping);
+
+ ///
+ /// Deletes a mapped port asynchronous.
+ ///
+ /// The Mapping entry.
+ ///
+ /// device.DeletePortMapAsync(new Mapping(Protocol.Tcp, 1700, 1600));
+ ///
+ /// MappingException-class
+ public abstract Task DeletePortMapAsync(Mapping mapping);
+
+ ///
+ /// Gets all mappings asynchronous.
+ ///
+ ///
+ /// The list of all forwarded ports
+ ///
+ ///
+ /// var mappings = await device.GetAllMappingsAsync();
+ /// foreach(var mapping in mappings)
+ /// {
+ /// Console.WriteLine(mapping)
+ /// }
+ ///
+ /// MappingException
+ public abstract Task> GetAllMappingsAsync();
+
+ ///
+ /// Gets the external (visible) IP address asynchronous. This is the NAT device IP address
+ ///
+ ///
+ /// The public IP addrees
+ ///
+ ///
+ /// Console.WriteLine("My public IP is: {0}", await device.GetExternalIPAsync());
+ ///
+ /// MappingException
+ public abstract Task GetExternalIPAsync();
+
+ ///
+ /// Gets the specified mapping asynchronous.
+ ///
+ /// The protocol.
+ /// The port.
+ ///
+ /// The matching mapping
+ ///
+ public abstract Task GetSpecificMappingAsync(Protocol protocol, int port);
+
+ protected void RegisterMapping(Mapping mapping)
+ {
+ _openedMapping.Remove(mapping);
+ _openedMapping.Add(mapping);
+ }
+
+ protected void UnregisterMapping(Mapping mapping)
+ {
+ _openedMapping.RemoveWhere(x => x.Equals(mapping));
+ }
+
+
+ internal void ReleaseMapping(IEnumerable mappings)
+ {
+ var maparr = mappings.ToArray();
+ var mapCount = maparr.Length;
+ NatDiscoverer.TraceSource.LogInfo("{0} ports to close", mapCount);
+ for (var i = 0; i < mapCount; i++)
+ {
+ var mapping = _openedMapping.ElementAt(i);
+
+ try
+ {
+ DeletePortMapAsync(mapping);
+ NatDiscoverer.TraceSource.LogInfo(mapping + " port successfully closed");
+ }
+ catch (Exception)
+ {
+ NatDiscoverer.TraceSource.LogError(mapping + " port couldn't be close");
+ }
+ }
+ }
+
+ internal void ReleaseAll()
+ {
+ ReleaseMapping(_openedMapping);
+ }
+
+ internal void ReleaseSessionMappings()
+ {
+ var mappings = from m in _openedMapping
+ where m.LifetimeType == MappingLifetime.Session
+ select m;
+
+ ReleaseMapping(mappings);
+ }
+
+ internal async Task RenewMappings()
+ {
+ var mappings = _openedMapping.Where(x => x.ShoundRenew());
+ foreach (var mapping in mappings.ToArray())
+ {
+ var m = mapping;
+ await RenewMapping(m);
+ }
+ }
+
+ private async Task RenewMapping(Mapping mapping)
+ {
+ var renewMapping = new Mapping(mapping);
+ try
+ {
+ renewMapping.Expiration = DateTime.UtcNow.AddSeconds(mapping.Lifetime);
+
+ NatDiscoverer.TraceSource.LogInfo("Renewing mapping {0}", renewMapping);
+ await CreatePortMapAsync(renewMapping);
+ NatDiscoverer.TraceSource.LogInfo("Next renew scheduled at: {0}",
+ renewMapping.Expiration.ToLocalTime().TimeOfDay);
+ }
+ catch (Exception)
+ {
+ NatDiscoverer.TraceSource.LogWarn("Renew {0} failed", mapping);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/NatDiscoverer.cs b/Open.NAT/Open.Nat/NatDiscoverer.cs
new file mode 100644
index 0000000..ee14aa1
--- /dev/null
+++ b/Open.NAT/Open.Nat/NatDiscoverer.cs
@@ -0,0 +1,160 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Open.Nat
+{
+ ///
+ ///
+ ///
+ public class NatDiscoverer
+ {
+ ///
+ /// The TraceSource instance
+ /// used for debugging and Troubleshooting
+ ///
+ ///
+ /// NatUtility.TraceSource.Switch.Level = SourceLevels.Verbose;
+ /// NatUtility.TraceSource.Listeners.Add(new ConsoleListener());
+ ///
+ ///
+ /// At least one trace listener has to be added to the Listeners collection if a trace is required; if no listener is added
+ /// there will no be tracing to analyse.
+ ///
+ ///
+ /// Open.NAT only supports SourceLevels.Verbose, SourceLevels.Error, SourceLevels.Warning and SourceLevels.Information.
+ ///
+ public readonly static TraceSource TraceSource = new TraceSource("Open.NAT");
+
+ private static readonly Dictionary Devices = new Dictionary();
+
+ // Finalizer is never used however its destructor, that releases the open ports, is invoked by the
+ // process as part of the shuting down step. So, don't remove it!
+ private static readonly Finalizer Finalizer = new Finalizer();
+ internal static readonly Timer RenewTimer = new Timer(RenewMappings, null, 5000, 2000);
+
+ ///
+ /// Discovers and returns an UPnp or Pmp NAT device; otherwise a NatDeviceNotFoundException
+ /// exception is thrown after 3 seconds.
+ ///
+ /// A NAT device
+ /// when no NAT found before 3 seconds.
+ public async Task DiscoverDeviceAsync()
+ {
+ var cts = new CancellationTokenSource(3 * 1000);
+ return await DiscoverDeviceAsync(PortMapper.Pmp | PortMapper.Upnp, cts);
+ }
+
+ ///
+ /// Discovers and returns a NAT device for the specified type; otherwise a NatDeviceNotFoundException
+ /// exception is thrown when it is cancelled.
+ ///
+ ///
+ /// It allows to specify the NAT type to discover as well as the cancellation token in order.
+ ///
+ /// Port mapper protocol; Upnp, Pmp or both
+ /// Cancellation token source for cancelling the discovery process
+ /// A NAT device
+ /// when no NAT found before cancellation
+ public async Task DiscoverDeviceAsync(PortMapper portMapper, CancellationTokenSource cancellationTokenSource)
+ {
+ Guard.IsTrue(portMapper == PortMapper.Upnp || portMapper == PortMapper.Pmp, "poertMapper");
+ Guard.IsNotNull(cancellationTokenSource, "cancellationTokenSource");
+
+ var devices = await DiscoverAsync(portMapper, true, cancellationTokenSource);
+ var device = devices.FirstOrDefault();
+ if(device==null)
+ {
+ throw new NatDeviceNotFoundException();
+ }
+ return device;
+ }
+
+ ///
+ /// Discovers and returns all NAT devices for the specified type. If no NAT device is found it returns an empty enumerable
+ ///
+ /// Port mapper protocol; Upnp, Pmp or both
+ /// Cancellation token source for cancelling the discovery process
+ /// All found NAT devices
+ public async Task> DiscoverDevicesAsync(PortMapper portMapper, CancellationTokenSource cancellationTokenSource)
+ {
+ Guard.IsTrue(portMapper == PortMapper.Upnp || portMapper == PortMapper.Pmp, "poertMapper");
+ Guard.IsNotNull(cancellationTokenSource, "cancellationTokenSource");
+
+ var devices = await DiscoverAsync(portMapper, false, cancellationTokenSource);
+ return devices.ToArray();
+ }
+
+ private async Task> DiscoverAsync(PortMapper portMapper, bool onlyOne, CancellationTokenSource cts)
+ {
+ TraceSource.LogInfo("Start Discovery");
+ var searcherTasks = new List>>();
+ if(portMapper.HasFlag(PortMapper.Upnp))
+ {
+ var upnpSearcher = new UpnpSearcher(new IPAddressesProvider());
+ upnpSearcher.DeviceFound += (sender, args) => { if (onlyOne) cts.Cancel(); };
+ searcherTasks.Add(upnpSearcher.Search(cts.Token));
+ }
+ if(portMapper.HasFlag(PortMapper.Pmp))
+ {
+ var pmpSearcher = new PmpSearcher(new IPAddressesProvider());
+ pmpSearcher.DeviceFound += (sender, args) => { if (onlyOne) cts.Cancel(); };
+ searcherTasks.Add(pmpSearcher.Search(cts.Token));
+ }
+
+ await Task.WhenAll(searcherTasks);
+ TraceSource.LogInfo("Stop Discovery");
+
+ var devices = searcherTasks.SelectMany(x => x.Result);
+ foreach (var device in devices)
+ {
+ var key = device.ToString();
+ NatDevice nat;
+ if(Devices.TryGetValue(key, out nat))
+ {
+ nat.Touch();
+ }
+ else
+ {
+ Devices.Add(key, device);
+ }
+ }
+ return devices;
+ }
+
+ ///
+ /// Release all ports opened by Open.NAT.
+ ///
+ ///
+ /// If ReleaseOnShutdown value is true, it release all the mappings created through the library.
+ ///
+ public static void ReleaseAll()
+ {
+ foreach (var device in Devices.Values)
+ {
+ device.ReleaseAll();
+ }
+ }
+
+ internal static void ReleaseSessionMappings()
+ {
+ foreach (var device in Devices.Values)
+ {
+ device.ReleaseSessionMappings();
+ }
+ }
+
+ private static void RenewMappings(object state)
+ {
+ Task.Factory.StartNew(async ()=>
+ {
+ foreach (var device in Devices.Values)
+ {
+ await device.RenewMappings();
+ }
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Open.Nat.csproj b/Open.NAT/Open.Nat/Open.Nat.csproj
new file mode 100644
index 0000000..fd832a5
--- /dev/null
+++ b/Open.NAT/Open.Nat/Open.Nat.csproj
@@ -0,0 +1,108 @@
+
+
+
+ Debug
+ AnyCPU
+ {F5D74163-145F-47BF-83DC-D0E07249C6CA}
+ Library
+ false
+ Open.Nat
+ Open.Nat
+ 8.0.50727
+ 2.0
+ v4.5
+
+
+
+
+ 2.0
+
+ ..\
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ 4
+ true
+ Library
+ Open.Nat
+ AllRules.ruleset
+ false
+ bin\Debug\Open.Nat.XML
+
+
+ true
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ 4
+ true
+ Library
+ Open.Nat
+ AllRules.ruleset
+ false
+
+
+ true
+
+
+ Open.Nat.snk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Open.Nat.nuspec b/Open.NAT/Open.Nat/Open.Nat.nuspec
new file mode 100644
index 0000000..f97ed68
--- /dev/null
+++ b/Open.NAT/Open.Nat/Open.Nat.nuspec
@@ -0,0 +1,51 @@
+
+
+
+ Open.NAT
+ $version$
+ Open.NAT
+ Alan McGovern, Ben Motmans, Lucas Ontivero
+ http://opensource.org/licenses/MIT
+ https://github.com/lontivero/Open.NAT
+ http://github.com/lontivero/Open.Nat/raw/gh-pages/images/logos/64.jpg
+ false
+
+ Open.NAT is a lightweight and easy-to-use class library to allow port forwarding in NAT devices (Network Address Translator) that support Universal Plug and Play (UPNP) and/or Port Mapping Protocol (PMP).
+
+ Library to allow port forwarding in NAT devices that support UPNP and/or PMP.
+ en-US
+ Please see LICENSE for more details.
+ NAT TRANSVERSAL UPNP PMP PORT FORWARD
+
+ **Version 2.0.8**
+ Fixes several defects. #10, #11, #12, #13 and #14
+
+ **2.0.0**
+ Thus version breaks backward compatibility with v1.
+ Changes the event-based discovery process' nature to an asynchronous one.
+
+ **1.1.0**
+ Fix for SSDP Location header.
+ After this version Open.NAT breaks backward compatibility.
+
+ **1.0.19**
+ Minor changes previous to v2.
+
+ **1.0.18**
+ Discovery timeout raises an event.
+ Permanent mappings are created when NAT only supports that kind of mappings.
+ Protocol to use in discovery process can be specified.
+ Automatic renew port mappings before expiration.
+ Add operations timeout after 4 seconds.
+ Add parameters validation in Mapping class.
+ Fix UnhandledException event was never raised.
+
+ **1.0.17**
+ Discovery timeout added.
+ Auto release ports opened in the session.
+ Fix NextSearch to use UtcNow (also performance)
+ Fix LocalIP property after add a port.
+ Tracing improvements
+
+
+
diff --git a/Open.NAT/Open.Nat/Open.Nat.snk b/Open.NAT/Open.Nat/Open.Nat.snk
new file mode 100644
index 0000000..9988163
Binary files /dev/null and b/Open.NAT/Open.Nat/Open.Nat.snk differ
diff --git a/Open.NAT/Open.Nat/Pmp/PmpConstants.cs b/Open.NAT/Open.Nat/Pmp/PmpConstants.cs
new file mode 100644
index 0000000..313c0db
--- /dev/null
+++ b/Open.NAT/Open.Nat/Pmp/PmpConstants.cs
@@ -0,0 +1,63 @@
+//
+// Authors:
+// Ben Motmans
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2007 Ben Motmans
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace Open.Nat
+{
+ internal static class PmpConstants
+ {
+ public const byte Version = 0;
+
+ public const byte OperationExternalAddressRequest = 0;
+ public const byte OperationCodeUdp = 1;
+ public const byte OperationCodeTcp = 2;
+ public const byte ServerNoop = 128;
+
+ public const int ClientPort = 5350;
+ public const int ServerPort = 5351;
+
+ public const int RetryDelay = 250;
+ public const int RetryAttempts = 9;
+
+ public const int RecommendedLeaseTime = 60*60;
+ public const int DefaultLeaseTime = RecommendedLeaseTime;
+
+ public const short ResultCodeSuccess = 0; // Success
+ public const short ResultCodeUnsupportedVersion = 1; // Unsupported Version
+
+ public const short ResultCodeNotAuthorized = 2;
+ // Not Authorized/Refused (e.g. box supports mapping, but user has turned feature off)
+
+ public const short ResultCodeNetworkFailure = 3;
+ // Network Failure (e.g. NAT box itself has not obtained a DHCP lease)
+
+ public const short ResultCodeOutOfResources = 4;
+ // Out of resources (NAT box cannot create any more mappings at this time)
+
+ public const short ResultCodeUnsupportedOperationCode = 5; // Unsupported opcode
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Pmp/PmpNatDevice.cs b/Open.NAT/Open.Nat/Pmp/PmpNatDevice.cs
new file mode 100644
index 0000000..beb2669
--- /dev/null
+++ b/Open.NAT/Open.Nat/Pmp/PmpNatDevice.cs
@@ -0,0 +1,192 @@
+//
+// Authors:
+// Ben Motmans
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2007 Ben Motmans
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Open.Nat
+{
+ internal sealed class PmpNatDevice : NatDevice
+ {
+ private readonly IPAddress _publicAddress;
+
+ internal PmpNatDevice(IPAddress localAddress, IPAddress publicAddress)
+ {
+ LocalAddress = localAddress;
+ _publicAddress = publicAddress;
+ }
+
+ internal IPAddress LocalAddress { get; private set; }
+
+ public override async Task CreatePortMapAsync(Mapping mapping)
+ {
+ await InternalCreatePortMapAsync(mapping, true)
+ .TimeoutAfter(TimeSpan.FromSeconds(4));
+ RegisterMapping(mapping);
+ }
+
+ public override async Task DeletePortMapAsync(Mapping mapping)
+ {
+ await InternalCreatePortMapAsync(mapping, false)
+ .TimeoutAfter(TimeSpan.FromSeconds(4));
+ UnregisterMapping(mapping);
+ }
+
+ public override Task> GetAllMappingsAsync()
+ {
+ throw new NotSupportedException();
+ }
+
+ public override Task GetExternalIPAsync()
+ {
+ return Task.Run(() => _publicAddress)
+ .TimeoutAfter(TimeSpan.FromSeconds(4));
+ }
+
+ public override Task GetSpecificMappingAsync(Protocol protocol, int port)
+ {
+ throw new NotSupportedException("NAT-PMP does not specify a way to get a specific port map");
+ }
+
+
+ private async Task InternalCreatePortMapAsync(Mapping mapping, bool create)
+ {
+ var package = new List();
+
+ package.Add(PmpConstants.Version);
+ package.Add(mapping.Protocol == Protocol.Tcp ? PmpConstants.OperationCodeTcp : PmpConstants.OperationCodeUdp);
+ package.Add(0); //reserved
+ package.Add(0); //reserved
+ package.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short) mapping.PrivatePort)));
+ package.AddRange(
+ BitConverter.GetBytes(create ? IPAddress.HostToNetworkOrder((short) mapping.PublicPort) : (short) 0));
+ package.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(mapping.Lifetime)));
+
+ try
+ {
+ byte[] buffer = package.ToArray();
+ int attempt = 0;
+ int delay = PmpConstants.RetryDelay;
+
+ using (var udpClient = new UdpClient())
+ {
+ CreatePortMapListen(udpClient, mapping);
+
+ while (attempt < PmpConstants.RetryAttempts)
+ {
+ await
+ udpClient.SendAsync(buffer, buffer.Length,
+ new IPEndPoint(LocalAddress, PmpConstants.ServerPort));
+
+ attempt++;
+ delay *= 2;
+ Thread.Sleep(delay);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ string type = create ? "create" : "delete";
+ string message = String.Format("Failed to {0} portmap (protocol={1}, private port={2})",
+ type,
+ mapping.Protocol,
+ mapping.PrivatePort);
+ NatDiscoverer.TraceSource.LogError(message);
+ var pmpException = e as MappingException;
+ throw new MappingException(message, pmpException);
+ }
+
+ return mapping;
+ }
+
+ private void CreatePortMapListen(UdpClient udpClient, Mapping mapping)
+ {
+ var endPoint = new IPEndPoint(LocalAddress, PmpConstants.ServerPort);
+
+ while (true)
+ {
+ byte[] data = udpClient.Receive(ref endPoint);
+
+ if (data.Length < 16)
+ continue;
+
+ if (data[0] != PmpConstants.Version)
+ continue;
+
+ var opCode = (byte) (data[1] & 127);
+
+ var protocol = Protocol.Tcp;
+ if (opCode == PmpConstants.OperationCodeUdp)
+ protocol = Protocol.Udp;
+
+ short resultCode = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data, 2));
+ int epoch = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data, 4));
+
+ short privatePort = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data, 8));
+ short publicPort = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data, 10));
+
+ var lifetime = (uint) IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data, 12));
+
+ if (privatePort < 0 || publicPort < 0 || resultCode != PmpConstants.ResultCodeSuccess)
+ {
+ var errors = new[]
+ {
+ "Success",
+ "Unsupported Version",
+ "Not Authorized/Refused (e.g. box supports mapping, but user has turned feature off)"
+ ,
+ "Network Failure (e.g. NAT box itself has not obtained a DHCP lease)",
+ "Out of resources (NAT box cannot create any more mappings at this time)",
+ "Unsupported opcode"
+ };
+ throw new MappingException(resultCode, errors[resultCode]);
+ }
+
+ if (lifetime == 0) return; //mapping was deleted
+
+ //mapping was created
+ //TODO: verify that the private port+protocol are a match
+ mapping.PublicPort = publicPort;
+ mapping.Protocol = protocol;
+ mapping.Expiration = DateTime.Now.AddSeconds(lifetime);
+ return;
+ }
+ }
+
+
+ public override string ToString()
+ {
+ return String.Format("Local Address: {0}\nPublic IP: {1}\nLast Seen: {2}",
+ LocalAddress, _publicAddress, LastSeen);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Pmp/PmpSearcher.cs b/Open.NAT/Open.Nat/Pmp/PmpSearcher.cs
new file mode 100644
index 0000000..7f64322
--- /dev/null
+++ b/Open.NAT/Open.Nat/Pmp/PmpSearcher.cs
@@ -0,0 +1,145 @@
+//
+// Authors:
+// Ben Motmans
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2007 Ben Motmans
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+
+namespace Open.Nat
+{
+ internal class PmpSearcher : Searcher
+ {
+ private readonly IIPAddressesProvider _ipprovider;
+ private Dictionary> _gatewayLists;
+ private int _timeout;
+
+ internal PmpSearcher(IIPAddressesProvider ipprovider)
+ {
+ _ipprovider = ipprovider;
+ _timeout = 250;
+ CreateSocketsAndAddGateways();
+ }
+
+ private void CreateSocketsAndAddGateways()
+ {
+ Sockets = new List();
+ _gatewayLists = new Dictionary>();
+
+ try
+ {
+ List gatewayList = _ipprovider.GatewayAddresses()
+ .Select(ip => new IPEndPoint(ip, PmpConstants.ServerPort))
+ .ToList();
+
+ if (!gatewayList.Any())
+ {
+ gatewayList.AddRange(
+ _ipprovider.DnsAddresses()
+ .Select(ip => new IPEndPoint(ip, PmpConstants.ServerPort)));
+ }
+
+ if (!gatewayList.Any()) return;
+
+ foreach (IPAddress address in _ipprovider.UnicastAddresses())
+ {
+ UdpClient client;
+
+ try
+ {
+ client = new UdpClient(new IPEndPoint(address, 0));
+ }
+ catch (SocketException)
+ {
+ continue; // Move on to the next address.
+ }
+
+ _gatewayLists.Add(client, gatewayList);
+ Sockets.Add(client);
+ }
+ }
+ catch (Exception e)
+ {
+ NatDiscoverer.TraceSource.LogError("There was a problem finding gateways: " + e);
+ // NAT-PMP does not use multicast, so there isn't really a good fallback.
+ }
+ }
+
+ protected override void Discover(UdpClient client, CancellationToken cancelationToken)
+ {
+ // Sort out the time for the next search first. The spec says the
+ // timeout should double after each attempt. Once it reaches 64 seconds
+ // (and that attempt fails), assume no devices available
+ NextSearch = DateTime.UtcNow.AddMilliseconds(_timeout);
+ _timeout *= 2;
+
+ if (_timeout >= 3000)
+ {
+ _timeout = 250;
+ NextSearch = DateTime.UtcNow.AddSeconds(10);
+ return;
+ }
+
+ // The nat-pmp search message. Must be sent to GatewayIP:53531
+ var buffer = new[] {PmpConstants.Version, PmpConstants.OperationExternalAddressRequest};
+ foreach (IPEndPoint gatewayEndpoint in _gatewayLists[client])
+ {
+ if (cancelationToken.IsCancellationRequested) return;
+
+ client.Send(buffer, buffer.Length, gatewayEndpoint);
+ }
+ }
+
+ private bool IsSearchAddress(IPAddress address)
+ {
+ return _gatewayLists.Values.SelectMany(x => x)
+ .Any(x => x.Address.Equals(address));
+ }
+
+ public override NatDevice AnalyseReceivedResponse(IPAddress localAddress, byte[] response, IPEndPoint endpoint)
+ {
+ if (!IsSearchAddress(endpoint.Address)
+ || response.Length != 12
+ || response[0] != PmpConstants.Version
+ || response[1] != PmpConstants.ServerNoop)
+ return null;
+
+ int errorcode = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(response, 2));
+ if (errorcode != 0)
+ NatDiscoverer.TraceSource.LogError("Non zero error: {0}", errorcode);
+
+ var publicIp = new IPAddress(new[] {response[8], response[9], response[10], response[11]});
+ //NextSearch = DateTime.Now.AddMinutes(5);
+
+ _timeout = 250;
+ return new PmpNatDevice(endpoint.Address, publicIp);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/PortMapper.cs b/Open.NAT/Open.Nat/PortMapper.cs
new file mode 100644
index 0000000..35abd7e
--- /dev/null
+++ b/Open.NAT/Open.Nat/PortMapper.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Open.Nat
+{
+ ///
+ /// Protocol that should be used for searching a NAT device.
+ ///
+ [Flags]
+ public enum PortMapper
+ {
+ ///
+ /// Use only Port Mapping Protocol
+ ///
+ Pmp = 1,
+
+ ///
+ /// Use only Universal Plug and Play
+ ///
+ Upnp = 2
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/DiscoveryResponseMessage.cs b/Open.NAT/Open.Nat/Upnp/DiscoveryResponseMessage.cs
new file mode 100644
index 0000000..692dcb9
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/DiscoveryResponseMessage.cs
@@ -0,0 +1,55 @@
+//
+// Authors:
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace Open.Nat
+{
+ class DiscoveryResponseMessage
+ {
+ private readonly IDictionary _headers;
+
+ public DiscoveryResponseMessage(string message)
+ {
+ var lines = message.Split(new[]{"\r\n"}, StringSplitOptions.RemoveEmptyEntries);
+ var headers = from h in lines.Skip(1)
+ let c = h.Split(':')
+ let key = c[0]
+ let value = c.Length > 1
+ ? string.Join(":", c.Skip(1))
+ : string.Empty
+ select new {Key = key, Value = value.Trim()};
+ _headers = headers.ToDictionary(x => x.Key.ToUpperInvariant(), x => x.Value);
+ }
+
+ public string this[string key]
+ {
+ get { return _headers[key.ToUpperInvariant()]; }
+ }
+ }
+}
diff --git a/Open.NAT/Open.Nat/Upnp/Messages/DiscoverDeviceMessage.cs b/Open.NAT/Open.Nat/Upnp/Messages/DiscoverDeviceMessage.cs
new file mode 100644
index 0000000..5a358b5
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/Messages/DiscoverDeviceMessage.cs
@@ -0,0 +1,51 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Globalization;
+
+namespace Open.Nat
+{
+ internal static class DiscoverDeviceMessage
+ {
+ ///
+ /// The message sent to discover all uPnP devices on the network
+ ///
+ ///
+ public static string Encode(string serviceType)
+ {
+ const string s = "M-SEARCH * HTTP/1.1\r\n"
+ + "HOST: 239.255.255.250:1900\r\n"
+ + "MAN: \"ssdp:discover\"\r\n"
+ + "MX: 3\r\n"
+ // + "ST: urn:schemas-upnp-org:service:WANIPConnection:1\r\n\r\n";
+ + "ST: urn:schemas-upnp-org:service:{0}\r\n\r\n";
+ //+ "ST:upnp:rootdevice\r\n\r\n";
+
+ string ss = string.Format(CultureInfo.InvariantCulture, s, serviceType);
+ return ss;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/Messages/Requests/CreatePortMappingMessage.cs b/Open.NAT/Open.Nat/Upnp/Messages/Requests/CreatePortMappingMessage.cs
new file mode 100644
index 0000000..cf37329
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/Messages/Requests/CreatePortMappingMessage.cs
@@ -0,0 +1,62 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections.Generic;
+using System.Net;
+
+namespace Open.Nat
+{
+ internal class CreatePortMappingRequestMessage : RequestMessageBase
+ {
+ private readonly Mapping _mapping;
+
+ public CreatePortMappingRequestMessage(Mapping mapping)
+ {
+ _mapping = mapping;
+ }
+
+ public override IDictionary ToXml()
+ {
+ string remoteHost = _mapping.PublicIP.Equals(IPAddress.None)
+ ? string.Empty
+ : _mapping.PublicIP.ToString();
+
+ return new Dictionary
+ {
+ {"NewRemoteHost", remoteHost},
+ {"NewExternalPort", _mapping.PublicPort},
+ {"NewProtocol", _mapping.Protocol == Protocol.Tcp ? "TCP" : "UDP"},
+ {"NewInternalPort", _mapping.PrivatePort},
+ {"NewInternalClient", _mapping.PrivateIP},
+ {"NewEnabled", 1},
+ {"NewPortMappingDescription", _mapping.Description},
+ {"NewLeaseDuration", _mapping.Lifetime}
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/Messages/Requests/DeletePortMappingMessage.cs b/Open.NAT/Open.Nat/Upnp/Messages/Requests/DeletePortMappingMessage.cs
new file mode 100644
index 0000000..33aa02f
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/Messages/Requests/DeletePortMappingMessage.cs
@@ -0,0 +1,52 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections.Generic;
+
+namespace Open.Nat
+{
+ internal class DeletePortMappingRequestMessage : RequestMessageBase
+ {
+ private readonly Mapping _mapping;
+
+ public DeletePortMappingRequestMessage(Mapping mapping)
+ {
+ _mapping = mapping;
+ }
+
+ public override IDictionary ToXml()
+ {
+ return new Dictionary
+ {
+ {"NewRemoteHost", string.Empty},
+ {"NewExternalPort", _mapping.PublicPort},
+ {"NewProtocol", _mapping.Protocol == Protocol.Tcp ? "TCP" : "UDP"}
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/Messages/Requests/GetExternalIPAddressMessage.cs b/Open.NAT/Open.Nat/Upnp/Messages/Requests/GetExternalIPAddressMessage.cs
new file mode 100644
index 0000000..3ae17a4
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/Messages/Requests/GetExternalIPAddressMessage.cs
@@ -0,0 +1,40 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections.Generic;
+
+namespace Open.Nat
+{
+ internal class GetExternalIPAddressRequestMessage : RequestMessageBase
+ {
+ public override IDictionary ToXml()
+ {
+ return new Dictionary();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/Messages/Requests/GetGenericPortMappingEntry.cs b/Open.NAT/Open.Nat/Upnp/Messages/Requests/GetGenericPortMappingEntry.cs
new file mode 100644
index 0000000..cd612dd
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/Messages/Requests/GetGenericPortMappingEntry.cs
@@ -0,0 +1,50 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections.Generic;
+
+namespace Open.Nat
+{
+ internal class GetGenericPortMappingEntry : RequestMessageBase
+ {
+ private readonly int _index;
+
+ public GetGenericPortMappingEntry(int index)
+ {
+ _index = index;
+ }
+
+ public override IDictionary ToXml()
+ {
+ return new Dictionary
+ {
+ {"NewPortMappingIndex", _index}
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/Messages/Requests/GetSpecificPortMappingEntryMessage.cs b/Open.NAT/Open.Nat/Upnp/Messages/Requests/GetSpecificPortMappingEntryMessage.cs
new file mode 100644
index 0000000..d7d4191
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/Messages/Requests/GetSpecificPortMappingEntryMessage.cs
@@ -0,0 +1,54 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections.Generic;
+
+namespace Open.Nat
+{
+ internal class GetSpecificPortMappingEntryRequestMessage : RequestMessageBase
+ {
+ private readonly int _externalPort;
+ private readonly Protocol _protocol;
+
+ public GetSpecificPortMappingEntryRequestMessage(Protocol protocol, int externalPort)
+ {
+ _protocol = protocol;
+ _externalPort = externalPort;
+ }
+
+ public override IDictionary ToXml()
+ {
+ return new Dictionary
+ {
+ {"NewRemoteHost", string.Empty},
+ {"NewExternalPort", _externalPort},
+ {"NewProtocol", _protocol == Protocol.Tcp ? "TCP" : "UDP"}
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/Messages/Responses/AddPortMappingResponseMessage.cs b/Open.NAT/Open.Nat/Upnp/Messages/Responses/AddPortMappingResponseMessage.cs
new file mode 100644
index 0000000..fead7eb
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/Messages/Responses/AddPortMappingResponseMessage.cs
@@ -0,0 +1,32 @@
+//
+// Authors:
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace Open.Nat
+{
+ internal class AddPortMappingResponseMessage : ResponseMessageBase
+ {
+ }
+}
diff --git a/Open.NAT/Open.Nat/Upnp/Messages/Responses/DeletePortMappingResponseMessage.cs b/Open.NAT/Open.Nat/Upnp/Messages/Responses/DeletePortMappingResponseMessage.cs
new file mode 100644
index 0000000..705c08c
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/Messages/Responses/DeletePortMappingResponseMessage.cs
@@ -0,0 +1,32 @@
+//
+// Authors:
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace Open.Nat
+{
+ internal class DeletePortMappingResponseMessage : ResponseMessageBase
+ {
+ }
+}
diff --git a/Open.NAT/Open.Nat/Upnp/Messages/Responses/GetExternalIPAddressResponseMessage.cs b/Open.NAT/Open.Nat/Upnp/Messages/Responses/GetExternalIPAddressResponseMessage.cs
new file mode 100644
index 0000000..4d56355
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/Messages/Responses/GetExternalIPAddressResponseMessage.cs
@@ -0,0 +1,45 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Net;
+using System.Xml;
+
+namespace Open.Nat
+{
+ internal class GetExternalIPAddressResponseMessage : ResponseMessageBase
+ {
+ public GetExternalIPAddressResponseMessage(XmlDocument response, string serviceType)
+ : base(response, serviceType, "GetExternalIPAddressResponseMessage")
+ {
+ string ip = GetNode().GetXmlElementText("NewExternalIPAddress");
+ ExternalIPAddress = IPAddress.Parse(ip);
+ }
+
+ public IPAddress ExternalIPAddress { get; private set; }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/Messages/Responses/GetGenericPortMappingEntryResponseMessage.cs b/Open.NAT/Open.Nat/Upnp/Messages/Responses/GetGenericPortMappingEntryResponseMessage.cs
new file mode 100644
index 0000000..22c473c
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/Messages/Responses/GetGenericPortMappingEntryResponseMessage.cs
@@ -0,0 +1,66 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Xml;
+
+namespace Open.Nat
+{
+ internal class GetPortMappingEntryResponseMessage : ResponseMessageBase
+ {
+ internal GetPortMappingEntryResponseMessage(XmlDocument response, string serviceType, bool genericMapping)
+ : base(response, serviceType, genericMapping ? "GetGenericPortMappingEntryResponseMessage" : "GetSpecificPortMappingEntryResponseMessage")
+ {
+ XmlNode data = GetNode();
+
+ RemoteHost = (genericMapping) ? data.GetXmlElementText("NewRemoteHost") : string.Empty;
+ ExternalPort = (genericMapping) ? Convert.ToInt32(data.GetXmlElementText("NewExternalPort")) : ushort.MaxValue;
+ if (genericMapping)
+ Protocol = data.GetXmlElementText("NewProtocol").Equals("TCP", StringComparison.InvariantCultureIgnoreCase)
+ ? Protocol.Tcp
+ : Protocol.Udp;
+ else
+ Protocol = Protocol.Udp;
+
+ InternalPort = Convert.ToInt32(data.GetXmlElementText("NewInternalPort"));
+ InternalClient = data.GetXmlElementText("NewInternalClient");
+ Enabled = data.GetXmlElementText("NewEnabled") == "1";
+ PortMappingDescription = data.GetXmlElementText("NewPortMappingDescription");
+ LeaseDuration = Convert.ToInt32(data.GetXmlElementText("NewLeaseDuration"));
+ }
+
+ public string RemoteHost { get; private set; }
+ public int ExternalPort { get; private set; }
+ public Protocol Protocol { get; private set; }
+ public int InternalPort { get; private set; }
+ public string InternalClient { get; private set; }
+ public bool Enabled { get; private set; }
+ public string PortMappingDescription { get; private set; }
+ public int LeaseDuration { get; private set; }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/RequestMessageBase.cs b/Open.NAT/Open.Nat/Upnp/RequestMessageBase.cs
new file mode 100644
index 0000000..ad2384c
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/RequestMessageBase.cs
@@ -0,0 +1,37 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections.Generic;
+
+namespace Open.Nat
+{
+ internal abstract class RequestMessageBase
+ {
+ public abstract IDictionary ToXml();
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/ResponseMessageBase.cs b/Open.NAT/Open.Nat/Upnp/ResponseMessageBase.cs
new file mode 100644
index 0000000..b6f3edb
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/ResponseMessageBase.cs
@@ -0,0 +1,58 @@
+//
+// Authors:
+// Lucas Ontivero lucas.ontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Xml;
+
+namespace Open.Nat
+{
+ internal abstract class ResponseMessageBase
+ {
+ private readonly XmlDocument _document;
+ protected string ServiceType;
+ private readonly string _typeName;
+
+ protected ResponseMessageBase(XmlDocument response, string serviceType, string typeName)
+ {
+ _document = response;
+ ServiceType = serviceType;
+ _typeName = typeName;
+ }
+
+ protected XmlNode GetNode()
+ {
+ var nsm = new XmlNamespaceManager(_document.NameTable);
+ nsm.AddNamespace("responseNs", ServiceType);
+
+ string typeName = _typeName;
+ string messageName = typeName.Substring(0, typeName.Length - "Message".Length);
+ XmlNode node = _document.SelectSingleNode("//responseNs:" + messageName, nsm);
+ if (node == null) throw new InvalidOperationException("The response is invalid: " + messageName);
+
+ return node;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/SoapClient.cs b/Open.NAT/Open.Nat/Upnp/SoapClient.cs
new file mode 100644
index 0000000..94e9d09
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/SoapClient.cs
@@ -0,0 +1,161 @@
+//
+// Authors:
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml;
+
+namespace Open.Nat
+{
+ internal class SoapClient
+ {
+ private readonly string _serviceType;
+ private readonly Uri _url;
+
+ public SoapClient(Uri url, string serviceType)
+ {
+ _url = url;
+ _serviceType = serviceType;
+ }
+
+ public async Task InvokeAsync(string operationName, IDictionary args)
+ {
+ NatDiscoverer.TraceSource.TraceEvent(TraceEventType.Verbose, 0, "SOAPACTION: **{0}** url:{1}", operationName,
+ _url);
+ byte[] messageBody = BuildMessageBody(operationName, args);
+ HttpWebRequest request = BuildHttpWebRequest(operationName, messageBody);
+
+ if (messageBody.Length > 0)
+ {
+ using (var stream = await request.GetRequestStreamAsync())
+ {
+ await stream.WriteAsync(messageBody, 0, messageBody.Length);
+ }
+ }
+
+ using(var response = await GetWebResponse(request))
+ {
+ var stream = response.GetResponseStream();
+ var contentLength = response.ContentLength;
+
+ var reader = new StreamReader(stream, Encoding.UTF8);
+
+ var responseBody = contentLength != -1
+ ? reader.ReadAsMany((int) contentLength)
+ : reader.ReadToEnd();
+
+ var responseXml = GetXmlDocument(responseBody);
+ NatDiscoverer.TraceSource.TraceEvent(TraceEventType.Verbose, 0, "Response: \n{0}", responseXml.ToPrintableXml());
+
+ response.Close();
+ return responseXml;
+ }
+ }
+
+ private static async Task GetWebResponse(WebRequest request)
+ {
+ WebResponse response;
+ try
+ {
+ response = await request.GetResponseAsync();
+ }
+ catch (WebException ex)
+ {
+ NatDiscoverer.TraceSource.TraceEvent(TraceEventType.Verbose, 0, "WebException status: {0}", ex.Status);
+
+ // Even if the request "failed" we need to continue reading the response from the router
+ response = ex.Response as HttpWebResponse;
+
+ if (response == null)
+ throw;
+ }
+ return response;
+ }
+
+ private HttpWebRequest BuildHttpWebRequest(string operationName, byte[] messageBody)
+ {
+ var request = WebRequest.CreateHttp(_url);
+ request.KeepAlive = false;
+ request.Method = "POST";
+ request.ContentType = "text/xml; charset=\"utf-8\"";
+ request.Headers.Add("SOAPACTION", "\"" + _serviceType + "#" + operationName + "\"");
+ request.ContentLength = messageBody.Length;
+ return request;
+ }
+
+ private byte[] BuildMessageBody(string operationName, IEnumerable> args)
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine("");
+ sb.AppendLine(" ");
+ sb.AppendLine(" ");
+ foreach (var a in args)
+ {
+ sb.AppendLine(" <" + a.Key + ">" + Convert.ToString(a.Value, CultureInfo.InvariantCulture) +
+ "" + a.Key + ">");
+ }
+ sb.AppendLine(" ");
+ sb.AppendLine(" ");
+ sb.Append("\r\n\r\n");
+ string requestBody = sb.ToString();
+
+ NatDiscoverer.TraceSource.TraceEvent(TraceEventType.Verbose, 0, requestBody);
+ byte[] messageBody = Encoding.UTF8.GetBytes(requestBody);
+ return messageBody;
+ }
+
+ private XmlDocument GetXmlDocument(string response)
+ {
+ XmlNode node;
+ var doc = new XmlDocument();
+ doc.LoadXml(response);
+
+ var nsm = new XmlNamespaceManager(doc.NameTable);
+
+ // Error messages should be found under this namespace
+ nsm.AddNamespace("errorNs", "urn:schemas-upnp-org:control-1-0");
+
+ // Check to see if we have a fault code message.
+ if ((node = doc.SelectSingleNode("//errorNs:UPnPError", nsm)) != null)
+ {
+ int code = Convert.ToInt32(node.GetXmlElementText("errorCode"), CultureInfo.InvariantCulture);
+ string errorMessage = node.GetXmlElementText("errorDescription");
+ NatDiscoverer.TraceSource.LogWarn("Server failed with error: {0} - {1}", code, errorMessage);
+ throw new MappingException(code, errorMessage);
+ }
+
+ return doc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/UpnpConstants.cs b/Open.NAT/Open.Nat/Upnp/UpnpConstants.cs
new file mode 100644
index 0000000..71dd20e
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/UpnpConstants.cs
@@ -0,0 +1,46 @@
+//
+// Authors:
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace Open.Nat
+{
+ internal static class UpnpConstants
+ {
+ public const int InvalidArguments = 402;
+ public const int ActionFailed = 501;
+ public const int Unathorized = 606;
+ public const int SpecifiedArrayIndexInvalid = 713;
public const int NoSuchEntryInArray = 714;
+ public const int WildCardNotPermittedInSourceIp = 715;
+ public const int WildCardNotPermittedInExternalPort = 716;
+ public const int ConflictInMappingEntry = 718;
+ public const int SamePortValuesRequired = 724;
+ public const int OnlyPermanentLeasesSupported = 725;
+ public const int RemoteHostOnlySupportsWildcard = 726;
+ public const int ExternalPortOnlySupportsWildcard = 727;
+ public const int NoPortMapsAvailable = 728;
+ public const int ConflictWithOtherMechanisms = 729;
+ public const int WildCardNotPermittedInIntPort = 732;
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/UpnpNatDevice.cs b/Open.NAT/Open.Nat/Upnp/UpnpNatDevice.cs
new file mode 100644
index 0000000..0011d73
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/UpnpNatDevice.cs
@@ -0,0 +1,198 @@
+//
+// Authors:
+// Alan McGovern alan.mcgovern@gmail.com
+// Ben Motmans
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2006 Alan McGovern
+// Copyright (C) 2007 Ben Motmans
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Threading.Tasks;
+
+namespace Open.Nat
+{
+ internal sealed class UpnpNatDevice : NatDevice
+ {
+ internal readonly UpnpNatDeviceInfo DeviceInfo;
+ private readonly SoapClient _soapClient;
+
+ internal UpnpNatDevice (UpnpNatDeviceInfo deviceInfo)
+ {
+ Touch();
+ DeviceInfo = deviceInfo;
+ _soapClient = new SoapClient(DeviceInfo.ServiceControlUri, DeviceInfo.ServiceType);
+ }
+
+ public override async Task GetExternalIPAsync()
+ {
+ var message = new GetExternalIPAddressRequestMessage();
+ var responseData = await _soapClient
+ .InvokeAsync("GetExternalIPAddress", message.ToXml())
+ .TimeoutAfter(TimeSpan.FromSeconds(4));
+
+ var response = new GetExternalIPAddressResponseMessage(responseData, DeviceInfo.ServiceType);
+ return response.ExternalIPAddress;
+ }
+
+ public override async Task CreatePortMapAsync(Mapping mapping)
+ {
+ Guard.IsNotNull(mapping, "mapping");
+
+ mapping.PrivateIP = DeviceInfo.LocalAddress;
+ try
+ {
+ var message = new CreatePortMappingRequestMessage(mapping);
+ await _soapClient
+ .InvokeAsync("AddPortMapping", message.ToXml())
+ .TimeoutAfter(TimeSpan.FromSeconds(4));
+ RegisterMapping(mapping);
+ }
+ catch(MappingException me)
+ {
+ switch (me.ErrorCode)
+ {
+ case UpnpConstants.OnlyPermanentLeasesSupported:
+ NatDiscoverer.TraceSource.LogWarn("Only Permanent Leases Supported - There is no warranty it will be closed");
+ mapping.Lifetime = 0;
+ // We create the mapping anyway. It must be released on shutdown.
+ mapping.LifetimeType = MappingLifetime.ForcedSession;
+ CreatePortMapAsync(mapping);
+ break;
+ case UpnpConstants.SamePortValuesRequired:
+ NatDiscoverer.TraceSource.LogWarn("Same Port Values Required - Using internal port {0}", mapping.PrivatePort);
+ mapping.PublicPort = mapping.PrivatePort;
+ CreatePortMapAsync(mapping);
+ break;
+ case UpnpConstants.RemoteHostOnlySupportsWildcard:
+ NatDiscoverer.TraceSource.LogWarn("Remote Host Only Supports Wildcard");
+ mapping.PublicIP = IPAddress.None;
+ CreatePortMapAsync(mapping);
+ break;
+ case UpnpConstants.ExternalPortOnlySupportsWildcard:
+ NatDiscoverer.TraceSource.LogWarn("External Port Only Supports Wildcard");
+ throw;
+ case UpnpConstants.ConflictInMappingEntry:
+ NatDiscoverer.TraceSource.LogWarn("Conflict with an already existing mapping");
+ throw;
+
+ default:
+ throw;
+ }
+ }
+ }
+
+ public override async Task DeletePortMapAsync(Mapping mapping)
+ {
+ Guard.IsNotNull(mapping, "mapping");
+
+ try
+ {
+ var message = new DeletePortMappingRequestMessage(mapping);
+ await _soapClient
+ .InvokeAsync("DeletePortMapping", message.ToXml())
+ .TimeoutAfter(TimeSpan.FromSeconds(4));
+ UnregisterMapping(mapping);
+ }
+ catch (MappingException e)
+ {
+ if(e.ErrorCode != UpnpConstants.NoSuchEntryInArray) throw;
+ }
+ }
+
+ public override async Task> GetAllMappingsAsync()
+ {
+ var index = 0;
+ var mappings = new List();
+
+ while (true)
+ {
+ try
+ {
+ var message = new GetGenericPortMappingEntry(index);
+
+ var responseData = await _soapClient
+ .InvokeAsync("GetGenericPortMappingEntry", message.ToXml())
+ .TimeoutAfter(TimeSpan.FromSeconds(4));
+
+ var responseMessage = new GetPortMappingEntryResponseMessage(responseData, DeviceInfo.ServiceType, true);
+
+ var mapping = new Mapping(responseMessage.Protocol
+ , IPAddress.Parse(responseMessage.InternalClient)
+ , responseMessage.InternalPort
+ , responseMessage.ExternalPort
+ , responseMessage.LeaseDuration
+ , responseMessage.PortMappingDescription);
+ mappings.Add(mapping);
+ index++;
+ }
+ catch (MappingException e)
+ {
+ if (e.ErrorCode == UpnpConstants.SpecifiedArrayIndexInvalid) break; // there are no more mappings
+ throw;
+ }
+ }
+
+ return mappings.ToArray();
+ }
+
+ public override async Task GetSpecificMappingAsync (Protocol protocol, int port)
+ {
+ Guard.IsTrue(protocol == Protocol.Tcp || protocol == Protocol.Udp, "protocol");
+ Guard.IsInRange(port, 0, ushort.MaxValue, "port");
+
+ try
+ {
+ var message = new GetSpecificPortMappingEntryRequestMessage(protocol, port);
+ var responseData = await _soapClient
+ .InvokeAsync("GetSpecificPortMappingEntry", message.ToXml())
+ .TimeoutAfter(TimeSpan.FromSeconds(4));
+
+ var messageResponse = new GetPortMappingEntryResponseMessage(responseData, DeviceInfo.ServiceType, false);
+
+ return new Mapping(messageResponse.Protocol
+ , IPAddress.Parse(messageResponse.InternalClient)
+ , messageResponse.InternalPort
+ , messageResponse.ExternalPort
+ , messageResponse.LeaseDuration
+ , messageResponse.PortMappingDescription);
+ }
+ catch (MappingException e)
+ {
+ if (e.ErrorCode != UpnpConstants.NoSuchEntryInArray) throw;
+ return null;
+ }
+ }
+
+ public override string ToString( )
+ {
+ //GetExternalIP is blocking and can throw exceptions, can't use it here.
+ return String.Format(
+ "EndPoint: {0}\nControl Url: {1}\nService Type: {2}\nLast Seen: {3}",
+ DeviceInfo.HostEndPoint, DeviceInfo.ServiceControlUri, DeviceInfo.ServiceType, LastSeen);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/UpnpNatDeviceInfo.cs b/Open.NAT/Open.Nat/Upnp/UpnpNatDeviceInfo.cs
new file mode 100644
index 0000000..e0665ab
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/UpnpNatDeviceInfo.cs
@@ -0,0 +1,60 @@
+//
+// Authors:
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Net;
+
+namespace Open.Nat
+{
+ internal class UpnpNatDeviceInfo
+ {
+ public UpnpNatDeviceInfo(IPAddress localAddress, Uri locationUri, string serviceControlUrl, string serviceType)
+ {
+ LocalAddress = localAddress;
+ ServiceType = serviceType;
+ HostEndPoint = new IPEndPoint(IPAddress.Parse(locationUri.Host), locationUri.Port);
+
+ if (Uri.IsWellFormedUriString(serviceControlUrl, UriKind.Absolute))
+ {
+ var u = new Uri(serviceControlUrl);
+ IPEndPoint old = HostEndPoint;
+ serviceControlUrl = serviceControlUrl.Substring(u.GetLeftPart(UriPartial.Authority).Length);
+
+ NatDiscoverer.TraceSource.LogInfo("{0}: Absolute URI detected. Host address is now: {1}", old,
+ HostEndPoint);
+ NatDiscoverer.TraceSource.LogInfo("{0}: New control url: {1}", HostEndPoint, serviceControlUrl);
+ }
+
+ var builder = new UriBuilder("http", locationUri.Host, locationUri.Port, serviceControlUrl);
+ ServiceControlUri = builder.Uri;
+ }
+
+ public IPEndPoint HostEndPoint { get; private set; }
+ public IPAddress LocalAddress { get; private set; }
+ public string ServiceType { get; private set; }
+ public Uri ServiceControlUri { get; private set; }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Upnp/UpnpSearcher.cs b/Open.NAT/Open.Nat/Upnp/UpnpSearcher.cs
new file mode 100644
index 0000000..89f66bd
--- /dev/null
+++ b/Open.NAT/Open.Nat/Upnp/UpnpSearcher.cs
@@ -0,0 +1,268 @@
+//
+// Authors:
+// Ben Motmans
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2007 Ben Motmans
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Net;
+using System.Diagnostics;
+using System.Net.Sockets;
+using System.Threading;
+using System.Xml;
+
+namespace Open.Nat
+{
+ internal class UpnpSearcher : Searcher
+ {
+ private readonly IIPAddressesProvider _ipprovider;
+ private readonly IDictionary _devices;
+ private readonly Dictionary _lastFetched;
+ private static readonly string[] ServiceTypes = new[]{
+ "WANIPConnection:2",
+ "WANPPPConnection:2",
+ "WANIPConnection:1",
+ "WANPPPConnection:1"
+ };
+
+ internal UpnpSearcher(IIPAddressesProvider ipprovider)
+ {
+ _ipprovider = ipprovider;
+ Sockets = CreateSockets();
+ _devices = new Dictionary();
+ _lastFetched = new Dictionary();
+ }
+
+ private List CreateSockets()
+ {
+ var clients = new List();
+ try
+ {
+ var ips = _ipprovider.UnicastAddresses();
+
+ foreach (var ipAddress in ips)
+ {
+ try
+ {
+ clients.Add(new UdpClient(new IPEndPoint(ipAddress, 0)));
+ }
+ catch (Exception)
+ {
+ continue; // Move on to the next address.
+ }
+ }
+ }
+ catch (Exception)
+ {
+ clients.Add(new UdpClient(0));
+ }
+ return clients;
+ }
+
+ protected override void Discover(UdpClient client, CancellationToken cancelationToken)
+ {
+ NextSearch = DateTime.UtcNow.AddSeconds(1);
+ var searchEndpoint = new IPEndPoint(
+ WellKnownConstants.IPv4MulticastAddress
+ /*IPAddress.Broadcast*/
+ , 1900);
+
+ foreach (var serviceType in ServiceTypes)
+ {
+ var datax = DiscoverDeviceMessage.Encode(serviceType);
+ var data = Encoding.ASCII.GetBytes(datax);
+
+ // UDP is unreliable, so send 3 requests at a time (per Upnp spec, sec 1.1.2)
+ // Yes, however it works perfectly well with just 1 request.
+ for (var i = 0; i < 2; i++)
+ {
+ if (cancelationToken.IsCancellationRequested) return;
+ client.Send(data, data.Length, searchEndpoint);
+ }
+ }
+ }
+
+ public override NatDevice AnalyseReceivedResponse(IPAddress localAddress, byte[] response, IPEndPoint endpoint)
+ {
+ // Convert it to a string for easy parsing
+ string dataString = null;
+
+ // No matter what, this method should never throw an exception. If something goes wrong
+ // we should still be in a position to handle the next reply correctly.
+ try
+ {
+ dataString = Encoding.UTF8.GetString(response);
+ var message = new DiscoveryResponseMessage(dataString);
+ var serviceType = message["ST"];
+
+ NatDiscoverer.TraceSource.TraceEvent(TraceEventType.Verbose, 0, "UPnP Response: {0}", dataString);
+
+ if (!IsValidControllerService(serviceType)) return null;
+ NatDiscoverer.TraceSource.LogInfo("UPnP Response: Router advertised a '{0}' service!!!", serviceType);
+
+ var location = message["Location"];
+ var locationUri = new Uri(location);
+
+ NatDiscoverer.TraceSource.LogInfo("Found device at: {0}", locationUri.ToString());
+
+ if (_devices.ContainsKey(locationUri))
+ {
+ NatDiscoverer.TraceSource.LogInfo("Already found - Ignored");
+ _devices[locationUri].Touch();
+ return null;
+ }
+
+ // If we send 3 requests at a time, ensure we only fetch the services list once
+ // even if three responses are received
+ if (_lastFetched.ContainsKey(endpoint.Address))
+ {
+ var last = _lastFetched[endpoint.Address];
+ if ((DateTime.Now - last) < TimeSpan.FromSeconds(20))
+ return null;
+ }
+ _lastFetched[endpoint.Address] = DateTime.Now;
+
+ NatDiscoverer.TraceSource.LogInfo("{0}:{1}: Fetching service list", locationUri.Host, locationUri.Port );
+
+ var deviceInfo = BuildUpnpNatDeviceInfo(localAddress, locationUri);
+
+ UpnpNatDevice device;
+ lock (_devices)
+ {
+ device = new UpnpNatDevice(deviceInfo);
+ if (!_devices.ContainsKey(locationUri))
+ {
+ _devices.Add(locationUri, device);
+ }
+ }
+ return device;
+ }
+ catch (Exception ex)
+ {
+ NatDiscoverer.TraceSource.LogError("Unhandled exception when trying to decode a device's response. ");
+ NatDiscoverer.TraceSource.LogError("Report the issue in https://github.com/lontivero/Open.Nat/issues");
+ NatDiscoverer.TraceSource.LogError("Also copy and paste the following info:");
+ NatDiscoverer.TraceSource.LogError("-- beging ---------------------------------");
+ NatDiscoverer.TraceSource.LogError(ex.Message);
+ NatDiscoverer.TraceSource.LogError("Data string:");
+ NatDiscoverer.TraceSource.LogError(dataString ?? "No data available");
+ NatDiscoverer.TraceSource.LogError("-- end ------------------------------------");
+ }
+ return null;
+ }
+
+ private static bool IsValidControllerService(string serviceType)
+ {
+ var services = from serviceName in ServiceTypes
+ let serviceUrn = string.Format("urn:schemas-upnp-org:service:{0}", serviceName)
+ where serviceType.ContainsIgnoreCase(serviceUrn)
+ select new {ServiceName = serviceName, ServiceUrn = serviceUrn};
+
+ return services.Any();
+ }
+
+ private UpnpNatDeviceInfo BuildUpnpNatDeviceInfo(IPAddress localAddress, Uri location)
+ {
+ NatDiscoverer.TraceSource.LogInfo("Found device at: {0}", location.ToString());
+
+ var hostEndPoint = new IPEndPoint(IPAddress.Parse(location.Host), location.Port);
+
+ WebResponse response = null;
+ try
+ {
+ var request = WebRequest.CreateHttp(location);
+ request.Headers.Add("ACCEPT-LANGUAGE", "en");
+ request.Method = "GET";
+
+ response = request.GetResponse();
+
+ var httpresponse = response as HttpWebResponse;
+
+ if (httpresponse != null && httpresponse.StatusCode != HttpStatusCode.OK)
+ {
+ var message = string.Format("Couldn't get services list: {0} {1}", httpresponse.StatusCode, httpresponse.StatusDescription);
+ throw new Exception(message);
+ }
+
+ var xmldoc = ReadXmlResponse(response);
+
+ NatDiscoverer.TraceSource.LogInfo("{0}: Parsed services list", hostEndPoint);
+
+ var ns = new XmlNamespaceManager(xmldoc.NameTable);
+ ns.AddNamespace("ns", "urn:schemas-upnp-org:device-1-0");
+ var services = xmldoc.SelectNodes("//ns:service", ns);
+
+ foreach (XmlNode service in services)
+ {
+ var serviceType = service.GetXmlElementText("serviceType");
+ if (!IsValidControllerService(serviceType)) continue;
+
+ NatDiscoverer.TraceSource.LogInfo("{0}: Found service: {1}", hostEndPoint, serviceType);
+
+ var serviceControlUrl = service.GetXmlElementText("controlURL");
+ NatDiscoverer.TraceSource.LogInfo("{0}: Found upnp service at: {1}", hostEndPoint, serviceControlUrl);
+
+ NatDiscoverer.TraceSource.LogInfo("{0}: Handshake Complete", hostEndPoint);
+ return new UpnpNatDeviceInfo(localAddress, location, serviceControlUrl, serviceType);
+ }
+
+ throw new Exception("No valid control service was found in the service descriptor document");
+ }
+ catch (WebException ex)
+ {
+ // Just drop the connection, FIXME: Should i retry?
+ NatDiscoverer.TraceSource.LogError("{0}: Device denied the connection attempt: {1}", hostEndPoint, ex);
+ var inner = ex.InnerException as SocketException;
+ if (inner != null)
+ {
+ NatDiscoverer.TraceSource.LogError("{0}: ErrorCode:{1}", hostEndPoint, inner.ErrorCode);
+ NatDiscoverer.TraceSource.LogError("Go to http://msdn.microsoft.com/en-us/library/system.net.sockets.socketerror.aspx");
+ NatDiscoverer.TraceSource.LogError("Usually this happens. Try resetting the device and try again. If you are in a VPN, disconnect and try again.");
+ }
+ throw;
+ }
+ finally
+ {
+ if (response != null)
+ response.Close();
+ }
+ }
+
+ private static XmlDocument ReadXmlResponse(WebResponse response)
+ {
+ using (var reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
+ {
+ var servicesXml = reader.ReadToEnd();
+ var xmldoc = new XmlDocument();
+ xmldoc.LoadXml(servicesXml);
+ return xmldoc;
+ }
+ }
+ }
+}
diff --git a/Open.NAT/Open.Nat/Utils/Extensions.cs b/Open.NAT/Open.Nat/Utils/Extensions.cs
new file mode 100644
index 0000000..565f203
--- /dev/null
+++ b/Open.NAT/Open.Nat/Utils/Extensions.cs
@@ -0,0 +1,121 @@
+//
+// Authors:
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Xml;
+
+namespace Open.Nat
+{
+ internal static class StreamExtensions
+ {
+ internal static string ReadAsMany(this StreamReader stream, int bytesToRead)
+ {
+ var buffer = new char[bytesToRead];
+ stream.ReadBlock(buffer, 0, bytesToRead);
+ return new string(buffer);
+ }
+
+ internal static string GetXmlElementText(this XmlNode node, string elementName)
+ {
+ XmlElement element = node[elementName];
+ return element != null ? element.InnerText : string.Empty;
+ }
+
+ internal static bool ContainsIgnoreCase(this string s, string pattern)
+ {
+ return s.IndexOf(pattern, StringComparison.OrdinalIgnoreCase) >= 0;
+ }
+
+ internal static void LogInfo(this TraceSource source, string format, params object[] args)
+ {
+ source.TraceEvent(TraceEventType.Information, 0, format, args);
+ }
+
+ internal static void LogWarn(this TraceSource source, string format, params object[] args)
+ {
+ source.TraceEvent(TraceEventType.Warning, 0, format, args);
+ }
+
+ internal static void LogError(this TraceSource source, string format, params object[] args)
+ {
+ source.TraceEvent(TraceEventType.Error, 0, format, args);
+ }
+
+ internal static string ToPrintableXml(this XmlDocument document)
+ {
+ using (var stream = new MemoryStream())
+ {
+ using (var writer = new XmlTextWriter(stream, Encoding.Unicode))
+ {
+ try
+ {
+ writer.Formatting = Formatting.Indented;
+
+ document.WriteContentTo(writer);
+ writer.Flush();
+ stream.Flush();
+
+ // Have to rewind the MemoryStream in order to read
+ // its contents.
+ stream.Position = 0;
+
+ // Read MemoryStream contents into a StreamReader.
+ var reader = new StreamReader(stream);
+
+ // Extract the text from the StreamReader.
+ return reader.ReadToEnd();
+ }
+ catch (Exception)
+ {
+ return document.ToString();
+ }
+ }
+ }
+ }
+
+ public static async Task TimeoutAfter(this Task task, TimeSpan timeout)
+ {
+#if DEBUG
+ return await task;
+#endif
+ var timeoutCancellationTokenSource = new CancellationTokenSource();
+
+ Task completedTask = await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token));
+ if (completedTask == task)
+ {
+ timeoutCancellationTokenSource.Cancel();
+ return await task;
+ }
+ throw new TimeoutException(
+ "The operation has timed out. The network is broken, router has gone or is too busy.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Utils/Guard.cs b/Open.NAT/Open.Nat/Utils/Guard.cs
new file mode 100644
index 0000000..1189ea1
--- /dev/null
+++ b/Open.NAT/Open.Nat/Utils/Guard.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Open.Nat
+{
+ internal class Guard
+ {
+ private Guard()
+ {
+ }
+
+ internal static void IsInRange(int paramValue, int lowerBound, int upperBound, string paramName)
+ {
+ if (paramValue < lowerBound || paramValue > upperBound)
+ throw new ArgumentOutOfRangeException(paramName);
+ }
+
+ internal static void IsTrue(bool exp, string paramName)
+ {
+ if (!exp)
+ throw new ArgumentOutOfRangeException(paramName);
+ }
+
+ internal static void IsNotNull(object obj, string paramName)
+ {
+ if(obj == null) throw new ArgumentNullException(paramName);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Utils/IIPAddressesProvider.cs b/Open.NAT/Open.Nat/Utils/IIPAddressesProvider.cs
new file mode 100644
index 0000000..b3b764c
--- /dev/null
+++ b/Open.NAT/Open.Nat/Utils/IIPAddressesProvider.cs
@@ -0,0 +1,38 @@
+//
+// Authors:
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections.Generic;
+using System.Net;
+
+namespace Open.Nat
+{
+ internal interface IIPAddressesProvider
+ {
+ IEnumerable DnsAddresses();
+ IEnumerable GatewayAddresses();
+ IEnumerable UnicastAddresses();
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Utils/IPAddressesProvider.cs b/Open.NAT/Open.Nat/Utils/IPAddressesProvider.cs
new file mode 100644
index 0000000..e6d142d
--- /dev/null
+++ b/Open.NAT/Open.Nat/Utils/IPAddressesProvider.cs
@@ -0,0 +1,69 @@
+//
+// Authors:
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Net.Sockets;
+
+namespace Open.Nat
+{
+ internal class IPAddressesProvider : IIPAddressesProvider
+ {
+ #region IIPAddressesProvider Members
+
+ public IEnumerable UnicastAddresses()
+ {
+ return IPAddresses(p => p.UnicastAddresses.Select(x => x.Address));
+ }
+
+ public IEnumerable DnsAddresses()
+ {
+ return IPAddresses(p => p.DnsAddresses);
+ }
+
+ public IEnumerable GatewayAddresses()
+ {
+ return IPAddresses(p => p.GatewayAddresses.Select(x => x.Address));
+ }
+
+ #endregion
+
+ private static IEnumerable IPAddresses(Func> ipExtractor)
+ {
+ return from networkInterface in NetworkInterface.GetAllNetworkInterfaces()
+ where
+ networkInterface.OperationalStatus == OperationalStatus.Up ||
+ networkInterface.OperationalStatus == OperationalStatus.Unknown
+ let properties = networkInterface.GetIPProperties()
+ from address in ipExtractor(properties)
+ where address.AddressFamily == AddressFamily.InterNetwork
+ select address;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Open.NAT/Open.Nat/Utils/WellKnownConstants.cs b/Open.NAT/Open.Nat/Utils/WellKnownConstants.cs
new file mode 100644
index 0000000..8de465d
--- /dev/null
+++ b/Open.NAT/Open.Nat/Utils/WellKnownConstants.cs
@@ -0,0 +1,36 @@
+//
+// Authors:
+// Lucas Ontivero lucasontivero@gmail.com
+//
+// Copyright (C) 2014 Lucas Ontivero
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Net;
+
+namespace Open.Nat
+{
+ internal static class WellKnownConstants
+ {
+ public static IPAddress IPv4MulticastAddress = IPAddress.Parse("239.255.255.250");
+ public static IPEndPoint NatPmpEndPoint = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 5351);
+ }
+}
\ No newline at end of file
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/CharacterCustomization.Designer.cs b/RBXLegacyLauncher/RBXLegacyLauncher/CharacterCustomization.Designer.cs
index a27650a..f6f663c 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/CharacterCustomization.Designer.cs
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/CharacterCustomization.Designer.cs
@@ -1324,7 +1324,7 @@ namespace RBXLegacyLauncher
this.tabPage7.Padding = new System.Windows.Forms.Padding(3);
this.tabPage7.Size = new System.Drawing.Size(447, 250);
this.tabPage7.TabIndex = 6;
- this.tabPage7.Text = "GEARS";
+ this.tabPage7.Text = "GEAR";
this.tabPage7.UseVisualStyleBackColor = true;
//
// button7
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/CharacterCustomization.resx b/RBXLegacyLauncher/RBXLegacyLauncher/CharacterCustomization.resx
index d761697..bb6e0eb 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/CharacterCustomization.resx
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/CharacterCustomization.resx
@@ -112,12 +112,12 @@
2.0
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
@@ -1273,7 +1273,7 @@
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
- vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
+ vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@@ -1417,7 +1417,7 @@
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
- vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
+ vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@@ -1561,7 +1561,7 @@
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
- vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
+ vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@@ -1705,7 +1705,7 @@
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
- vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
+ vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@@ -1849,7 +1849,7 @@
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
- vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
+ vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@@ -1993,7 +1993,7 @@
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
- vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
+ vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@@ -2137,7 +2137,7 @@
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
- vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
+ vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@@ -2281,7 +2281,7 @@
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
- vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
+ vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/ClientSettings.resx b/RBXLegacyLauncher/RBXLegacyLauncher/ClientSettings.resx
index 7080a7d..1af7de1 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/ClientSettings.resx
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/ClientSettings.resx
@@ -112,9 +112,9 @@
2.0
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
\ No newline at end of file
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/DocForm.resx b/RBXLegacyLauncher/RBXLegacyLauncher/DocForm.resx
index 6278e07..063b003 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/DocForm.resx
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/DocForm.resx
@@ -112,10 +112,10 @@
2.0
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
VERSION CODENAME DOCUMENTATION
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/LoaderForm.resx b/RBXLegacyLauncher/RBXLegacyLauncher/LoaderForm.resx
index 7311863..b030d8f 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/LoaderForm.resx
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/LoaderForm.resx
@@ -112,10 +112,10 @@
2.0
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/MainForm.Designer.cs b/RBXLegacyLauncher/RBXLegacyLauncher/MainForm.Designer.cs
index 5bd926d..639d598 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/MainForm.Designer.cs
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/MainForm.Designer.cs
@@ -19,6 +19,7 @@
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
+ this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
this.button11 = new System.Windows.Forms.Button();
this.label35 = new System.Windows.Forms.Label();
this.label42 = new System.Windows.Forms.Label();
@@ -99,10 +100,10 @@
this.label27 = new System.Windows.Forms.Label();
this.label28 = new System.Windows.Forms.Label();
this.textBox5 = new System.Windows.Forms.TextBox();
- this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
this.tabPage2.SuspendLayout();
this.tabPage3.SuspendLayout();
this.tabPage6.SuspendLayout();
@@ -110,7 +111,6 @@
this.tabPage8.SuspendLayout();
this.tabPage4.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();
- ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
this.SuspendLayout();
//
// pictureBox1
@@ -171,6 +171,25 @@
this.tabPage1.ToolTipText = "Join a server via IP Address";
this.tabPage1.UseVisualStyleBackColor = true;
//
+ // numericUpDown1
+ //
+ this.numericUpDown1.Location = new System.Drawing.Point(214, 25);
+ this.numericUpDown1.Maximum = new decimal(new int[] {
+ 99999,
+ 0,
+ 0,
+ 0});
+ this.numericUpDown1.Name = "numericUpDown1";
+ this.numericUpDown1.Size = new System.Drawing.Size(175, 20);
+ this.numericUpDown1.TabIndex = 43;
+ this.numericUpDown1.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
+ this.numericUpDown1.Value = new decimal(new int[] {
+ 53640,
+ 0,
+ 0,
+ 0});
+ this.numericUpDown1.ValueChanged += new System.EventHandler(this.NumericUpDown1ValueChanged);
+ //
// button11
//
this.button11.Location = new System.Drawing.Point(213, 47);
@@ -389,6 +408,7 @@
this.label30.Name = "label30";
this.label30.Size = new System.Drawing.Size(393, 2);
this.label30.TabIndex = 23;
+ this.label30.Visible = false;
//
// button6
//
@@ -398,6 +418,7 @@
this.button6.TabIndex = 6;
this.button6.Text = "CONFIGURE CLIENT";
this.button6.UseVisualStyleBackColor = true;
+ this.button6.Visible = false;
this.button6.Click += new System.EventHandler(this.Button6Click);
//
// label19
@@ -416,7 +437,7 @@
this.textBox6.Name = "textBox6";
this.textBox6.ReadOnly = true;
this.textBox6.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
- this.textBox6.Size = new System.Drawing.Size(393, 67);
+ this.textBox6.Size = new System.Drawing.Size(393, 111);
this.textBox6.TabIndex = 4;
this.textBox6.Text = "textBox6";
//
@@ -999,24 +1020,6 @@
this.textBox5.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.textBox5.TextChanged += new System.EventHandler(this.TextBox5TextChanged);
//
- // numericUpDown1
- //
- this.numericUpDown1.Location = new System.Drawing.Point(214, 25);
- this.numericUpDown1.Maximum = new decimal(new int[] {
- 99999,
- 0,
- 0,
- 0});
- this.numericUpDown1.Name = "numericUpDown1";
- this.numericUpDown1.Size = new System.Drawing.Size(175, 20);
- this.numericUpDown1.TabIndex = 43;
- this.numericUpDown1.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
- this.numericUpDown1.Value = new decimal(new int[] {
- 53640,
- 0,
- 0,
- 0});
- //
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -1055,6 +1058,7 @@
this.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage1.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
this.tabPage2.ResumeLayout(false);
this.tabPage3.ResumeLayout(false);
this.tabPage3.PerformLayout();
@@ -1063,7 +1067,6 @@
this.tabPage8.ResumeLayout(false);
this.tabPage4.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit();
- ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/MainForm.cs b/RBXLegacyLauncher/RBXLegacyLauncher/MainForm.cs
index 642bc47..4cf775d 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/MainForm.cs
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/MainForm.cs
@@ -9,6 +9,7 @@ using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
+using Open.Nat;
namespace RBXLegacyLauncher
{
@@ -19,42 +20,61 @@ namespace RBXLegacyLauncher
InitializeComponent();
}
- public event EventHandler evNATdone;
-
- public class evNATdoneargs : EventArgs
+ public async void StartUPNP()
{
- public string IP;
- public int port;
- }
+ try
+ {
+ var nat = new NatDiscoverer();
- //this class contains network connectivity stuff
- public void StartUPNP()
- {
- Mono.Nat.NatUtility.DeviceFound += new EventHandler(NatUtility_DeviceFound);
- Mono.Nat.NatUtility.DeviceLost += new EventHandler(NatUtility_DeviceLost);
- Mono.Nat.NatUtility.StartDiscovery();
- }
-
- private void NatUtility_DeviceFound(object sender, Mono.Nat.DeviceEventArgs e)
- {
- //do port forwarding with UPNP
- Mono.Nat.INatDevice natd = e.Device;
- natd.CreatePortMap(new Mono.Nat.Mapping(Mono.Nat.Protocol.Tcp,GlobalVars.ServerPort,GlobalVars.ServerPort));
- natd.CreatePortMap(new Mono.Nat.Mapping(Mono.Nat.Protocol.Udp,GlobalVars.ServerPort,GlobalVars.ServerPort));
- ConsolePrint("Port " + GlobalVars.ServerPort.ToString() + " registered to device " + natd.GetExternalIP().ToString(), 3);
- evNATdoneargs args = new evNATdoneargs();
- args.IP = natd.GetExternalIP().ToString();
- args.port = GlobalVars.ServerPort;
- evNATdone(this, args);
- //MessageBox.Show("NAT done! My public IP is " + IP);
+ var cts = new CancellationTokenSource(5000);
+ var device = await nat.DiscoverDeviceAsync(PortMapper.Upnp, cts);
+ await device.CreatePortMapAsync(new Mapping(Protocol.Udp, GlobalVars.ServerPort, GlobalVars.ServerPort, "RBXLegacy"));
+
+ var ip = await device.GetExternalIPAsync();
+
+ ConsolePrint("Port " + GlobalVars.ServerPort.ToString() + " registered to device " + ip, 3);
+ }
+ catch(NatDeviceNotFoundException e)
+ {
+ ConsolePrint("Error: " + e.ToString(), 2);
+ }
+ catch(MappingException me)
+ {
+ switch(me.ErrorCode)
+ {
+ case 718:
+ ConsolePrint("The external port is already in use.", 2);
+ break;
+ case 728:
+ ConsolePrint("The router's mapping table is full.", 2);
+ break;
+ }
+ }
}
- private void NatUtility_DeviceLost(object sender, Mono.Nat.DeviceEventArgs e)
+ public async void StopUPNP()
{
- //do port forwarding with UPNP
- Mono.Nat.INatDevice natd = e.Device;
- natd.DeletePortMap(new Mono.Nat.Mapping(Mono.Nat.Protocol.Tcp,GlobalVars.ServerPort,GlobalVars.ServerPort));
- natd.DeletePortMap(new Mono.Nat.Mapping(Mono.Nat.Protocol.Udp,GlobalVars.ServerPort,GlobalVars.ServerPort));
+ try
+ {
+ var nat = new NatDiscoverer();
+ var cts = new CancellationTokenSource(5000);
+ var device = await nat.DiscoverDeviceAsync(PortMapper.Upnp, cts);
+
+ foreach (var mapping in await device.GetAllMappingsAsync())
+ {
+ if(mapping.Description.Contains("RBXLegacy"))
+ {
+ await device.DeletePortMapAsync(mapping);
+ }
+ }
+
+ var ip = await device.GetExternalIPAsync();
+ ConsolePrint("Port " + GlobalVars.ServerPort.ToString() + " removed from device " + ip, 2);
+ }
+ catch(NatDeviceNotFoundException e)
+ {
+ ConsolePrint("Error: " + e.ToString(), 2);
+ }
}
void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
@@ -398,7 +418,7 @@ namespace RBXLegacyLauncher
DialogResult result = MessageBox.Show("Your configuration has been saved successfully!","RBXLegacy Launcher - Configuration", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
}
- void numericUpDown1TextChanged(object sender, EventArgs e)
+ void NumericUpDown1ValueChanged(object sender, EventArgs e)
{
int parsedValue;
if (int.TryParse(numericUpDown1.Text, out parsedValue))
@@ -607,6 +627,7 @@ namespace RBXLegacyLauncher
void ConsolePrint(string text, int type)
{
+ //1 = white text, 2 = red text, 3 = green text, 4 = aqua text, 5 = yellow text
richTextBox1.AppendText("[" + DateTime.Now.ToShortTimeString() + "]", Color.White);
richTextBox1.AppendText(" - ", Color.White);
if (type == 1)
@@ -755,19 +776,19 @@ namespace RBXLegacyLauncher
string HatIDOffline3 = GlobalVars.Custom_Hat3ID_Offline;
if (GlobalVars.UsesPlayerName == true && GlobalVars.UsesID == true)
{
- args = quote + mapfile + "\" -script \"dofile('" + GlobalVars.DefaultScript + "') _G.SetRBXLegacyVersion(" + GlobalVars.SelectedClientVersion + ") _G.CSSolo(" + GlobalVars.UserID + ",'" + GlobalVars.PlayerName + "','" + HatIDOffline1 + "','" + HatIDOffline2 + "','" + HatIDOffline3 + "'," + GlobalVars.HeadColorID + "," + GlobalVars.TorsoColorID + "," + GlobalVars.LeftArmColorID + "," + GlobalVars.RightArmColorID + "," + GlobalVars.LeftLegColorID + "," + GlobalVars.RightLegColorID + ",'" + GlobalVars.Custom_TShirt + "','" + GlobalVars.Custom_Shirt + "','" + GlobalVars.Custom_Pants + "','" + GlobalVars.FaceID + "','" + GlobalVars.HeadID + "','" + GlobalVars.TorsoID + "','" + GlobalVars.RightArmID + "','" + GlobalVars.LeftArmID + "','" + GlobalVars.RightLegID + "','" + GlobalVars.LeftLegID + "','" + GlobalVars.Custom_Gear1 + "','" + GlobalVars.Custom_Gear2 + "','" + GlobalVars.Custom_Gear3 + "','" + GlobalVars.Custom_IconType + "'," + GlobalVars.melee.ToString().ToLower() + "," + GlobalVars.powerup.ToString().ToLower() + "," + GlobalVars.ranged.ToString().ToLower() + "," + GlobalVars.navigation.ToString().ToLower() + "," + GlobalVars.explosives.ToString().ToLower() + "," + GlobalVars.musical.ToString().ToLower() + "," + GlobalVars.social.ToString().ToLower() + "," + GlobalVars.transport.ToString().ToLower() + "," + GlobalVars.building.ToString().ToLower() + ") " + quote;
+ args = quote + mapfile + "\" -script \"dofile('" + GlobalVars.DefaultScript + "') _G.SetRBXLegacyVersion(" + GlobalVars.SelectedClientVersion + ") _G.CSSolo(" + GlobalVars.UserID + ",'" + GlobalVars.PlayerName + "','" + HatIDOffline1 + "','" + HatIDOffline2 + "','" + HatIDOffline3 + "'," + GlobalVars.HeadColorID + "," + GlobalVars.TorsoColorID + "," + GlobalVars.LeftArmColorID + "," + GlobalVars.RightArmColorID + "," + GlobalVars.LeftLegColorID + "," + GlobalVars.RightLegColorID + ",'" + GlobalVars.Custom_TShirt + "','" + GlobalVars.Custom_Shirt + "','" + GlobalVars.Custom_Pants + "','" + GlobalVars.FaceID + "','" + GlobalVars.HeadID + "','" + GlobalVars.TorsoID + "','" + GlobalVars.RightArmID + "','" + GlobalVars.LeftArmID + "','" + GlobalVars.RightLegID + "','" + GlobalVars.LeftLegID + "','" + GlobalVars.Custom_Gear1 + "','" + GlobalVars.Custom_Gear2 + "','" + GlobalVars.Custom_Gear3 + "','" + GlobalVars.Custom_IconType + "'," + GlobalVars.melee.ToString().ToLower() + "," + GlobalVars.powerup.ToString().ToLower() + "," + GlobalVars.ranged.ToString().ToLower() + "," + GlobalVars.navigation.ToString().ToLower() + "," + GlobalVars.explosives.ToString().ToLower() + "," + GlobalVars.musical.ToString().ToLower() + "," + GlobalVars.social.ToString().ToLower() + "," + GlobalVars.transport.ToString().ToLower() + "," + GlobalVars.building.ToString().ToLower() + "," + GlobalVars.RespawnTime + ") " + quote;
}
else if (GlobalVars.UsesPlayerName == false && GlobalVars.UsesID == true)
{
- args = quote + mapfile + "\" -script \"dofile('" + GlobalVars.DefaultScript + "') _G.SetRBXLegacyVersion(" + GlobalVars.SelectedClientVersion + ") _G.CSSolo(" + GlobalVars.UserID + ",'Player','" + HatIDOffline1 + "','" + HatIDOffline2 + "','" + HatIDOffline3 + "'," + GlobalVars.HeadColorID + "," + GlobalVars.TorsoColorID + "," + GlobalVars.LeftArmColorID + "," + GlobalVars.RightArmColorID + "," + GlobalVars.LeftLegColorID + "," + GlobalVars.RightLegColorID + ",'" + GlobalVars.Custom_TShirt + "','" + GlobalVars.Custom_Shirt + "','" + GlobalVars.Custom_Pants + "','" + GlobalVars.FaceID + "','" + GlobalVars.HeadID + "','" + GlobalVars.TorsoID + "','" + GlobalVars.RightArmID + "','" + GlobalVars.LeftArmID + "','" + GlobalVars.RightLegID + "','" + GlobalVars.LeftLegID + "','" + GlobalVars.Custom_Gear1 + "','" + GlobalVars.Custom_Gear2 + "','" + GlobalVars.Custom_Gear3 + "','" + GlobalVars.Custom_IconType + "'," + GlobalVars.melee.ToString().ToLower() + "," + GlobalVars.powerup.ToString().ToLower() + "," + GlobalVars.ranged.ToString().ToLower() + "," + GlobalVars.navigation.ToString().ToLower() + "," + GlobalVars.explosives.ToString().ToLower() + "," + GlobalVars.musical.ToString().ToLower() + "," + GlobalVars.social.ToString().ToLower() + "," + GlobalVars.transport.ToString().ToLower() + "," + GlobalVars.building.ToString().ToLower() + ") " + quote;
+ args = quote + mapfile + "\" -script \"dofile('" + GlobalVars.DefaultScript + "') _G.SetRBXLegacyVersion(" + GlobalVars.SelectedClientVersion + ") _G.CSSolo(" + GlobalVars.UserID + ",'Player','" + HatIDOffline1 + "','" + HatIDOffline2 + "','" + HatIDOffline3 + "'," + GlobalVars.HeadColorID + "," + GlobalVars.TorsoColorID + "," + GlobalVars.LeftArmColorID + "," + GlobalVars.RightArmColorID + "," + GlobalVars.LeftLegColorID + "," + GlobalVars.RightLegColorID + ",'" + GlobalVars.Custom_TShirt + "','" + GlobalVars.Custom_Shirt + "','" + GlobalVars.Custom_Pants + "','" + GlobalVars.FaceID + "','" + GlobalVars.HeadID + "','" + GlobalVars.TorsoID + "','" + GlobalVars.RightArmID + "','" + GlobalVars.LeftArmID + "','" + GlobalVars.RightLegID + "','" + GlobalVars.LeftLegID + "','" + GlobalVars.Custom_Gear1 + "','" + GlobalVars.Custom_Gear2 + "','" + GlobalVars.Custom_Gear3 + "','" + GlobalVars.Custom_IconType + "'," + GlobalVars.melee.ToString().ToLower() + "," + GlobalVars.powerup.ToString().ToLower() + "," + GlobalVars.ranged.ToString().ToLower() + "," + GlobalVars.navigation.ToString().ToLower() + "," + GlobalVars.explosives.ToString().ToLower() + "," + GlobalVars.musical.ToString().ToLower() + "," + GlobalVars.social.ToString().ToLower() + "," + GlobalVars.transport.ToString().ToLower() + "," + GlobalVars.building.ToString().ToLower() + "," + GlobalVars.RespawnTime + ") " + quote;
}
else if (GlobalVars.UsesPlayerName == true && GlobalVars.UsesID == false)
{
- args = quote + mapfile + "\" -script \"dofile('" + GlobalVars.DefaultScript + "') _G.SetRBXLegacyVersion(" + GlobalVars.SelectedClientVersion + ") _G.CSSolo(0,'" + GlobalVars.PlayerName + "','" + HatIDOffline1 + "','" + HatIDOffline2 + "','" + HatIDOffline3 + "'," + GlobalVars.HeadColorID + "," + GlobalVars.TorsoColorID + "," + GlobalVars.LeftArmColorID + "," + GlobalVars.RightArmColorID + "," + GlobalVars.LeftLegColorID + "," + GlobalVars.RightLegColorID + ",'" + GlobalVars.Custom_TShirt + "','" + GlobalVars.Custom_Shirt + "','" + GlobalVars.Custom_Pants + "','" + GlobalVars.FaceID + "','" + GlobalVars.HeadID + "','" + GlobalVars.TorsoID + "','" + GlobalVars.RightArmID + "','" + GlobalVars.LeftArmID + "','" + GlobalVars.RightLegID + "','" + GlobalVars.LeftLegID + "','" + GlobalVars.Custom_Gear1 + "','" + GlobalVars.Custom_Gear2 + "','" + GlobalVars.Custom_Gear3 + "','" + GlobalVars.Custom_IconType + "'," + GlobalVars.melee.ToString().ToLower() + "," + GlobalVars.powerup.ToString().ToLower() + "," + GlobalVars.ranged.ToString().ToLower() + "," + GlobalVars.navigation.ToString().ToLower() + "," + GlobalVars.explosives.ToString().ToLower() + "," + GlobalVars.musical.ToString().ToLower() + "," + GlobalVars.social.ToString().ToLower() + "," + GlobalVars.transport.ToString().ToLower() + "," + GlobalVars.building.ToString().ToLower() + ") " + quote;
+ args = quote + mapfile + "\" -script \"dofile('" + GlobalVars.DefaultScript + "') _G.SetRBXLegacyVersion(" + GlobalVars.SelectedClientVersion + ") _G.CSSolo(0,'" + GlobalVars.PlayerName + "','" + HatIDOffline1 + "','" + HatIDOffline2 + "','" + HatIDOffline3 + "'," + GlobalVars.HeadColorID + "," + GlobalVars.TorsoColorID + "," + GlobalVars.LeftArmColorID + "," + GlobalVars.RightArmColorID + "," + GlobalVars.LeftLegColorID + "," + GlobalVars.RightLegColorID + ",'" + GlobalVars.Custom_TShirt + "','" + GlobalVars.Custom_Shirt + "','" + GlobalVars.Custom_Pants + "','" + GlobalVars.FaceID + "','" + GlobalVars.HeadID + "','" + GlobalVars.TorsoID + "','" + GlobalVars.RightArmID + "','" + GlobalVars.LeftArmID + "','" + GlobalVars.RightLegID + "','" + GlobalVars.LeftLegID + "','" + GlobalVars.Custom_Gear1 + "','" + GlobalVars.Custom_Gear2 + "','" + GlobalVars.Custom_Gear3 + "','" + GlobalVars.Custom_IconType + "'," + GlobalVars.melee.ToString().ToLower() + "," + GlobalVars.powerup.ToString().ToLower() + "," + GlobalVars.ranged.ToString().ToLower() + "," + GlobalVars.navigation.ToString().ToLower() + "," + GlobalVars.explosives.ToString().ToLower() + "," + GlobalVars.musical.ToString().ToLower() + "," + GlobalVars.social.ToString().ToLower() + "," + GlobalVars.transport.ToString().ToLower() + "," + GlobalVars.building.ToString().ToLower() + "," + GlobalVars.RespawnTime + ") " + quote;
}
else if (GlobalVars.UsesPlayerName == false && GlobalVars.UsesID == false )
{
- args = quote + mapfile + "\" -script \"dofile('" + GlobalVars.DefaultScript + "') _G.SetRBXLegacyVersion(" + GlobalVars.SelectedClientVersion + ") _G.CSSolo(0,'Player','" + HatIDOffline1 + "','" + HatIDOffline2 + "','" + HatIDOffline3 + "'," + GlobalVars.HeadColorID + "," + GlobalVars.TorsoColorID + "," + GlobalVars.LeftArmColorID + "," + GlobalVars.RightArmColorID + "," + GlobalVars.LeftLegColorID + "," + GlobalVars.RightLegColorID + ",'" + GlobalVars.Custom_TShirt + "','" + GlobalVars.Custom_Shirt + "','" + GlobalVars.Custom_Pants + "','" + GlobalVars.FaceID + "','" + GlobalVars.HeadID + "','" + GlobalVars.TorsoID + "','" + GlobalVars.RightArmID + "','" + GlobalVars.LeftArmID + "','" + GlobalVars.RightLegID + "','" + GlobalVars.LeftLegID + "','" + GlobalVars.Custom_Gear1 + "','" + GlobalVars.Custom_Gear2 + "','" + GlobalVars.Custom_Gear3 + "','" + GlobalVars.Custom_IconType + "'," + GlobalVars.melee.ToString().ToLower() + "," + GlobalVars.powerup.ToString().ToLower() + "," + GlobalVars.ranged.ToString().ToLower() + "," + GlobalVars.navigation.ToString().ToLower() + "," + GlobalVars.explosives.ToString().ToLower() + "," + GlobalVars.musical.ToString().ToLower() + "," + GlobalVars.social.ToString().ToLower() + "," + GlobalVars.transport.ToString().ToLower() + "," + GlobalVars.building.ToString().ToLower() + ") " + quote;
+ args = quote + mapfile + "\" -script \"dofile('" + GlobalVars.DefaultScript + "') _G.SetRBXLegacyVersion(" + GlobalVars.SelectedClientVersion + ") _G.CSSolo(0,'Player','" + HatIDOffline1 + "','" + HatIDOffline2 + "','" + HatIDOffline3 + "'," + GlobalVars.HeadColorID + "," + GlobalVars.TorsoColorID + "," + GlobalVars.LeftArmColorID + "," + GlobalVars.RightArmColorID + "," + GlobalVars.LeftLegColorID + "," + GlobalVars.RightLegColorID + ",'" + GlobalVars.Custom_TShirt + "','" + GlobalVars.Custom_Shirt + "','" + GlobalVars.Custom_Pants + "','" + GlobalVars.FaceID + "','" + GlobalVars.HeadID + "','" + GlobalVars.TorsoID + "','" + GlobalVars.RightArmID + "','" + GlobalVars.LeftArmID + "','" + GlobalVars.RightLegID + "','" + GlobalVars.LeftLegID + "','" + GlobalVars.Custom_Gear1 + "','" + GlobalVars.Custom_Gear2 + "','" + GlobalVars.Custom_Gear3 + "','" + GlobalVars.Custom_IconType + "'," + GlobalVars.melee.ToString().ToLower() + "," + GlobalVars.powerup.ToString().ToLower() + "," + GlobalVars.ranged.ToString().ToLower() + "," + GlobalVars.navigation.ToString().ToLower() + "," + GlobalVars.explosives.ToString().ToLower() + "," + GlobalVars.musical.ToString().ToLower() + "," + GlobalVars.social.ToString().ToLower() + "," + GlobalVars.transport.ToString().ToLower() + "," + GlobalVars.building.ToString().ToLower() + "," + GlobalVars.RespawnTime + ") " + quote;
}
try
{
@@ -799,7 +820,16 @@ namespace RBXLegacyLauncher
try
{
ConsolePrint("Server Loaded.", 4);
- Process.Start(rbxexe, args);
+ Process server = new Process();
+ server.StartInfo.FileName = rbxexe;
+ server.StartInfo.Arguments = args;
+ server.EnableRaisingEvents = true;
+ ReadClientValues(GlobalVars.SelectedClient);
+ if (GlobalVars.upnp == true)
+ {
+ server.Exited += new EventHandler(ServerExited);
+ }
+ server.Start();
}
catch (Exception ex)
{
@@ -826,7 +856,16 @@ namespace RBXLegacyLauncher
try
{
ConsolePrint("Server Loaded in No3D mode.", 4);
- Process.Start(rbxexe, args);
+ Process server = new Process();
+ server.StartInfo.FileName = rbxexe;
+ server.StartInfo.Arguments = args;
+ server.EnableRaisingEvents = true;
+ ReadClientValues(GlobalVars.SelectedClient);
+ if (GlobalVars.upnp == true)
+ {
+ server.Exited += new EventHandler(ServerExited);
+ }
+ server.Start();
}
catch (Exception ex)
{
@@ -835,6 +874,16 @@ namespace RBXLegacyLauncher
}
}
+ void ServerExited(object sender, EventArgs e)
+ {
+ StopUPNP();
+
+ if (this.WindowState == FormWindowState.Minimized)
+ {
+ this.WindowState = FormWindowState.Normal;
+ }
+ }
+
void StartStudio()
{
string mapfile = GlobalVars.MapsDir + @"\\" + GlobalVars.Map;
@@ -872,8 +921,8 @@ namespace RBXLegacyLauncher
void ConsoleProcessCommands(string command)
{
- string important = SecurityFuncs.Base64Decode("cmJ4bGVnYWN5IGthbnJpc2hh");
- if (command.Equals("rbxlegacy server"))
+ string important = SecurityFuncs.Base64Decode("a2FucmlzaGE=");
+ if (command.Equals("server"))
{
if (GlobalVars.upnp == true)
{
@@ -881,7 +930,7 @@ namespace RBXLegacyLauncher
}
StartServer();
}
- else if (command.Equals("rbxlegacy server no3d"))
+ else if (command.Equals("serverno3d"))
{
if (GlobalVars.upnp == true)
{
@@ -889,15 +938,7 @@ namespace RBXLegacyLauncher
}
StartServerNo3D();
}
- else if (command.Equals("rbxlegacy no3d"))
- {
- if (GlobalVars.upnp == true)
- {
- StartUPNP();
- }
- StartServerNo3D();
- }
- else if (command.Equals("rbxlegacy client"))
+ else if (command.Equals("client"))
{
ReadClientValues(GlobalVars.SelectedClient);
if (GlobalVars.HasRocky == true)
@@ -911,53 +952,37 @@ namespace RBXLegacyLauncher
}
StartClient();
}
- else if (command.Equals("rbxlegacy client solo"))
+ else if (command.Equals("solo"))
{
StartSolo();
}
- else if (command.Equals("rbxlegacy solo"))
- {
- StartSolo();
- }
- else if (command.Equals("rbxlegacy studio"))
+ else if (command.Equals("studio"))
{
StartStudio();
}
- else if (command.Equals("rbxlegacy config save"))
+ else if (command.Equals("config save"))
{
WriteConfigValues();
}
- else if (command.Equals("rbxlegacy config load"))
+ else if (command.Equals("config load"))
{
ReadConfigValues();
}
- else if (command.Equals("rbxlegacy config reset"))
+ else if (command.Equals("config reset"))
{
ResetConfigValues();
}
- else if (command.Equals("rbxlegacy sdk"))
- {
- SDKForm sdk = new SDKForm();
- sdk.Show();
- ConsolePrint("Launched SDK.", 4);
- }
else if (command.Equals("sdk"))
{
SDKForm sdk = new SDKForm();
sdk.Show();
ConsolePrint("Launched SDK.", 4);
}
- else if (command.Equals("rbxlegacy help"))
+ else if (command.Equals("uri"))
{
- ConsoleRBXLegacyHelp(0);
- }
- else if (command.Equals("rbxlegacy"))
- {
- ConsoleRBXLegacyHelp(0);
- }
- else if (command.Equals("rbxlegacy config"))
- {
- ConsoleRBXLegacyHelp(1);
+ Process uri = new Process();
+ uri.StartInfo.FileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\RBXLegacyURI.exe";
+ uri.Start();
}
else if (command.Equals("config"))
{
@@ -975,7 +1000,7 @@ namespace RBXLegacyLauncher
}
else
{
- ConsolePrint("ERROR 3 - Command is either not registered or valid", 2);
+ ConsolePrint("ERROR 3 - Command is invalid", 2);
}
}
@@ -984,32 +1009,36 @@ namespace RBXLegacyLauncher
{
if (page == 1)
{
- ConsolePrint("rbxlegacy config", 2);
- ConsolePrint("-------------------------", 1);
- ConsolePrint("= save | Saves the config file", 3);
- ConsolePrint("= load | Reloads the config file", 3);
- ConsolePrint("= reset | Resets the config file", 3);
+ ConsolePrint("RBXLegacy Config Command List", 2);
+ ConsolePrint("-----------------------------------------", 1);
+ ConsolePrint("config save | Saves the config file", 4);
+ ConsolePrint("config load | Reloads the config file", 4);
+ ConsolePrint("config reset | Resets the config file", 4);
}
else
{
- ConsolePrint("rbxlegacy", 2);
- ConsolePrint("---------", 1);
- ConsolePrint("= client | Loads client with launcher settings", 3);
- ConsolePrint("-- solo | Loads client in Play Solo mode with launcher settings", 4);
- ConsolePrint("= server | Loads server with launcher settings", 3);
- ConsolePrint("-- no3d | Loads server in NoGraphics mode with launcher settings", 4);
- ConsolePrint("= studio | Loads Roblox Studio with launcher settings", 3);
- ConsolePrint("= sdk | Loads the RBXLegacy SDK", 3);
- ConsolePrint("= config", 3);
- ConsolePrint("-- save | Saves the config file", 4);
- ConsolePrint("-- load | Reloads the config file", 4);
- ConsolePrint("-- reset | Resets the config file", 4);
+ ConsolePrint("RBXLegacy Console Command List", 2);
+ ConsolePrint("------------------------------------------", 1);
+ ConsolePrint("client | Loads client with launcher settings", 4);
+ ConsolePrint("solo | Loads client in Play Solo mode with launcher settings", 4);
+ ConsolePrint("server | Loads server with launcher settings", 4);
+ ConsolePrint("serverno3d | Loads server in No3D mode with launcher settings", 4);
+ ConsolePrint("studio | Loads Roblox Studio with launcher settings", 4);
+ ConsolePrint("sdk | Loads the RBXLegacy SDK", 4);
+ ConsolePrint("uri | Installs the RBXLegacy URI", 4);
+ ConsolePrint("config save | Saves the config file", 4);
+ ConsolePrint("config load | Reloads the config file", 4);
+ ConsolePrint("config reset | Resets the config file", 4);
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
+ if (GlobalVars.upnp == true)
+ {
+ StopUPNP();
+ }
WriteConfigValues();
}
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/MainForm.resx b/RBXLegacyLauncher/RBXLegacyLauncher/MainForm.resx
index 883cf29..aeb0a9e 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/MainForm.resx
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/MainForm.resx
@@ -112,16 +112,16 @@
2.0
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
iVBORw0KGgoAAAANSUhEUgAAAMYAAAAhCAYAAACC2tRnAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
- vgAADr4B6kKxwAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAAYO0lEQVR4Xu1c
+ vAAADrwBlbxySQAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAAYO0lEQVR4Xu1c
CXgUVba+ne5sEPYdJAKCOiqCDqPCoIgbDjow41NHEARRH47PcUNRouI2jLKKIgIiKgg+NtFRILImQJAd
M7INARJCEsOSAFl7q+r/nXPrVqe6Ux1ah+D3vi/n+/6vqqvOPffce89/t6pqYScQ4k7CNgjXIThcWXS0
ICYLDlEFUU9BXQ/qWXXoXozI8jtFVmWsAb+LrtM1iRBdy2/j3u8I8cqvOEJXCOc9ZHMUnb9IOoyxpP8e
@@ -235,7 +235,7 @@
iVBORw0KGgoAAAANSUhEUgAAAMYAAAAhCAYAAACC2tRnAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
- wAAADsABataJCQAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAAYO0lEQVR4Xu1c
+ vQAADr0BR/uQrQAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAAYO0lEQVR4Xu1c
CXgUVba+ne5sEPYdJAKCOiqCDqPCoIgbDjow41NHEARRH47PcUNRouI2jLKKIgIiKgg+NtFRILImQJAd
M7INARJCEsOSAFl7q+r/nXPrVqe6Ux1ah+D3vi/n+/6vqqvOPffce89/t6pqYScQ4k7CNgjXIThcWXS0
ICYLDlEFUU9BXQ/qWXXoXozI8jtFVmWsAb+LrtM1iRBdy2/j3u8I8cqvOEJXCOc9ZHMUnb9IOoyxpP8e
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/QuickConfigure.resx b/RBXLegacyLauncher/RBXLegacyLauncher/QuickConfigure.resx
index 8fcf2e5..6c8efa7 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/QuickConfigure.resx
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/QuickConfigure.resx
@@ -112,10 +112,10 @@
2.0
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/RBXLegacyLauncher.csproj b/RBXLegacyLauncher/RBXLegacyLauncher/RBXLegacyLauncher.csproj
index 7366c54..f3a4924 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/RBXLegacyLauncher.csproj
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/RBXLegacyLauncher.csproj
@@ -7,7 +7,7 @@
WinExe
RBXLegacyLauncher
RBXLegacyLauncher
- v2.0
+ v4.5
Properties
@@ -49,14 +49,23 @@
..\..\..\RBXLegacy\release\RBXLegacy\RBXLegacyLauncher.exe
-
- Resources\Mono.Nat.dll
+
+ Resources\Open.Nat.dll
+
+ 3.5
+
+
+ 3.5
+
+
+ 3.5
+
@@ -110,9 +119,6 @@
DocForm.Designer.cs
-
- ClientSettings.cs
-
LoaderForm.cs
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/Resources/Mono.Nat.dll b/RBXLegacyLauncher/RBXLegacyLauncher/Resources/Mono.Nat.dll
deleted file mode 100644
index 614b2c2..0000000
Binary files a/RBXLegacyLauncher/RBXLegacyLauncher/Resources/Mono.Nat.dll and /dev/null differ
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/Resources/Open.Nat.dll b/RBXLegacyLauncher/RBXLegacyLauncher/Resources/Open.Nat.dll
new file mode 100644
index 0000000..1fff0f9
Binary files /dev/null and b/RBXLegacyLauncher/RBXLegacyLauncher/Resources/Open.Nat.dll differ
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/RichTextBoxExtensions.cs b/RBXLegacyLauncher/RBXLegacyLauncher/RichTextBoxExtensions.cs
index 6850363..6a5f5f2 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/RichTextBoxExtensions.cs
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/RichTextBoxExtensions.cs
@@ -4,12 +4,14 @@ using System.Drawing;
using System.Windows.Forms;
// you need this once (only), and it must be in this namespace
+/*
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class
| AttributeTargets.Method)]
public sealed class ExtensionAttribute : Attribute {}
}
+*/
public static class RichTextBoxExtensions
{
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/SDKForm.Designer.cs b/RBXLegacyLauncher/RBXLegacyLauncher/SDKForm.Designer.cs
index 4b2abe4..bad469c 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/SDKForm.Designer.cs
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/SDKForm.Designer.cs
@@ -97,7 +97,7 @@
this.checkBox4.Name = "checkBox4";
this.checkBox4.Size = new System.Drawing.Size(192, 20);
this.checkBox4.TabIndex = 34;
- this.checkBox4.Text = "Use Sudppipe (RECCOMENDED)";
+ this.checkBox4.Text = "Use Sudppipe (RECOMMENDED)";
this.checkBox4.UseVisualStyleBackColor = true;
this.checkBox4.CheckedChanged += new System.EventHandler(this.CheckBox4CheckedChanged);
//
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/SDKForm.resx b/RBXLegacyLauncher/RBXLegacyLauncher/SDKForm.resx
index 8fcf2e5..3ce0458 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/SDKForm.resx
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/SDKForm.resx
@@ -112,12 +112,12 @@
2.0
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
AAABAAYAEBAAAAAAIABoBAAAZgAAACAgAAAAACAAqBAAAM4EAAAwMAAAAAAgAKglAAB2FQAAQEAAAAAA
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/ServerPrefs.Designer.cs b/RBXLegacyLauncher/RBXLegacyLauncher/ServerPrefs.Designer.cs
index a75ec87..df3a4c6 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/ServerPrefs.Designer.cs
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/ServerPrefs.Designer.cs
@@ -19,6 +19,7 @@
this.textBox1 = new System.Windows.Forms.TextBox();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
+ this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
this.checkBox12 = new System.Windows.Forms.CheckBox();
this.textBox11 = new System.Windows.Forms.TextBox();
this.textBox12 = new System.Windows.Forms.TextBox();
@@ -55,11 +56,10 @@
this.radioButton1 = new System.Windows.Forms.RadioButton();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.button1 = new System.Windows.Forms.Button();
- this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
- this.tabPage2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
+ this.tabPage2.SuspendLayout();
this.SuspendLayout();
//
// textBox1
@@ -133,6 +133,24 @@
this.tabPage1.UseVisualStyleBackColor = true;
this.tabPage1.Click += new System.EventHandler(this.TabPage1Click);
//
+ // numericUpDown1
+ //
+ this.numericUpDown1.Location = new System.Drawing.Point(240, 80);
+ this.numericUpDown1.Maximum = new decimal(new int[] {
+ 99999,
+ 0,
+ 0,
+ 0});
+ this.numericUpDown1.Name = "numericUpDown1";
+ this.numericUpDown1.Size = new System.Drawing.Size(237, 20);
+ this.numericUpDown1.TabIndex = 67;
+ this.numericUpDown1.Value = new decimal(new int[] {
+ 53640,
+ 0,
+ 0,
+ 0});
+ this.numericUpDown1.ValueChanged += new System.EventHandler(this.NumericUpDown1ValueChanged);
+ //
// checkBox12
//
this.checkBox12.Location = new System.Drawing.Point(353, 6);
@@ -494,23 +512,6 @@
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.Button1Click);
//
- // numericUpDown1
- //
- this.numericUpDown1.Location = new System.Drawing.Point(240, 80);
- this.numericUpDown1.Maximum = new decimal(new int[] {
- 99999,
- 0,
- 0,
- 0});
- this.numericUpDown1.Name = "numericUpDown1";
- this.numericUpDown1.Size = new System.Drawing.Size(237, 20);
- this.numericUpDown1.TabIndex = 67;
- this.numericUpDown1.Value = new decimal(new int[] {
- 53640,
- 0,
- 0,
- 0});
- //
// ServerPrefs
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -530,9 +531,9 @@
this.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage1.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
this.tabPage2.ResumeLayout(false);
this.tabPage2.PerformLayout();
- ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
this.ResumeLayout(false);
}
private System.Windows.Forms.NumericUpDown numericUpDown1;
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/ServerPrefs.cs b/RBXLegacyLauncher/RBXLegacyLauncher/ServerPrefs.cs
index 0ee0c6e..e3fe0cf 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/ServerPrefs.cs
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/ServerPrefs.cs
@@ -2,6 +2,9 @@
using System.Drawing;
using System.Windows.Forms;
using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+using Open.Nat;
namespace RBXLegacyLauncher
{
@@ -191,21 +194,16 @@ namespace RBXLegacyLauncher
string GetExternalIPAddress()
{
- string ipAddress;
- using (WebClient wc = new WebClient())
- {
- try
- {
- Mono.Nat.INatDevice natd = e.Device;
- ipAddress = natd.GetExternalIP().ToString();
- }
- catch (Exception)
- {
- ipAddress = "localhost";
- }
- }
-
- return ipAddress;
+ string url = "http://checkip.dyndns.org";
+ System.Net.WebRequest req = System.Net.WebRequest.Create(url);
+ System.Net.WebResponse resp = req.GetResponse();
+ System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream());
+ string response = sr.ReadToEnd().Trim();
+ string[] a = response.Split(':');
+ string a2 = a[1].Substring(1);
+ string[] a3 = a2.Split('<');
+ string a4 = a3[0];
+ return a4;
}
void RadioButton1CheckedChanged(object sender, EventArgs e)
@@ -307,7 +305,7 @@ namespace RBXLegacyLauncher
GlobalVars.building = false;
}
- void numericUpDown1TextChanged(object sender, EventArgs e)
+ void NumericUpDown1ValueChanged(object sender, EventArgs e)
{
int parsedValue;
if (int.TryParse(numericUpDown1.Text, out parsedValue))
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/ServerPrefs.resx b/RBXLegacyLauncher/RBXLegacyLauncher/ServerPrefs.resx
index 8fcf2e5..3ce0458 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/ServerPrefs.resx
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/ServerPrefs.resx
@@ -112,12 +112,12 @@
2.0
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
+
AAABAAYAEBAAAAAAIABoBAAAZgAAACAgAAAAACAAqBAAAM4EAAAwMAAAAAAgAKglAAB2FQAAQEAAAAAA
diff --git a/RBXLegacyLauncher/RBXLegacyLauncher/app.config b/RBXLegacyLauncher/RBXLegacyLauncher/app.config
index 8520aac..9008dd2 100644
--- a/RBXLegacyLauncher/RBXLegacyLauncher/app.config
+++ b/RBXLegacyLauncher/RBXLegacyLauncher/app.config
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/RBXLegacySetup.iss b/RBXLegacySetup.iss
index a771707..3d0ee53 100644
--- a/RBXLegacySetup.iss
+++ b/RBXLegacySetup.iss
@@ -31,6 +31,7 @@ Name: "quicklaunchicon"; Description: "Create a icon on your Quick Start Menu";
[Files]
Source: "RBXLegacy\RBXLegacyLauncher.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "RBXLegacy\RBXLegacyLauncher.exe.config"; DestDir: "{app}"; Flags: ignoreversion
+Source: "RBXLegacy\RBXLegacyURI.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "RBXLegacy\README.TXT"; DestDir: "{app}"; Flags: ignoreversion
Source: "RBXLegacy\changelog.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "RBXLegacy\info.txt"; DestDir: "{app}"; Flags: ignoreversion
@@ -40,7 +41,7 @@ Source: "RBXLegacy\models\*"; DestDir: "{app}\models"; Flags: ignoreversion recu
Source: "RBXLegacy\avatar\*"; DestDir: "{app}\avatar"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "RBXLegacy\scripts\*"; DestDir: "{app}\scripts"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "RBXLegacy\udppipe.exe"; DestDir: "{app}"; Flags: ignoreversion
-Source: "RBXLegacy\Mono.Nat.dll"; DestDir: "{app}"; Flags: ignoreversion
+Source: "RBXLegacy\Open.Nat.dll"; DestDir: "{app}"; Flags: ignoreversion
[Icons]
Name: "{group}\RBXLegacy"; Filename: "{app}\RBXLegacyLauncher.exe"
@@ -50,5 +51,6 @@ Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\RBXLegacy"; Filena
[Run]
Filename: "{app}\RBXLegacyLauncher.exe"; Description: "Play RBXLegacy"; Flags: nowait postinstall skipifsilent
+Filename: "{app}\RBXLegacyURI.exe"; Description: "Install the URI"; Flags: nowait postinstall skipifsilent
Filename: "{app}\README.TXT"; Description: "View the README file"; Flags: postinstall shellexec skipifsilent unchecked
Filename: "{app}\changelog.txt"; Description: "View the changelog"; Flags: postinstall shellexec skipifsilent unchecked
diff --git a/RBXLegacySetupPreview.iss b/RBXLegacySetupPreview.iss
index 6ff4b34..76abc44 100644
--- a/RBXLegacySetupPreview.iss
+++ b/RBXLegacySetupPreview.iss
@@ -31,6 +31,7 @@ Name: "quicklaunchicon"; Description: "Create a icon on your Quick Start Menu";
[Files]
Source: "RBXLegacy-Preview\RBXLegacyLauncher.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "RBXLegacy-Preview\RBXLegacyLauncher.exe.config"; DestDir: "{app}"; Flags: ignoreversion
+Source: "RBXLegacy-Preview\RBXLegacyURI.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "RBXLegacy-Preview\README.TXT"; DestDir: "{app}"; Flags: ignoreversion
Source: "RBXLegacy-Preview\changelog.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "RBXLegacy-Preview\info.txt"; DestDir: "{app}"; Flags: ignoreversion
@@ -40,7 +41,7 @@ Source: "RBXLegacy-Preview\models\*"; DestDir: "{app}\models"; Flags: ignorevers
Source: "RBXLegacy-Preview\avatar\*"; DestDir: "{app}\avatar"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "RBXLegacy-Preview\scripts\*"; DestDir: "{app}\scripts"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "RBXLegacy-Preview\udppipe.exe"; DestDir: "{app}"; Flags: ignoreversion
-Source: "RBXLegacy-Preview\Mono.Nat.dll"; DestDir: "{app}"; Flags: ignoreversion
+Source: "RBXLegacy-Preview\Open.Nat.dll"; DestDir: "{app}"; Flags: ignoreversion
[Icons]
Name: "{group}\RBXLegacy-Preview"; Filename: "{app}\RBXLegacyLauncher.exe"
@@ -49,6 +50,7 @@ Name: "{commondesktop}\RBXLegacy-Preview"; Filename: "{app}\RBXLegacyLauncher.ex
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\RBXLegacy-Preview"; Filename: "{app}\RBXLegacyLauncher.exe"; Tasks: quicklaunchicon
[Run]
-Filename: "{app}\RBXLegacyLauncher.exe"; Description: "Play RBXLegacy 1.18 Preview"; Flags: nowait postinstall skipifsilent
+Filename: "{app}\RBXLegacyLauncher.exe"; Description: "Play RBXLegacy"; Flags: nowait postinstall skipifsilent
+Filename: "{app}\RBXLegacyURI.exe"; Description: "Install the URI"; Flags: nowait postinstall skipifsilent
Filename: "{app}\README.TXT"; Description: "View the README file"; Flags: postinstall shellexec skipifsilent unchecked
Filename: "{app}\changelog.txt"; Description: "View the changelog"; Flags: postinstall shellexec skipifsilent unchecked
diff --git a/RBXLegacyURI/RBXLegacyURI/Program.cs b/RBXLegacyURI/RBXLegacyURI/Program.cs
index 2278475..de02dc6 100644
--- a/RBXLegacyURI/RBXLegacyURI/Program.cs
+++ b/RBXLegacyURI/RBXLegacyURI/Program.cs
@@ -18,15 +18,18 @@ namespace RBXLegacyURI
private static void Main(string[] args)
{
- Console.Title = "RBXLegacy";
- try {
+ Console.Title = "RBXLegacy URI Installer";
+ try
+ {
Program.registerURI("RBXLegacy", AppDomain.CurrentDomain.BaseDirectory + "RBXLegacyLauncher.exe", "");
Program.registerURI("rbxlegacy", AppDomain.CurrentDomain.BaseDirectory + "RBXLegacyLauncher.exe", ""); // chromium
- Console.WriteLine("RBXLegacy has been installed on your computer successfully! You can now join RBXLegacy servers with URI.");
+ Console.WriteLine("RBXLegacy has been installed on your computer successfully! You can now join RBXLegacy servers with URI links and via the website!");
Console.WriteLine("Press any key to continue . . .");
Console.ReadKey();
- } catch (Exception) {
- Console.Title = "RBXLegacy - ERROR";
+ Console.WriteLine("z0mgh4x0r l0gs"); // how can they see this still??? 1337 h4x0r
+ }
+ catch (Exception)
+ {
Console.WriteLine("RBXLegacy failed to install the RBXLegacy URL protocol.");
Console.WriteLine("Make sure you're running this application as an administrator, and that RBXLegacyLauncher.exe is in the RBXLegacy folder.");
Console.WriteLine("Press any key to continue . . .");
diff --git a/RBXLegacyURI/RBXLegacyURI/RBXLegacyURI.csproj b/RBXLegacyURI/RBXLegacyURI/RBXLegacyURI.csproj
index 93381f3..ed6f875 100644
--- a/RBXLegacyURI/RBXLegacyURI/RBXLegacyURI.csproj
+++ b/RBXLegacyURI/RBXLegacyURI/RBXLegacyURI.csproj
@@ -10,6 +10,8 @@
v4.0
Client
Properties
+ Resources\rbxlegacyicon2.ico
+ False
x86
diff --git a/RBXLegacyURI/RBXLegacyURI/Resources/rbxlegacyicon2.ico b/RBXLegacyURI/RBXLegacyURI/Resources/rbxlegacyicon2.ico
new file mode 100644
index 0000000..73e2538
Binary files /dev/null and b/RBXLegacyURI/RBXLegacyURI/Resources/rbxlegacyicon2.ico differ
diff --git a/README.md b/README.md
index a38f6d6..828e660 100644
--- a/README.md
+++ b/README.md
@@ -20,3 +20,11 @@ If you find any problem(s) in RBXLegacy, [feel free to submit an issue here.](ht
If you know how to solve an (existing) issue in RBXLegacy, [you can submit a pull request for it.](https://github.com/Bitl/RBXLegacy-src/pulls)
And of course, we welcome everyone with new ideas. [You can post your idea in issues as well.](https://github.com/Bitl/RBXLegacy-src/issues)
+
+## Licence
+
+RBXLegacy is licenced under the GPL, but some components of it may use different licences.
+
+Open.NAT is licened under the MIT Licence. Please look in the Open.NAT folder for more information.
+
+