preview 2

This commit is contained in:
Bitl 2017-10-08 11:30:10 -07:00
parent 47d50ad458
commit 0d1c7cb76a
71 changed files with 3764 additions and 226 deletions

View File

@ -28,18 +28,18 @@
<Ref name="CameraSubject">null</Ref>
<token name="CameraType">0</token>
<CoordinateFrame name="CoordinateFrame">
<X>2.8825047</X>
<Y>16.8061104</Y>
<Z>19.8420525</Z>
<R00>0.990262866</R00>
<R01>-0.0670645982</R01>
<R02>0.121990994</R02>
<R10>3.7252903e-009</R10>
<R11>0.876308203</R11>
<R12>0.481750816</R12>
<R20>-0.139210135</R20>
<R21>-0.477059931</R21>
<R22>0.8677755</R22>
<X>21.9769001</X>
<Y>13.1075497</Y>
<Z>-9.91257381</Z>
<R00>-0.342057496</R00>
<R01>-0.313667655</R01>
<R02>0.885781765</R02>
<R10>-7.45057971e-009</R10>
<R11>0.942642868</R11>
<R12>0.333802998</R12>
<R20>-0.939678967</R20>
<R21>0.114179812</R21>
<R22>-0.322438091</R22>
</CoordinateFrame>
<CoordinateFrame name="Focus">
<X>-0.167192921</X>
@ -324,6 +324,112 @@
end
end
script.Parent.MouseButton1Down:connect(onClicked)</ProtectedString>
<bool name="archivable">true</bool>
</Properties>
</Item>
</Item>
<Item class="TextButton" referent="RBX15">
<Properties>
<bool name="Active">true</bool>
<bool name="AutoButtonColor">true</bool>
<Color3 name="BackgroundColor3">4288914085</Color3>
<float name="BackgroundTransparency">0.400000006</float>
<Color3 name="BorderColor3">4279970357</Color3>
<int name="BorderSizePixel">0</int>
<token name="Font">0</token>
<token name="FontSize">0</token>
<string name="Name">BackgroundColor</string>
<UDim2 name="Position">
<XS>1</XS>
<XO>-155</XO>
<YS>1</YS>
<YO>-75</YO>
</UDim2>
<bool name="Selected">false</bool>
<UDim2 name="Size">
<XS>0</XS>
<XO>150</XO>
<YS>0</YS>
<YO>20</YO>
</UDim2>
<token name="SizeConstraint">0</token>
<token name="Style">0</token>
<string name="Text">Change Background Color</string>
<Color3 name="TextColor3">4283256141</Color3>
<float name="TextTransparency">0</float>
<bool name="TextWrap">false</bool>
<token name="TextXAlignment">2</token>
<token name="TextYAlignment">1</token>
<bool name="Visible">true</bool>
<int name="ZIndex">1</int>
<bool name="archivable">true</bool>
</Properties>
<Item class="LocalScript" referent="RBX16">
<Properties>
<bool name="Disabled">false</bool>
<Content name="LinkedSource"><null></null></Content>
<string name="Name">LocalScript</string>
<ProtectedString name="Source">function onClicked()
if (game.Lighting.Sky.SkyboxBk == &quot;rbxasset://Sky/blue.jpg&quot;) then
game.Lighting.Sky.SkyboxBk = &quot;rbxasset://Sky/red.jpg&quot;
game.Lighting.Sky.SkyboxDn = &quot;rbxasset://Sky/red.jpg&quot;
game.Lighting.Sky.SkyboxFt = &quot;rbxasset://Sky/red.jpg&quot;
game.Lighting.Sky.SkyboxLf = &quot;rbxasset://Sky/red.jpg&quot;
game.Lighting.Sky.SkyboxRt = &quot;rbxasset://Sky/red.jpg&quot;
game.Lighting.Sky.SkyboxUp = &quot;rbxasset://Sky/red.jpg&quot;
elseif (game.Lighting.Sky.SkyboxBk == &quot;rbxasset://Sky/red.jpg&quot;) then
game.Lighting.Sky.SkyboxBk = &quot;rbxasset://Sky/green.jpg&quot;
game.Lighting.Sky.SkyboxDn = &quot;rbxasset://Sky/green.jpg&quot;
game.Lighting.Sky.SkyboxFt = &quot;rbxasset://Sky/green.jpg&quot;
game.Lighting.Sky.SkyboxLf = &quot;rbxasset://Sky/green.jpg&quot;
game.Lighting.Sky.SkyboxRt = &quot;rbxasset://Sky/green.jpg&quot;
game.Lighting.Sky.SkyboxUp = &quot;rbxasset://Sky/green.jpg&quot;
elseif (game.Lighting.Sky.SkyboxBk == &quot;rbxasset://Sky/green.jpg&quot;) then
game.Lighting.Sky.SkyboxBk = &quot;rbxasset://Sky/orange.jpg&quot;
game.Lighting.Sky.SkyboxDn = &quot;rbxasset://Sky/orange.jpg&quot;
game.Lighting.Sky.SkyboxFt = &quot;rbxasset://Sky/orange.jpg&quot;
game.Lighting.Sky.SkyboxLf = &quot;rbxasset://Sky/orange.jpg&quot;
game.Lighting.Sky.SkyboxRt = &quot;rbxasset://Sky/orange.jpg&quot;
game.Lighting.Sky.SkyboxUp = &quot;rbxasset://Sky/orange.jpg&quot;
elseif (game.Lighting.Sky.SkyboxBk == &quot;rbxasset://Sky/orange.jpg&quot;) then
game.Lighting.Sky.SkyboxBk = &quot;rbxasset://Sky/black.jpg&quot;
game.Lighting.Sky.SkyboxDn = &quot;rbxasset://Sky/black.jpg&quot;
game.Lighting.Sky.SkyboxFt = &quot;rbxasset://Sky/black.jpg&quot;
game.Lighting.Sky.SkyboxLf = &quot;rbxasset://Sky/black.jpg&quot;
game.Lighting.Sky.SkyboxRt = &quot;rbxasset://Sky/black.jpg&quot;
game.Lighting.Sky.SkyboxUp = &quot;rbxasset://Sky/black.jpg&quot;
elseif (game.Lighting.Sky.SkyboxBk == &quot;rbxasset://Sky/black.jpg&quot;) then
game.Lighting.Sky.SkyboxBk = &quot;rbxasset://Sky/white.jpg&quot;
game.Lighting.Sky.SkyboxDn = &quot;rbxasset://Sky/white.jpg&quot;
game.Lighting.Sky.SkyboxFt = &quot;rbxasset://Sky/white.jpg&quot;
game.Lighting.Sky.SkyboxLf = &quot;rbxasset://Sky/white.jpg&quot;
game.Lighting.Sky.SkyboxRt = &quot;rbxasset://Sky/white.jpg&quot;
game.Lighting.Sky.SkyboxUp = &quot;rbxasset://Sky/white.jpg&quot;
elseif (game.Lighting.Sky.SkyboxBk == &quot;rbxasset://Sky/white.jpg&quot;) then
game.Lighting.Sky.SkyboxBk = &quot;rbxasset://Sky/greenscreen.jpg&quot;
game.Lighting.Sky.SkyboxDn = &quot;rbxasset://Sky/greenscreen.jpg&quot;
game.Lighting.Sky.SkyboxFt = &quot;rbxasset://Sky/greenscreen.jpg&quot;
game.Lighting.Sky.SkyboxLf = &quot;rbxasset://Sky/greenscreen.jpg&quot;
game.Lighting.Sky.SkyboxRt = &quot;rbxasset://Sky/greenscreen.jpg&quot;
game.Lighting.Sky.SkyboxUp = &quot;rbxasset://Sky/greenscreen.jpg&quot;
elseif (game.Lighting.Sky.SkyboxBk == &quot;rbxasset://Sky/greenscreen.jpg&quot;) then
game.Lighting.Sky.SkyboxBk = &quot;rbxasset://Sky/blue.jpg&quot;
game.Lighting.Sky.SkyboxDn = &quot;rbxasset://Sky/blue.jpg&quot;
game.Lighting.Sky.SkyboxFt = &quot;rbxasset://Sky/blue.jpg&quot;
game.Lighting.Sky.SkyboxLf = &quot;rbxasset://Sky/blue.jpg&quot;
game.Lighting.Sky.SkyboxRt = &quot;rbxasset://Sky/blue.jpg&quot;
game.Lighting.Sky.SkyboxUp = &quot;rbxasset://Sky/blue.jpg&quot;
else
game.Lighting.Sky.SkyboxBk = &quot;rbxasset://Sky/red.jpg&quot;
game.Lighting.Sky.SkyboxDn = &quot;rbxasset://Sky/red.jpg&quot;
game.Lighting.Sky.SkyboxFt = &quot;rbxasset://Sky/red.jpg&quot;
game.Lighting.Sky.SkyboxLf = &quot;rbxasset://Sky/red.jpg&quot;
game.Lighting.Sky.SkyboxRt = &quot;rbxasset://Sky/red.jpg&quot;
game.Lighting.Sky.SkyboxUp = &quot;rbxasset://Sky/red.jpg&quot;
end
end
script.Parent.MouseButton1Down:connect(onClicked)</ProtectedString>
<bool name="archivable">true</bool>
</Properties>
@ -331,7 +437,7 @@ script.Parent.MouseButton1Down:connect(onClicked)</ProtectedString>
</Item>
</Item>
</Item>
<Item class="SoundService" referent="RBX15">
<Item class="SoundService" referent="RBX17">
<Properties>
<token name="AmbientReverb">0</token>
<float name="DistanceFactor">10</float>
@ -341,68 +447,68 @@ script.Parent.MouseButton1Down:connect(onClicked)</ProtectedString>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="CollectionService" referent="RBX16">
<Item class="CollectionService" referent="RBX18">
<Properties>
<string name="Name">CollectionService</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="PhysicsService" referent="RBX17">
<Item class="PhysicsService" referent="RBX19">
<Properties>
<string name="Name">PhysicsService</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="BadgeService" referent="RBX18">
<Item class="BadgeService" referent="RBX20">
<Properties>
<string name="Name">BadgeService</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="Geometry" referent="RBX19">
<Item class="Geometry" referent="RBX21">
<Properties>
<string name="Name">Geometry</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="RenderHooksService" referent="RBX20">
<Item class="RenderHooksService" referent="RBX22">
<Properties>
<string name="Name">RenderHooksService</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="SocialService" referent="RBX21">
<Item class="SocialService" referent="RBX23">
<Properties>
<string name="Name">SocialService</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="Debris" referent="RBX22">
<Item class="Debris" referent="RBX24">
<Properties>
<int name="MaxItems">1000</int>
<string name="Name">Debris</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="Timer" referent="RBX23">
<Item class="Timer" referent="RBX25">
<Properties>
<string name="Name">Instance</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="ScriptInformationProvider" referent="RBX24">
<Item class="ScriptInformationProvider" referent="RBX26">
<Properties>
<string name="Name">Instance</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="Selection" referent="RBX25">
<Item class="Selection" referent="RBX27">
<Properties>
<string name="Name">Selection</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="Lighting" referent="RBX26">
<Item class="Lighting" referent="RBX28">
<Properties>
<Color3 name="Ambient">4286874756</Color3>
<float name="Brightness">1</float>
@ -414,7 +520,7 @@ script.Parent.MouseButton1Down:connect(onClicked)</ProtectedString>
<string name="TimeOfDay">14:00:00</string>
<bool name="archivable">true</bool>
</Properties>
<Item class="Sky" referent="RBX27">
<Item class="Sky" referent="RBX29">
<Properties>
<bool name="CelestialBodiesShown">false</bool>
<string name="Name">Sky</string>
@ -429,19 +535,19 @@ script.Parent.MouseButton1Down:connect(onClicked)</ProtectedString>
</Properties>
</Item>
</Item>
<Item class="ChangeHistoryService" referent="RBX28">
<Item class="ChangeHistoryService" referent="RBX30">
<Properties>
<string name="Name">ChangeHistoryService</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="MeshContentProvider" referent="RBX29">
<Item class="MeshContentProvider" referent="RBX31">
<Properties>
<string name="Name">Instance</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="TextureContentProvider" referent="RBX30">
<Item class="TextureContentProvider" referent="RBX32">
<Properties>
<string name="Name">Instance</string>
<bool name="archivable">true</bool>

Binary file not shown.

8
Open.NAT/AUTHORS Normal file
View File

@ -0,0 +1,8 @@
Open.Nat is a Mono.Nat fork
= Mono.Nat authors
Alan McGovern <alan.mcgovern@gmail.com>
Ben Motmans <ben.motmans@gmail.com>
= Open.Nat author
Lucas Ontivero <lucasontivero@gmail.com>

24
Open.NAT/LICENSE Normal file
View File

@ -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.

35
Open.NAT/Open.Nat.sln Normal file
View File

@ -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

View File

@ -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)]

View File

@ -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<NatDevice> Receive();
NatDevice AnalyseReceivedResponse(IPAddress localAddress, byte[] response, IPEndPoint endpoint);
}
}

View File

@ -0,0 +1,115 @@
//
// Authors:
// Ben Motmans <ben.motmans@gmail.com>
// 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<NatDevice> _devices = new List<NatDevice>();
protected List<UdpClient> Sockets;
public EventHandler<DeviceEventArgs> DeviceFound;
internal DateTime NextSearch = DateTime.UtcNow;
public async Task<IEnumerable<NatDevice>> 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));
}
}
}

View File

@ -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
{
/// <summary>
/// Protocol to allow/disallow
/// </summary>
public enum Protocol
{
/// <summary>
/// Transport Control Protocol
/// </summary>
Tcp,
/// <summary>
/// Datagram Protocol
/// </summary>
Udp
}
}

View File

@ -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; }
}
}

View File

@ -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
{
/// <summary>
///
/// </summary>
[Serializable]
public class MappingException : Exception
{
/// <summary>
///
/// </summary>
public int ErrorCode { get; private set; }
/// <summary>
///
/// </summary>
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);
}
}
}

View File

@ -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
{
/// <summary>
///
/// </summary>
[Serializable]
public class NatDeviceNotFoundException : Exception
{
/// <summary>
///
/// </summary>
public NatDeviceNotFoundException()
{
}
/// <summary>
///
/// </summary>
/// <param name="message"></param>
public NatDeviceNotFoundException(string message)
: base(message)
{
}
/// <summary>
///
/// </summary>
/// <param name="message"></param>
/// <param name="innerException"></param>
public NatDeviceNotFoundException(string message, Exception innerException)
: base(message, innerException)
{
}
protected NatDeviceNotFoundException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}

View File

@ -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();
}
}
}

View File

@ -0,0 +1,273 @@
//
// Authors:
// Alan McGovern alan.mcgovern@gmail.com
// Ben Motmans <ben.motmans@gmail.com>
// 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
}
/// <summary>
/// Represents a port forwarding entry in the NAT translation table.
/// </summary>
public class Mapping
{
private DateTime _expiration;
private int _lifetime;
internal MappingLifetime LifetimeType { get; set; }
/// <summary>
/// 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.
/// </summary>
public string Description { get; internal set; }
/// <summary>
/// Gets the private ip.
/// </summary>
public IPAddress PrivateIP { get; internal set; }
/// <summary>
/// Gets the protocol.
/// </summary>
public Protocol Protocol { get; internal set; }
/// <summary>
/// The PrivatePort parameter specifies the port on a client machine to which all traffic
/// coming in on <see cref="#PublicPort">PublicPort</see> for the protocol specified by
/// <see cref="#Protocol">Protocol</see> should be forwarded to.
/// </summary>
/// <see cref="Protocol">Protocol enum</see>
public int PrivatePort { get; internal set; }
/// <summary>
/// Gets the public ip.
/// </summary>
public IPAddress PublicIP { get; internal set; }
/// <summary>
/// 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.
/// </summary>
public int PublicPort { get; internal set; }
/// <summary>
/// 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'.
/// </summary>
/// <remarks>
/// All portmappings are release automatically as part of the shutdown process when <see cref="NatDiscoverer">NatUtility</see>.<see cref="NatUtility#releaseonshutdown">ReleaseOnShutdown</see> 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.
/// </remarks>
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;
}
}
}
/// <summary>
/// Gets the expiration. The property value is calculated using <see cref="#Lifetime">Lifetime</see> property.
/// </summary>
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")
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Mapping"/> class.
/// </summary>
/// <param name="protocol">The protocol.</param>
/// <param name="privateIP">The private ip.</param>
/// <param name="privatePort">The private port.</param>
/// <param name="publicPort">The public port.</param>
/// <param name="lifetime">The lifetime.</param>
/// <param name="description">The description.</param>
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;
}
/// <summary>
/// Initializes a new instance of the <see cref="Mapping"/> class.
/// </summary>
/// <param name="protocol">The protocol.</param>
/// <param name="privatePort">The private port.</param>
/// <param name="publicPort">The public port.</param>
/// <remarks>
/// This constructor initializes a Permanent mapping. The description by deafult is "Open.NAT"
/// </remarks>
public Mapping(Protocol protocol, int privatePort, int publicPort)
: this(protocol, IPAddress.None, privatePort, publicPort, 0, "Open.NAT")
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Mapping"/> class.
/// </summary>
/// <param name="protocol">The protocol.</param>
/// <param name="privatePort">The private port.</param>
/// <param name="publicPort">The public port.</param>
/// <param name="description">The description.</param>
/// <remarks>
/// This constructor initializes a Permanent mapping.
/// </remarks>
public Mapping(Protocol protocol, int privatePort, int publicPort, string description)
: this(protocol, IPAddress.None, privatePort, publicPort, int.MaxValue, description)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Mapping"/> class.
/// </summary>
/// <param name="protocol">The protocol.</param>
/// <param name="privatePort">The private port.</param>
/// <param name="publicPort">The public port.</param>
/// <param name="lifetime">The lifetime.</param>
/// <param name="description">The description.</param>
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;
}
/// <summary>
/// Determines whether this instance is expired.
/// </summary>
/// <remarks>
/// Permanent mappings never expires.
/// </remarks>
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;
}
}
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String" /> that represents this instance.
/// </returns>
public override string ToString()
{
return string.Format("{0} {1} --> {2}:{3} ({4})",
Protocol == Protocol.Tcp ? "Tcp" : "Udp",
PublicPort,
PrivateIP,
PrivatePort,
Description);
}
}
}

View File

@ -0,0 +1,186 @@
//
// Authors:
// Alan McGovern alan.mcgovern@gmail.com
// Ben Motmans <ben.motmans@gmail.com>
// 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
{
/// <summary>
/// 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.
/// </summary>
public abstract class NatDevice
{
private readonly HashSet<Mapping> _openedMapping = new HashSet<Mapping>();
protected DateTime LastSeen { get; private set; }
internal void Touch()
{
LastSeen = DateTime.Now;
}
/// <summary>
/// Creates the port map asynchronous.
/// </summary>
/// <param name="mapping">The <see cref="Mapping">Mapping</see> entry.</param>
/// <example>
/// device.CreatePortMapAsync(new Mapping(Protocol.Tcp, 1700, 1600));
/// </example>
/// <exception cref="MappingException">MappingException</exception>
public abstract Task CreatePortMapAsync(Mapping mapping);
/// <summary>
/// Deletes a mapped port asynchronous.
/// </summary>
/// <param name="mapping">The <see cref="Mapping">Mapping</see> entry.</param>
/// <example>
/// device.DeletePortMapAsync(new Mapping(Protocol.Tcp, 1700, 1600));
/// </example>
/// <exception cref="MappingException">MappingException-class</exception>
public abstract Task DeletePortMapAsync(Mapping mapping);
/// <summary>
/// Gets all mappings asynchronous.
/// </summary>
/// <returns>
/// The list of all forwarded ports
/// </returns>
/// <example>
/// var mappings = await device.GetAllMappingsAsync();
/// foreach(var mapping in mappings)
/// {
/// Console.WriteLine(mapping)
/// }
/// </example>
/// <exception cref="MappingException">MappingException</exception>
public abstract Task<IEnumerable<Mapping>> GetAllMappingsAsync();
/// <summary>
/// Gets the external (visible) IP address asynchronous. This is the NAT device IP address
/// </summary>
/// <returns>
/// The public IP addrees
/// </returns>
/// <example>
/// Console.WriteLine("My public IP is: {0}", await device.GetExternalIPAsync());
/// </example>
/// <exception cref="MappingException">MappingException</exception>
public abstract Task<IPAddress> GetExternalIPAsync();
/// <summary>
/// Gets the specified mapping asynchronous.
/// </summary>
/// <param name="protocol">The protocol.</param>
/// <param name="port">The port.</param>
/// <returns>
/// The matching mapping
/// </returns>
public abstract Task<Mapping> 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<Mapping> 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);
}
}
}
}

View File

@ -0,0 +1,160 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Open.Nat
{
/// <summary>
///
/// </summary>
public class NatDiscoverer
{
/// <summary>
/// The <see cref="http://msdn.microsoft.com/en-us/library/vstudio/system.diagnostics.tracesource">TraceSource</see> instance
/// used for debugging and <see cref="https://github.com/lontivero/Open.Nat/wiki/Troubleshooting">Troubleshooting</see>
/// </summary>
/// <example>
/// NatUtility.TraceSource.Switch.Level = SourceLevels.Verbose;
/// NatUtility.TraceSource.Listeners.Add(new ConsoleListener());
/// </example>
/// <remarks>
/// 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.
/// </remarks>
/// <remarks>
/// Open.NAT only supports SourceLevels.Verbose, SourceLevels.Error, SourceLevels.Warning and SourceLevels.Information.
/// </remarks>
public readonly static TraceSource TraceSource = new TraceSource("Open.NAT");
private static readonly Dictionary<string, NatDevice> Devices = new Dictionary<string, NatDevice>();
// 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);
/// <summary>
/// Discovers and returns an UPnp or Pmp NAT device; otherwise a <see cref="NatDeviceNotFoundException">NatDeviceNotFoundException</see>
/// exception is thrown after 3 seconds.
/// </summary>
/// <returns>A NAT device</returns>
/// <exception cref="NatDeviceNotFoundException">when no NAT found before 3 seconds.</exception>
public async Task<NatDevice> DiscoverDeviceAsync()
{
var cts = new CancellationTokenSource(3 * 1000);
return await DiscoverDeviceAsync(PortMapper.Pmp | PortMapper.Upnp, cts);
}
/// <summary>
/// Discovers and returns a NAT device for the specified type; otherwise a <see cref="NatDeviceNotFoundException">NatDeviceNotFoundException</see>
/// exception is thrown when it is cancelled.
/// </summary>
/// <remarks>
/// It allows to specify the NAT type to discover as well as the cancellation token in order.
/// </remarks>
/// <param name="portMapper">Port mapper protocol; Upnp, Pmp or both</param>
/// <param name="cancellationTokenSource">Cancellation token source for cancelling the discovery process</param>
/// <returns>A NAT device</returns>
/// <exception cref="NatDeviceNotFoundException">when no NAT found before cancellation</exception>
public async Task<NatDevice> 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;
}
/// <summary>
/// Discovers and returns all NAT devices for the specified type. If no NAT device is found it returns an empty enumerable
/// </summary>
/// <param name="portMapper">Port mapper protocol; Upnp, Pmp or both</param>
/// <param name="cancellationTokenSource">Cancellation token source for cancelling the discovery process</param>
/// <returns>All found NAT devices</returns>
public async Task<IEnumerable<NatDevice>> 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<IEnumerable<NatDevice>> DiscoverAsync(PortMapper portMapper, bool onlyOne, CancellationTokenSource cts)
{
TraceSource.LogInfo("Start Discovery");
var searcherTasks = new List<Task<IEnumerable<NatDevice>>>();
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;
}
/// <summary>
/// Release all ports opened by Open.NAT.
/// </summary>
/// <remarks>
/// If ReleaseOnShutdown value is true, it release all the mappings created through the library.
/// </remarks>
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();
}
});
}
}
}

View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{F5D74163-145F-47BF-83DC-D0E07249C6CA}</ProjectGuid>
<OutputType>Library</OutputType>
<NoStandardLibraries>false</NoStandardLibraries>
<AssemblyName>Open.Nat</AssemblyName>
<RootNamespace>Open.Nat</RootNamespace>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>2.0</OldToolsVersion>
<TargetFrameworkProfile />
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<WarningLevel>4</WarningLevel>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<OutputType>Library</OutputType>
<RootNamespace>Open.Nat</RootNamespace>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
<DocumentationFile>bin\Debug\Open.Nat.XML</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<WarningLevel>4</WarningLevel>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<OutputType>Library</OutputType>
<RootNamespace>Open.Nat</RootNamespace>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>Open.Nat.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Finalizer.cs" />
<Compile Include="Utils\Guard.cs" />
<Compile Include="NatDevice.cs" />
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Enums\ProtocolType.cs" />
<Compile Include="EventArgs\DeviceEventArgs.cs" />
<Compile Include="Exceptions\MappingException.cs" />
<Compile Include="Discovery\ISearcher.cs" />
<Compile Include="Mapping.cs" />
<Compile Include="Exceptions\NatDeviceNotFoundException.cs" />
<Compile Include="NatDiscoverer.cs" />
<Compile Include="Pmp\PmpSearcher.cs" />
<Compile Include="Pmp\PmpConstants.cs" />
<Compile Include="Pmp\PmpNatDevice.cs" />
<Compile Include="PortMapper.cs" />
<Compile Include="Discovery\Searcher.cs" />
<Compile Include="Upnp\UpnpSearcher.cs" />
<Compile Include="Upnp\DiscoveryResponseMessage.cs" />
<Compile Include="Upnp\Messages\DiscoverDeviceMessage.cs" />
<Compile Include="Upnp\Messages\Requests\CreatePortMappingMessage.cs" />
<Compile Include="Upnp\Messages\Requests\DeletePortMappingMessage.cs" />
<Compile Include="Upnp\Messages\Requests\GetExternalIPAddressMessage.cs" />
<Compile Include="Upnp\Messages\Requests\GetGenericPortMappingEntry.cs" />
<Compile Include="Upnp\Messages\Requests\GetSpecificPortMappingEntryMessage.cs" />
<Compile Include="Upnp\ResponseMessageBase.cs" />
<Compile Include="Upnp\Messages\Responses\GetExternalIPAddressResponseMessage.cs" />
<Compile Include="Upnp\Messages\Responses\GetGenericPortMappingEntryResponseMessage.cs" />
<Compile Include="Upnp\RequestMessageBase.cs" />
<Compile Include="Upnp\SoapClient.cs" />
<Compile Include="Upnp\UpnpConstants.cs" />
<Compile Include="Upnp\UpnpNatDeviceInfo.cs" />
<Compile Include="Upnp\UpnpNatDevice.cs" />
<Compile Include="Utils\Extensions.cs" />
<Compile Include="Utils\IIPAddressesProvider.cs" />
<Compile Include="Utils\IPAddressesProvider.cs" />
<Compile Include="Utils\WellKnownConstants.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Open.Nat.snk" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
<ProjectExtensions>
<VisualStudio AllowExistingFolder="true" />
</ProjectExtensions>
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</Project>

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>Open.NAT</id>
<version>$version$</version>
<title>Open.NAT</title>
<authors>Alan McGovern, Ben Motmans, Lucas Ontivero</authors>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>https://github.com/lontivero/Open.NAT</projectUrl>
<iconUrl>http://github.com/lontivero/Open.Nat/raw/gh-pages/images/logos/64.jpg</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>
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).
</description>
<summary>Library to allow port forwarding in NAT devices that support UPNP and/or PMP.</summary>
<language>en-US</language>
<copyright>Please see LICENSE for more details.</copyright>
<tags>NAT TRANSVERSAL UPNP PMP PORT FORWARD</tags>
<releaseNotes>
**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
</releaseNotes>
</metadata>
</package>

Binary file not shown.

View File

@ -0,0 +1,63 @@
//
// Authors:
// Ben Motmans <ben.motmans@gmail.com>
// 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
}
}

View File

@ -0,0 +1,192 @@
//
// Authors:
// Ben Motmans <ben.motmans@gmail.com>
// 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<IEnumerable<Mapping>> GetAllMappingsAsync()
{
throw new NotSupportedException();
}
public override Task<IPAddress> GetExternalIPAsync()
{
return Task.Run(() => _publicAddress)
.TimeoutAfter(TimeSpan.FromSeconds(4));
}
public override Task<Mapping> GetSpecificMappingAsync(Protocol protocol, int port)
{
throw new NotSupportedException("NAT-PMP does not specify a way to get a specific port map");
}
private async Task<Mapping> InternalCreatePortMapAsync(Mapping mapping, bool create)
{
var package = new List<byte>();
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);
}
}
}

View File

@ -0,0 +1,145 @@
//
// Authors:
// Ben Motmans <ben.motmans@gmail.com>
// 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<UdpClient, IEnumerable<IPEndPoint>> _gatewayLists;
private int _timeout;
internal PmpSearcher(IIPAddressesProvider ipprovider)
{
_ipprovider = ipprovider;
_timeout = 250;
CreateSocketsAndAddGateways();
}
private void CreateSocketsAndAddGateways()
{
Sockets = new List<UdpClient>();
_gatewayLists = new Dictionary<UdpClient, IEnumerable<IPEndPoint>>();
try
{
List<IPEndPoint> 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);
}
}
}

View File

@ -0,0 +1,21 @@
using System;
namespace Open.Nat
{
/// <summary>
/// Protocol that should be used for searching a NAT device.
/// </summary>
[Flags]
public enum PortMapper
{
/// <summary>
/// Use only Port Mapping Protocol
/// </summary>
Pmp = 1,
/// <summary>
/// Use only Universal Plug and Play
/// </summary>
Upnp = 2
}
}

View File

@ -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<string, string> _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()]; }
}
}
}

View File

@ -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
{
/// <summary>
/// The message sent to discover all uPnP devices on the network
/// </summary>
/// <returns></returns>
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;
}
}
}

View File

@ -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<string, object> ToXml()
{
string remoteHost = _mapping.PublicIP.Equals(IPAddress.None)
? string.Empty
: _mapping.PublicIP.ToString();
return new Dictionary<string, object>
{
{"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}
};
}
}
}

View File

@ -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<string, object> ToXml()
{
return new Dictionary<string, object>
{
{"NewRemoteHost", string.Empty},
{"NewExternalPort", _mapping.PublicPort},
{"NewProtocol", _mapping.Protocol == Protocol.Tcp ? "TCP" : "UDP"}
};
}
}
}

View File

@ -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<string, object> ToXml()
{
return new Dictionary<string, object>();
}
}
}

View File

@ -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<string, object> ToXml()
{
return new Dictionary<string, object>
{
{"NewPortMappingIndex", _index}
};
}
}
}

View File

@ -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<string, object> ToXml()
{
return new Dictionary<string, object>
{
{"NewRemoteHost", string.Empty},
{"NewExternalPort", _externalPort},
{"NewProtocol", _protocol == Protocol.Tcp ? "TCP" : "UDP"}
};
}
}
}

View File

@ -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
{
}
}

View File

@ -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
{
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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<string, object> ToXml();
}
}

View File

@ -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;
}
}
}

View File

@ -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<XmlDocument> InvokeAsync(string operationName, IDictionary<string, object> 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<WebResponse> 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<KeyValuePair<string, object>> args)
{
var sb = new StringBuilder();
sb.AppendLine("<s:Envelope ");
sb.AppendLine(" xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" ");
sb.AppendLine(" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">");
sb.AppendLine(" <s:Body>");
sb.AppendLine(" <u:" + operationName + " xmlns:u=\"" + _serviceType + "\">");
foreach (var a in args)
{
sb.AppendLine(" <" + a.Key + ">" + Convert.ToString(a.Value, CultureInfo.InvariantCulture) +
"</" + a.Key + ">");
}
sb.AppendLine(" </u:" + operationName + ">");
sb.AppendLine(" </s:Body>");
sb.Append("</s:Envelope>\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;
}
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,198 @@
//
// Authors:
// Alan McGovern alan.mcgovern@gmail.com
// Ben Motmans <ben.motmans@gmail.com>
// 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<IPAddress> 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<IEnumerable<Mapping>> GetAllMappingsAsync()
{
var index = 0;
var mappings = new List<Mapping>();
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<Mapping> 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);
}
}
}

View File

@ -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; }
}
}

View File

@ -0,0 +1,268 @@
//
// Authors:
// Ben Motmans <ben.motmans@gmail.com>
// 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<Uri, NatDevice> _devices;
private readonly Dictionary<IPAddress, DateTime> _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<Uri, NatDevice>();
_lastFetched = new Dictionary<IPAddress, DateTime>();
}
private List<UdpClient> CreateSockets()
{
var clients = new List<UdpClient>();
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;
}
}
}
}

View File

@ -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<TResult> TimeoutAfter<TResult>(this Task<TResult> 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.");
}
}
}

View File

@ -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);
}
}
}

View File

@ -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<IPAddress> DnsAddresses();
IEnumerable<IPAddress> GatewayAddresses();
IEnumerable<IPAddress> UnicastAddresses();
}
}

View File

@ -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<IPAddress> UnicastAddresses()
{
return IPAddresses(p => p.UnicastAddresses.Select(x => x.Address));
}
public IEnumerable<IPAddress> DnsAddresses()
{
return IPAddresses(p => p.DnsAddresses);
}
public IEnumerable<IPAddress> GatewayAddresses()
{
return IPAddresses(p => p.GatewayAddresses.Select(x => x.Address));
}
#endregion
private static IEnumerable<IPAddress> IPAddresses(Func<IPInterfaceProperties, IEnumerable<IPAddress>> 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;
}
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -112,12 +112,12 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="pictureBox5.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
@ -1273,7 +1273,7 @@
<data name="button1308.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@ -1417,7 +1417,7 @@
<data name="button1208.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@ -1561,7 +1561,7 @@
<data name="button1108.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@ -1705,7 +1705,7 @@
<data name="button1008.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@ -1849,7 +1849,7 @@
<data name="button908.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@ -1993,7 +1993,7 @@
<data name="button708.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@ -2137,7 +2137,7 @@
<data name="button608.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE
@ -2281,7 +2281,7 @@
<data name="button508.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAaQAAAGkCAYAAAB+TFE1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
vQAADr0BR/uQrQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
vAAADrwBlbxySQAAIEdJREFUeF7t3Qtz1EbahuHv//+w9e4mBHO0YSEH7ACOsQHb2GAb5qtbNU1NHCG1
ZkbSK/V9VXWFeDQ6tFT9jE7d/7eQJCkAA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaS
JCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmS
QjCQJEkhGEiSpBAMJElSCAaSJCkEA0mSFIKBJEkKwUCSJIVgIEmSQjCQJEkhGEiSpBAMJElSCAaSJCkE

View File

@ -112,9 +112,9 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -112,10 +112,10 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="richTextBox1.Text" xml:space="preserve">
<value>VERSION CODENAME DOCUMENTATION

View File

@ -112,10 +112,10 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="pictureBox1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">

View File

@ -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();
}

View File

@ -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<evNATdoneargs> 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<Mono.Nat.DeviceEventArgs>(NatUtility_DeviceFound);
Mono.Nat.NatUtility.DeviceLost += new EventHandler<Mono.Nat.DeviceEventArgs>(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();
}

View File

@ -112,16 +112,16 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="pictureBox1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAMYAAAAhCAYAAACC2tRnAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
vgAADr4B6kKxwAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAAYO0lEQVR4Xu1c
vAAADrwBlbxySQAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAAYO0lEQVR4Xu1c
CXgUVba+ne5sEPYdJAKCOiqCDqPCoIgbDjow41NHEARRH47PcUNRouI2jLKKIgIiKgg+NtFRILImQJAd
M7INARJCEsOSAFl7q+r/nXPrVqe6Ux1ah+D3vi/n+/6vqqvOPffce89/t6pqYScQ4k7CNgjXIThcWXS0
ICYLDlEFUU9BXQ/qWXXoXozI8jtFVmWsAb+LrtM1iRBdy2/j3u8I8cqvOEJXCOc9ZHMUnb9IOoyxpP8e
@ -235,7 +235,7 @@
<data name="pictureBox2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAMYAAAAhCAYAAACC2tRnAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wAAADsABataJCQAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAAYO0lEQVR4Xu1c
vQAADr0BR/uQrQAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTFH80I3AAAYO0lEQVR4Xu1c
CXgUVba+ne5sEPYdJAKCOiqCDqPCoIgbDjow41NHEARRH47PcUNRouI2jLKKIgIiKgg+NtFRILImQJAd
M7INARJCEsOSAFl7q+r/nXPrVqe6Ux1ah+D3vi/n+/6vqqvOPffce89/t6pqYScQ4k7CNgjXIThcWXS0
ICYLDlEFUU9BXQ/qWXXoXozI8jtFVmWsAb+LrtM1iRBdy2/j3u8I8cqvOEJXCOc9ZHMUnb9IOoyxpP8e

View File

@ -112,10 +112,10 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">

View File

@ -7,7 +7,7 @@
<OutputType>WinExe</OutputType>
<RootNamespace>RBXLegacyLauncher</RootNamespace>
<AssemblyName>RBXLegacyLauncher</AssemblyName>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<AppDesignerFolder>Properties</AppDesignerFolder>
@ -49,14 +49,23 @@
<StartProgram>..\..\..\RBXLegacy\release\RBXLegacy\RBXLegacyLauncher.exe</StartProgram>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Nat">
<HintPath>Resources\Mono.Nat.dll</HintPath>
<Reference Include="Open.Nat">
<HintPath>Resources\Open.Nat.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="CharacterCustomization.cs" />
@ -110,9 +119,6 @@
<EmbeddedResource Include="DocForm.resx">
<DependentUpon>DocForm.Designer.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Form1.resx">
<DependentUpon>ClientSettings.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="LoaderForm.resx">
<DependentUpon>LoaderForm.cs</DependentUpon>
</EmbeddedResource>

View File

@ -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
{

View File

@ -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);
//

View File

@ -112,12 +112,12 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAYAEBAAAAAAIABoBAAAZgAAACAgAAAAACAAqBAAAM4EAAAwMAAAAAAgAKglAAB2FQAAQEAAAAAA

View File

@ -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;

View File

@ -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))

View File

@ -112,12 +112,12 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAYAEBAAAAAAIABoBAAAZgAAACAgAAAAACAAqBAAAM4EAAAwMAAAAAAgAKglAAB2FQAAQEAAAAAA

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v2.0.50727" />
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

View File

@ -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

View File

@ -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

View File

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

View File

@ -10,6 +10,8 @@
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<AppDesignerFolder>Properties</AppDesignerFolder>
<ApplicationIcon>Resources\rbxlegacyicon2.ico</ApplicationIcon>
<NoWin32Manifest>False</NoWin32Manifest>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

View File

@ -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.