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) + + ""); + } + 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. + +