diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-10-27 23:11:21 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-10-27 23:11:21 -0400 |
| commit | bdcaf5dd023a6bc0470915e07cc7fe7a46cb6c5d (patch) | |
| tree | a52531d9d7a169567a7f2ee41ffd6539eb46359a /Mono.Nat | |
| parent | 5dca85fe150c2f13f58e04279101576536098a4c (diff) | |
trim nat project
Diffstat (limited to 'Mono.Nat')
20 files changed, 142 insertions, 1434 deletions
diff --git a/Mono.Nat/AbstractNatDevice.cs b/Mono.Nat/AbstractNatDevice.cs index e998a6ea4..1b4216002 100644 --- a/Mono.Nat/AbstractNatDevice.cs +++ b/Mono.Nat/AbstractNatDevice.cs @@ -52,43 +52,5 @@ namespace Mono.Nat } public abstract Task CreatePortMap(Mapping mapping); - - public virtual void DeletePortMap (Mapping mapping) - { - IAsyncResult result = BeginDeletePortMap (mapping, null, mapping); - EndDeletePortMap(result); - } - - public virtual Mapping[] GetAllMappings () - { - IAsyncResult result = BeginGetAllMappings (null, null); - return EndGetAllMappings (result); - } - - public virtual IPAddress GetExternalIP () - { - IAsyncResult result = BeginGetExternalIP(null, null); - return EndGetExternalIP(result); - } - - public virtual Mapping GetSpecificMapping (Protocol protocol, int port) - { - IAsyncResult result = this.BeginGetSpecificMapping (protocol, port, null, null); - return this.EndGetSpecificMapping(result); - } - - public abstract IAsyncResult BeginCreatePortMap(Mapping mapping, AsyncCallback callback, object asyncState); - public abstract IAsyncResult BeginDeletePortMap (Mapping mapping, AsyncCallback callback, object asyncState); - - public abstract IAsyncResult BeginGetAllMappings (AsyncCallback callback, object asyncState); - public abstract IAsyncResult BeginGetExternalIP (AsyncCallback callback, object asyncState); - public abstract IAsyncResult BeginGetSpecificMapping(Protocol protocol, int externalPort, AsyncCallback callback, object asyncState); - - public abstract void EndCreatePortMap (IAsyncResult result); - public abstract void EndDeletePortMap (IAsyncResult result); - - public abstract Mapping[] EndGetAllMappings (IAsyncResult result); - public abstract IPAddress EndGetExternalIP (IAsyncResult result); - public abstract Mapping EndGetSpecificMapping (IAsyncResult result); } } diff --git a/Mono.Nat/INatDevice.cs b/Mono.Nat/INatDevice.cs index 44ba5223b..b0401627b 100644 --- a/Mono.Nat/INatDevice.cs +++ b/Mono.Nat/INatDevice.cs @@ -37,26 +37,8 @@ namespace Mono.Nat public interface INatDevice { Task CreatePortMap (Mapping mapping); - void DeletePortMap (Mapping mapping); IPAddress LocalAddress { get; } - Mapping[] GetAllMappings (); - IPAddress GetExternalIP (); - Mapping GetSpecificMapping (Protocol protocol, int port); - - IAsyncResult BeginCreatePortMap (Mapping mapping, AsyncCallback callback, object asyncState); - IAsyncResult BeginDeletePortMap (Mapping mapping, AsyncCallback callback, object asyncState); - - IAsyncResult BeginGetAllMappings (AsyncCallback callback, object asyncState); - IAsyncResult BeginGetExternalIP (AsyncCallback callback, object asyncState); - IAsyncResult BeginGetSpecificMapping (Protocol protocol, int externalPort, AsyncCallback callback, object asyncState); - - void EndCreatePortMap (IAsyncResult result); - void EndDeletePortMap (IAsyncResult result); - - Mapping[] EndGetAllMappings (IAsyncResult result); - IPAddress EndGetExternalIP (IAsyncResult result); - Mapping EndGetSpecificMapping (IAsyncResult result); DateTime LastSeen { get; set; } } diff --git a/Mono.Nat/Mono.Nat.csproj b/Mono.Nat/Mono.Nat.csproj index c9d79bbdf..273bdb20c 100644 --- a/Mono.Nat/Mono.Nat.csproj +++ b/Mono.Nat/Mono.Nat.csproj @@ -56,20 +56,11 @@ <Compile Include="Pmp\PmpNatDevice.cs" /> <Compile Include="Pmp\Searchers\PmpSearcher.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="Upnp\AsyncResults\GetAllMappingsAsyncResult.cs" /> - <Compile Include="Upnp\AsyncResults\PortMapAsyncResult.cs" /> <Compile Include="Upnp\Messages\DiscoverDeviceMessage.cs" /> <Compile Include="Upnp\Messages\ErrorMessage.cs" /> <Compile Include="Upnp\Messages\GetServicesMessage.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\Messages\Responses\CreatePortMappingResponseMessage.cs" /> - <Compile Include="Upnp\Messages\Responses\DeletePortMappingResponseMessage.cs" /> - <Compile Include="Upnp\Messages\Responses\GetExternalIPAddressResponseMessage.cs" /> - <Compile Include="Upnp\Messages\Responses\GetGenericPortMappingEntryResponseMessage.cs" /> <Compile Include="Upnp\Messages\UpnpMessage.cs" /> <Compile Include="Upnp\Searchers\UpnpSearcher.cs" /> <Compile Include="Upnp\Upnp.cs" /> @@ -89,6 +80,9 @@ <Name>MediaBrowser.Model</Name> </ProjectReference> </ItemGroup> + <ItemGroup> + <Folder Include="Upnp\AsyncResults\" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. diff --git a/Mono.Nat/NatUtility.cs b/Mono.Nat/NatUtility.cs index 78788685a..1ba12f346 100644 --- a/Mono.Nat/NatUtility.cs +++ b/Mono.Nat/NatUtility.cs @@ -34,6 +34,7 @@ using System.Linq; using System.Collections.Generic; using System.IO; using System.Net.NetworkInformation; +using System.Threading.Tasks; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Dlna; using MediaBrowser.Model.Logging; @@ -46,8 +47,6 @@ namespace Mono.Nat public static event EventHandler<DeviceEventArgs> DeviceFound; public static event EventHandler<DeviceEventArgs> DeviceLost; - public static event EventHandler<UnhandledExceptionEventArgs> UnhandledException; - private static List<ISearcher> controllers; private static bool verbose; @@ -87,9 +86,8 @@ namespace Mono.Nat DeviceLost(sender, args); }; }); - Thread t = new Thread(SearchAndListen); - t.IsBackground = true; - t.Start(); + + Task.Factory.StartNew(SearchAndListen, TaskCreationOptions.LongRunning); } internal static void Log(string format, params object[] args) @@ -99,7 +97,7 @@ namespace Mono.Nat logger.Debug(format, args); } - private static void SearchAndListen() + private static async Task SearchAndListen() { while (true) { @@ -115,18 +113,19 @@ namespace Mono.Nat } foreach (ISearcher s in controllers) + { if (s.NextSearch < DateTime.Now && enabledProtocols.Contains(s.Protocol)) { Log("Searching for: {0}", s.GetType().Name); - s.Search(); + s.Search(); } + } } catch (Exception e) { - if (UnhandledException != null) - UnhandledException(typeof(NatUtility), new UnhandledExceptionEventArgs(e, false)); + } - Thread.Sleep(10); + await Task.Delay(100).ConfigureAwait(false); } } diff --git a/Mono.Nat/Pmp/PmpNatDevice.cs b/Mono.Nat/Pmp/PmpNatDevice.cs index 0deaf4af8..adb08fce3 100644 --- a/Mono.Nat/Pmp/PmpNatDevice.cs +++ b/Mono.Nat/Pmp/PmpNatDevice.cs @@ -34,234 +34,166 @@ using System.Threading.Tasks; namespace Mono.Nat.Pmp { - internal sealed class PmpNatDevice : AbstractNatDevice, IEquatable<PmpNatDevice> - { - private AsyncResult externalIpResult; - private bool pendingOp; - private IPAddress localAddress; - private IPAddress publicAddress; - - internal PmpNatDevice (IPAddress localAddress, IPAddress publicAddress) - { - this.localAddress = localAddress; - this.publicAddress = publicAddress; - } - - public override IPAddress LocalAddress - { - get { return localAddress; } - } + internal sealed class PmpNatDevice : AbstractNatDevice, IEquatable<PmpNatDevice> + { + private IPAddress localAddress; + private IPAddress publicAddress; - public override Task CreatePortMap(Mapping mapping) - { - CreatePortMap(mapping, true); - return Task.FromResult(true); - } - - private void StartOp(ref AsyncResult result, AsyncCallback callback, object asyncState) + internal PmpNatDevice(IPAddress localAddress, IPAddress publicAddress) { - if (pendingOp == true) - throw new InvalidOperationException("Can only have one simultaenous async operation"); - - pendingOp = true; - result = new AsyncResult(callback, asyncState); + this.localAddress = localAddress; + this.publicAddress = publicAddress; } - private void EndOp(IAsyncResult supplied, ref AsyncResult actual) + public override IPAddress LocalAddress { - if (supplied == null) - throw new ArgumentNullException("result"); + get { return localAddress; } + } - if (supplied != actual) - throw new ArgumentException("Supplied IAsyncResult does not match the stored result"); + public override Task CreatePortMap(Mapping mapping) + { + return InternalCreatePortMapAsync(mapping, true); + } - if (!supplied.IsCompleted) - supplied.AsyncWaitHandle.WaitOne(); + public override bool Equals(object obj) + { + PmpNatDevice device = obj as PmpNatDevice; + return (device == null) ? false : this.Equals(device); + } - if (actual.StoredException != null) - throw actual.StoredException; + public override int GetHashCode() + { + return this.publicAddress.GetHashCode(); + } - pendingOp = false; - actual = null; + public bool Equals(PmpNatDevice other) + { + return (other == null) ? false : this.publicAddress.Equals(other.publicAddress); } - - public override bool Equals(object obj) - { - PmpNatDevice device = obj as PmpNatDevice; - return (device == null) ? false : this.Equals(device); - } - - public override int GetHashCode () - { - return this.publicAddress.GetHashCode(); - } - public bool Equals (PmpNatDevice other) - { - return (other == null) ? false : this.publicAddress.Equals(other.publicAddress); - } + 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; - private Mapping CreatePortMap (Mapping mapping, bool create) - { - List<byte> package = new List<byte> (); - - package.Add (PmpConstants.Version); - package.Add (mapping.Protocol == Protocol.Tcp ? PmpConstants.OperationCodeTcp : PmpConstants.OperationCodeUdp); - package.Add ((byte)0); //reserved - package.Add ((byte)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))); + using (var udpClient = new UdpClient()) + { + var cancellationTokenSource = new CancellationTokenSource(); - CreatePortMapAsyncState state = new CreatePortMapAsyncState (); - state.Buffer = package.ToArray (); - state.Mapping = mapping; + while (attempt < PmpConstants.RetryAttempts) + { + await udpClient.SendAsync(buffer, buffer.Length, + new IPEndPoint(LocalAddress, PmpConstants.ServerPort)); - ThreadPool.QueueUserWorkItem (new WaitCallback (CreatePortMapAsync), state); - WaitHandle.WaitAll (new WaitHandle[] {state.ResetEvent}); - - if (!state.Success) { - string type = create ? "create" : "delete"; - throw new MappingException (String.Format ("Failed to {0} portmap (protocol={1}, private port={2}", type, mapping.Protocol, mapping.PrivatePort)); - } - - return state.Mapping; - } - - private void CreatePortMapAsync (object obj) - { - CreatePortMapAsyncState state = obj as CreatePortMapAsyncState; - - UdpClient udpClient = new UdpClient (); - CreatePortMapListenState listenState = new CreatePortMapListenState (state, udpClient); + if (attempt == 0) + { + Task.Run(() => CreatePortMapListen(udpClient, mapping, cancellationTokenSource.Token)); + } - int attempt = 0; - int delay = PmpConstants.RetryDelay; - - ThreadPool.QueueUserWorkItem (new WaitCallback (CreatePortMapListen), listenState); + attempt++; + delay *= 2; + await Task.Delay(delay).ConfigureAwait(false); + } - while (attempt < PmpConstants.RetryAttempts && !listenState.Success) { - udpClient.Send (state.Buffer, state.Buffer.Length, new IPEndPoint (localAddress, PmpConstants.ServerPort)); - listenState.UdpClientReady.Set(); + cancellationTokenSource.Cancel(); + } + } + catch (OperationCanceledException) + { - attempt++; - delay *= 2; - Thread.Sleep (delay); - } - - state.Success = listenState.Success; - - udpClient.Close (); - state.ResetEvent.Set (); - } - - private void CreatePortMapListen (object obj) - { - CreatePortMapListenState state = obj as CreatePortMapListenState; + } + catch (Exception e) + { + string type = create ? "create" : "delete"; + string message = String.Format("Failed to {0} portmap (protocol={1}, private port={2}) {3}", + type, + mapping.Protocol, + mapping.PrivatePort, + e.Message); + NatUtility.Log(message); + var pmpException = e as MappingException; + throw new MappingException(message, pmpException); + } + + return mapping; + } - UdpClient udpClient = state.UdpClient; - state.UdpClientReady.WaitOne(); // Evidently UdpClient has some lazy-init Send/Receive race? - IPEndPoint endPoint = new IPEndPoint (localAddress, PmpConstants.ServerPort); - - while (!state.Success) + private async void CreatePortMapListen(UdpClient udpClient, Mapping mapping, CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) { - byte[] data; - try - { - data = udpClient.Receive(ref endPoint); - } - catch (SocketException) - { - state.Success = false; - return; - } + var result = await udpClient.ReceiveAsync().ConfigureAwait(false); + var endPoint = result.RemoteEndPoint; + byte[] data = data = result.Buffer; - catch (ObjectDisposedException) - { - state.Success = false; - return; - } - - if (data.Length < 16) - continue; + if (data.Length < 16) + continue; - if (data[0] != PmpConstants.Version) - continue; - - byte opCode = (byte)(data[1] & (byte)127); - - Protocol protocol = Protocol.Tcp; - if (opCode == PmpConstants.OperationCodeUdp) - protocol = Protocol.Udp; + if (data[0] != PmpConstants.Version) + continue; - short resultCode = IPAddress.NetworkToHostOrder (BitConverter.ToInt16 (data, 2)); - uint epoch = (uint)IPAddress.NetworkToHostOrder (BitConverter.ToInt32 (data, 4)); + var opCode = (byte)(data[1] & 127); - int privatePort = IPAddress.NetworkToHostOrder (BitConverter.ToInt16 (data, 8)); - int publicPort = IPAddress.NetworkToHostOrder (BitConverter.ToInt16 (data, 10)); + var protocol = Protocol.Tcp; + if (opCode == PmpConstants.OperationCodeUdp) + protocol = Protocol.Udp; - uint lifetime = (uint)IPAddress.NetworkToHostOrder (BitConverter.ToInt32 (data, 12)); + short resultCode = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data, 2)); + int epoch = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data, 4)); - if (publicPort < 0 || privatePort < 0 || resultCode != PmpConstants.ResultCodeSuccess) - { - state.Success = false; - return; - } - - if (lifetime == 0) - { - //mapping was deleted - state.Success = true; - state.Mapping = null; - return; - } - else + 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) { - //mapping was created - //TODO: verify that the private port+protocol are a match - Mapping mapping = state.Mapping; - mapping.PublicPort = publicPort; - mapping.Protocol = protocol; - mapping.Expiration = DateTime.Now.AddSeconds (lifetime); + 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]); + } - state.Success = true; - } - } - } + 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; + } + } /// <summary> /// Overridden. /// </summary> /// <returns></returns> - public override string ToString( ) + public override string ToString() { - return String.Format( "PmpNatDevice - Local Address: {0}, Public IP: {1}, Last Seen: {2}", - this.localAddress, this.publicAddress, this.LastSeen ); + return String.Format("PmpNatDevice - Local Address: {0}, Public IP: {1}, Last Seen: {2}", + this.localAddress, this.publicAddress, this.LastSeen); } - - - private class CreatePortMapAsyncState - { - internal byte[] Buffer; - internal ManualResetEvent ResetEvent = new ManualResetEvent (false); - internal Mapping Mapping; - - internal bool Success; - } - - private class CreatePortMapListenState - { - internal volatile bool Success; - internal Mapping Mapping; - internal UdpClient UdpClient; - internal ManualResetEvent UdpClientReady; - - internal CreatePortMapListenState (CreatePortMapAsyncState state, UdpClient client) - { - Mapping = state.Mapping; - UdpClient = client; UdpClientReady = new ManualResetEvent(false); - } - } - } + } }
\ No newline at end of file diff --git a/Mono.Nat/Upnp/AsyncResults/GetAllMappingsAsyncResult.cs b/Mono.Nat/Upnp/AsyncResults/GetAllMappingsAsyncResult.cs deleted file mode 100644 index 51ecfbaf0..000000000 --- a/Mono.Nat/Upnp/AsyncResults/GetAllMappingsAsyncResult.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// 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; -using System.Collections.Generic; -using System.Text; -using System.Net; - -namespace Mono.Nat.Upnp -{ - internal class GetAllMappingsAsyncResult : PortMapAsyncResult - { - private List<Mapping> mappings; - private Mapping specificMapping; - - public GetAllMappingsAsyncResult(WebRequest request, AsyncCallback callback, object asyncState) - : base(request, callback, asyncState) - { - mappings = new List<Mapping>(); - } - - public List<Mapping> Mappings - { - get { return this.mappings; } - } - - public Mapping SpecificMapping - { - get { return this.specificMapping; } - set { this.specificMapping = value; } - } - } -} diff --git a/Mono.Nat/Upnp/AsyncResults/PortMapAsyncResult.cs b/Mono.Nat/Upnp/AsyncResults/PortMapAsyncResult.cs deleted file mode 100644 index d8ac3fe61..000000000 --- a/Mono.Nat/Upnp/AsyncResults/PortMapAsyncResult.cs +++ /dev/null @@ -1,75 +0,0 @@ -// -// 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; -using System.Net; -using System.Threading; - -namespace Mono.Nat.Upnp -{ - internal class PortMapAsyncResult : AsyncResult - { - private WebRequest request; - private MessageBase savedMessage; - - protected PortMapAsyncResult(WebRequest request, AsyncCallback callback, object asyncState) - : base (callback, asyncState) - { - this.request = request; - } - - internal WebRequest Request - { - get { return this.request; } - set { this.request = value; } - } - - internal MessageBase SavedMessage - { - get { return this.savedMessage; } - set { this.savedMessage = value; } - } - - internal static PortMapAsyncResult Create (MessageBase message, WebRequest request, AsyncCallback storedCallback, object asyncState) - { - if (message is GetGenericPortMappingEntry) - return new GetAllMappingsAsyncResult(request, storedCallback, asyncState); - - if (message is GetSpecificPortMappingEntryMessage) - { - GetSpecificPortMappingEntryMessage mapMessage = (GetSpecificPortMappingEntryMessage)message; - GetAllMappingsAsyncResult result = new GetAllMappingsAsyncResult(request, storedCallback, asyncState); - - result.SpecificMapping = new Mapping(mapMessage.protocol, 0, mapMessage.externalPort, 0); - return result; - } - - return new PortMapAsyncResult(request, storedCallback, asyncState); - } - } -} diff --git a/Mono.Nat/Upnp/Messages/ErrorMessage.cs b/Mono.Nat/Upnp/Messages/ErrorMessage.cs index f2755c93e..7c0c44d8e 100644 --- a/Mono.Nat/Upnp/Messages/ErrorMessage.cs +++ b/Mono.Nat/Upnp/Messages/ErrorMessage.cs @@ -59,10 +59,5 @@ namespace Mono.Nat.Upnp { throw new NotImplementedException(); } - - public override System.Net.WebRequest Encode(out byte[] body) - { - throw new NotImplementedException(); - } } } diff --git a/Mono.Nat/Upnp/Messages/GetServicesMessage.cs b/Mono.Nat/Upnp/Messages/GetServicesMessage.cs index 87dcb59e4..9d29f98fd 100644 --- a/Mono.Nat/Upnp/Messages/GetServicesMessage.cs +++ b/Mono.Nat/Upnp/Messages/GetServicesMessage.cs @@ -60,17 +60,6 @@ namespace Mono.Nat.Upnp } } - public override WebRequest Encode(out byte[] body) - { - HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://" + this.hostAddress.ToString() + this.servicesDescriptionUrl); - req.Headers.Add("ACCEPT-LANGUAGE", "en"); - req.Method = "GET"; - - body = new byte[0]; - return req; - } - - public override HttpRequestOptions Encode() { var req = new HttpRequestOptions(); diff --git a/Mono.Nat/Upnp/Messages/Requests/CreatePortMappingMessage.cs b/Mono.Nat/Upnp/Messages/Requests/CreatePortMappingMessage.cs index 2d128f8e7..e9caa916d 100644 --- a/Mono.Nat/Upnp/Messages/Requests/CreatePortMappingMessage.cs +++ b/Mono.Nat/Upnp/Messages/Requests/CreatePortMappingMessage.cs @@ -71,25 +71,5 @@ namespace Mono.Nat.Upnp writer.Flush(); return CreateRequest("AddPortMapping", builder.ToString()); } - - public override WebRequest Encode(out byte[] body) - { - CultureInfo culture = CultureInfo.InvariantCulture; - - StringBuilder builder = new StringBuilder(256); - XmlWriter writer = CreateWriter(builder); - - WriteFullElement(writer, "NewRemoteHost", string.Empty); - WriteFullElement(writer, "NewExternalPort", this.mapping.PublicPort.ToString(culture)); - WriteFullElement(writer, "NewProtocol", this.mapping.Protocol == Protocol.Tcp ? "TCP" : "UDP"); - WriteFullElement(writer, "NewInternalPort", this.mapping.PrivatePort.ToString(culture)); - WriteFullElement(writer, "NewInternalClient", this.localIpAddress.ToString()); - WriteFullElement(writer, "NewEnabled", "1"); - WriteFullElement(writer, "NewPortMappingDescription", string.IsNullOrEmpty(mapping.Description) ? "Mono.Nat" : mapping.Description); - WriteFullElement(writer, "NewLeaseDuration", mapping.Lifetime.ToString()); - - writer.Flush(); - return CreateRequest("AddPortMapping", builder.ToString(), out body); - } } } diff --git a/Mono.Nat/Upnp/Messages/Requests/DeletePortMappingMessage.cs b/Mono.Nat/Upnp/Messages/Requests/DeletePortMappingMessage.cs deleted file mode 100644 index ac04a66db..000000000 --- a/Mono.Nat/Upnp/Messages/Requests/DeletePortMappingMessage.cs +++ /dev/null @@ -1,71 +0,0 @@ -// -// 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.Net; -using System.IO; -using System.Text; -using System.Xml; -using MediaBrowser.Common.Net; - -namespace Mono.Nat.Upnp -{ - internal class DeletePortMappingMessage : MessageBase - { - private Mapping mapping; - - public DeletePortMappingMessage(Mapping mapping, UpnpNatDevice device) - : base(device) - { - this.mapping = mapping; - } - - public override HttpRequestOptions Encode() - { - StringBuilder builder = new StringBuilder(256); - XmlWriter writer = CreateWriter(builder); - - WriteFullElement(writer, "NewRemoteHost", string.Empty); - WriteFullElement(writer, "NewExternalPort", mapping.PublicPort.ToString(MessageBase.Culture)); - WriteFullElement(writer, "NewProtocol", mapping.Protocol == Protocol.Tcp ? "TCP" : "UDP"); - - writer.Flush(); - return CreateRequest("DeletePortMapping", builder.ToString()); - } - - public override WebRequest Encode(out byte[] body) - { - StringBuilder builder = new StringBuilder(256); - XmlWriter writer = CreateWriter(builder); - - WriteFullElement(writer, "NewRemoteHost", string.Empty); - WriteFullElement(writer, "NewExternalPort", mapping.PublicPort.ToString(MessageBase.Culture)); - WriteFullElement(writer, "NewProtocol", mapping.Protocol == Protocol.Tcp ? "TCP" : "UDP"); - - writer.Flush(); - return CreateRequest("DeletePortMapping", builder.ToString(), out body); - } - } -} diff --git a/Mono.Nat/Upnp/Messages/Requests/GetExternalIPAddressMessage.cs b/Mono.Nat/Upnp/Messages/Requests/GetExternalIPAddressMessage.cs deleted file mode 100644 index b5c9caf9c..000000000 --- a/Mono.Nat/Upnp/Messages/Requests/GetExternalIPAddressMessage.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// 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; -using System.Collections.Generic; -using System.Text; -using System.Net; -using System.IO; -using MediaBrowser.Common.Net; - -namespace Mono.Nat.Upnp -{ - internal class GetExternalIPAddressMessage : MessageBase - { - - #region Constructors - public GetExternalIPAddressMessage(UpnpNatDevice device) - :base(device) - { - } - #endregion - - public override HttpRequestOptions Encode() - { - return CreateRequest("GetExternalIPAddress", string.Empty); - } - - public override WebRequest Encode(out byte[] body) - { - return CreateRequest("GetExternalIPAddress", string.Empty, out body); - } - } -} diff --git a/Mono.Nat/Upnp/Messages/Requests/GetGenericPortMappingEntry.cs b/Mono.Nat/Upnp/Messages/Requests/GetGenericPortMappingEntry.cs deleted file mode 100644 index 89980c30c..000000000 --- a/Mono.Nat/Upnp/Messages/Requests/GetGenericPortMappingEntry.cs +++ /dev/null @@ -1,67 +0,0 @@ -// -// 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; -using System.Collections.Generic; -using System.Text; -using System.Xml; -using MediaBrowser.Common.Net; - -namespace Mono.Nat.Upnp -{ - internal class GetGenericPortMappingEntry : MessageBase - { - private int index; - - public GetGenericPortMappingEntry(int index, UpnpNatDevice device) - :base(device) - { - this.index = index; - } - - public override HttpRequestOptions Encode() - { - StringBuilder sb = new StringBuilder(128); - XmlWriter writer = CreateWriter(sb); - - WriteFullElement(writer, "NewPortMappingIndex", index.ToString()); - - writer.Flush(); - return CreateRequest("GetGenericPortMappingEntry", sb.ToString()); - } - - public override System.Net.WebRequest Encode(out byte[] body) - { - StringBuilder sb = new StringBuilder(128); - XmlWriter writer = CreateWriter(sb); - - WriteFullElement(writer, "NewPortMappingIndex", index.ToString()); - - writer.Flush(); - return CreateRequest("GetGenericPortMappingEntry", sb.ToString(), out body); - } - } -} diff --git a/Mono.Nat/Upnp/Messages/Requests/GetSpecificPortMappingEntryMessage.cs b/Mono.Nat/Upnp/Messages/Requests/GetSpecificPortMappingEntryMessage.cs deleted file mode 100644 index 3e6bac2a8..000000000 --- a/Mono.Nat/Upnp/Messages/Requests/GetSpecificPortMappingEntryMessage.cs +++ /dev/null @@ -1,74 +0,0 @@ -// -// 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; -using System.Collections.Generic; -using System.Text; -using System.Xml; -using System.Net; -using MediaBrowser.Common.Net; - -namespace Mono.Nat.Upnp -{ - internal class GetSpecificPortMappingEntryMessage : MessageBase - { - internal Protocol protocol; - internal int externalPort; - - public GetSpecificPortMappingEntryMessage(Protocol protocol, int externalPort, UpnpNatDevice device) - : base(device) - { - this.protocol = protocol; - this.externalPort = externalPort; - } - - public override WebRequest Encode(out byte[] body) - { - StringBuilder sb = new StringBuilder(64); - XmlWriter writer = CreateWriter(sb); - - WriteFullElement(writer, "NewRemoteHost", string.Empty); - WriteFullElement(writer, "NewExternalPort", externalPort.ToString()); - WriteFullElement(writer, "NewProtocol", protocol == Protocol.Tcp ? "TCP" : "UDP"); - writer.Flush(); - - return CreateRequest("GetSpecificPortMappingEntry", sb.ToString(), out body); - } - - public override HttpRequestOptions Encode() - { - StringBuilder sb = new StringBuilder(64); - XmlWriter writer = CreateWriter(sb); - - WriteFullElement(writer, "NewRemoteHost", string.Empty); - WriteFullElement(writer, "NewExternalPort", externalPort.ToString()); - WriteFullElement(writer, "NewProtocol", protocol == Protocol.Tcp ? "TCP" : "UDP"); - writer.Flush(); - - return CreateRequest("GetSpecificPortMappingEntry", sb.ToString()); - } - } -} diff --git a/Mono.Nat/Upnp/Messages/Responses/CreatePortMappingResponseMessage.cs b/Mono.Nat/Upnp/Messages/Responses/CreatePortMappingResponseMessage.cs index b8128f0b5..48776dd6f 100644 --- a/Mono.Nat/Upnp/Messages/Responses/CreatePortMappingResponseMessage.cs +++ b/Mono.Nat/Upnp/Messages/Responses/CreatePortMappingResponseMessage.cs @@ -44,10 +44,5 @@ namespace Mono.Nat.Upnp { throw new NotImplementedException(); } - - public override System.Net.WebRequest Encode(out byte[] body) - { - throw new NotImplementedException(); - } } } diff --git a/Mono.Nat/Upnp/Messages/Responses/DeletePortMappingResponseMessage.cs b/Mono.Nat/Upnp/Messages/Responses/DeletePortMappingResponseMessage.cs deleted file mode 100644 index 69d32126a..000000000 --- a/Mono.Nat/Upnp/Messages/Responses/DeletePortMappingResponseMessage.cs +++ /dev/null @@ -1,51 +0,0 @@ -// -// 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; -using MediaBrowser.Common.Net; - -namespace Mono.Nat.Upnp -{ - internal class DeletePortMapResponseMessage : MessageBase - { - public DeletePortMapResponseMessage() - :base(null) - { - } - - public override HttpRequestOptions Encode() - { - throw new NotSupportedException(); - } - - public override System.Net.WebRequest Encode(out byte[] body) - { - throw new NotSupportedException(); - } - } -} diff --git a/Mono.Nat/Upnp/Messages/Responses/GetExternalIPAddressResponseMessage.cs b/Mono.Nat/Upnp/Messages/Responses/GetExternalIPAddressResponseMessage.cs deleted file mode 100644 index 201296556..000000000 --- a/Mono.Nat/Upnp/Messages/Responses/GetExternalIPAddressResponseMessage.cs +++ /dev/null @@ -1,59 +0,0 @@ -// -// 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; -using System.Collections.Generic; -using System.Text; -using System.Net; -using MediaBrowser.Common.Net; - -namespace Mono.Nat.Upnp -{ - internal class GetExternalIPAddressResponseMessage : MessageBase - { - public IPAddress ExternalIPAddress - { - get { return this.externalIPAddress; } - } - private IPAddress externalIPAddress; - - public GetExternalIPAddressResponseMessage(string ip) - :base(null) - { - this.externalIPAddress = IPAddress.Parse(ip); - } - - public override HttpRequestOptions Encode() - { - throw new NotImplementedException(); - } - - public override WebRequest Encode(out byte[] body) - { - throw new NotImplementedException(); - } - } -} diff --git a/Mono.Nat/Upnp/Messages/Responses/GetGenericPortMappingEntryResponseMessage.cs b/Mono.Nat/Upnp/Messages/Responses/GetGenericPortMappingEntryResponseMessage.cs deleted file mode 100644 index 51584cc7e..000000000 --- a/Mono.Nat/Upnp/Messages/Responses/GetGenericPortMappingEntryResponseMessage.cs +++ /dev/null @@ -1,114 +0,0 @@ -// -// 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; -using System.Collections.Generic; -using System.Text; -using System.Xml; -using MediaBrowser.Common.Net; - -namespace Mono.Nat.Upnp -{ - internal class GetGenericPortMappingEntryResponseMessage : MessageBase - { - private string remoteHost; - private int externalPort; - private Protocol protocol; - private int internalPort; - private string internalClient; - private bool enabled; - private string portMappingDescription; - private int leaseDuration; - - public string RemoteHost - { - get { return this.remoteHost; } - } - - public int ExternalPort - { - get { return this.externalPort; } - } - - public Protocol Protocol - { - get { return this.protocol; } - } - - public int InternalPort - { - get { return this.internalPort; } - } - - public string InternalClient - { - get { return this.internalClient; } - } - - public bool Enabled - { - get { return this.enabled; } - } - - public string PortMappingDescription - { - get { return this.portMappingDescription; } - } - - public int LeaseDuration - { - get { return this.leaseDuration; } - } - - - public GetGenericPortMappingEntryResponseMessage(XmlNode data, bool genericMapping) - : base(null) - { - remoteHost = (genericMapping) ? data["NewRemoteHost"].InnerText : string.Empty; - externalPort = (genericMapping) ? Convert.ToInt32(data["NewExternalPort"].InnerText) : -1; - if (genericMapping) - protocol = data["NewProtocol"].InnerText.Equals("TCP", StringComparison.InvariantCultureIgnoreCase) ? Protocol.Tcp : Protocol.Udp; - else - protocol = Protocol.Udp; - - internalPort = Convert.ToInt32(data["NewInternalPort"].InnerText); - internalClient = data["NewInternalClient"].InnerText; - enabled = data["NewEnabled"].InnerText == "1" ? true : false; - portMappingDescription = data["NewPortMappingDescription"].InnerText; - leaseDuration = Convert.ToInt32(data["NewLeaseDuration"].InnerText); - } - - public override HttpRequestOptions Encode() - { - throw new NotImplementedException(); - } - - public override System.Net.WebRequest Encode(out byte[] body) - { - throw new NotImplementedException(); - } - } -} diff --git a/Mono.Nat/Upnp/Messages/UpnpMessage.cs b/Mono.Nat/Upnp/Messages/UpnpMessage.cs index 11e446277..54cca4494 100644 --- a/Mono.Nat/Upnp/Messages/UpnpMessage.cs +++ b/Mono.Nat/Upnp/Messages/UpnpMessage.cs @@ -45,33 +45,6 @@ namespace Mono.Nat.Upnp this.device = device; } - protected WebRequest CreateRequest(string upnpMethod, string methodParameters, out byte[] body) - { - string ss = "http://" + this.device.HostEndPoint.ToString() + this.device.ControlUrl; - NatUtility.Log("Initiating request to: {0}", ss); - Uri location = new Uri(ss); - - HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(location); - req.KeepAlive = false; - req.Method = "POST"; - req.ContentType = "text/xml; charset=\"utf-8\""; - req.Headers.Add("SOAPACTION", "\"" + device.ServiceType + "#" + upnpMethod + "\""); - - string bodyString = "<s:Envelope " - + "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" " - + "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" - + "<s:Body>" - + "<u:" + upnpMethod + " " - + "xmlns:u=\"" + device.ServiceType + "\">" - + methodParameters - + "</u:" + upnpMethod + ">" - + "</s:Body>" - + "</s:Envelope>\r\n\r\n"; - - body = System.Text.Encoding.UTF8.GetBytes(bodyString); - return req; - } - protected HttpRequestOptions CreateRequest(string upnpMethod, string methodParameters) { string ss = "http://" + this.device.HostEndPoint.ToString() + this.device.ControlUrl; @@ -98,50 +71,7 @@ namespace Mono.Nat.Upnp return req; } - public static MessageBase Decode(UpnpNatDevice device, string message) - { - XmlNode node; - XmlDocument doc = new XmlDocument(); - doc.LoadXml(message); - - XmlNamespaceManager nsm = new XmlNamespaceManager(doc.NameTable); - - // Error messages should be found under this namespace - nsm.AddNamespace("errorNs", "urn:schemas-upnp-org:control-1-0"); - nsm.AddNamespace("responseNs", device.ServiceType); - - // Check to see if we have a fault code message. - if ((node = doc.SelectSingleNode("//errorNs:UPnPError", nsm)) != null) { - string errorCode = node["errorCode"] != null ? node["errorCode"].InnerText : ""; - string errorDescription = node["errorDescription"] != null ? node["errorDescription"].InnerText : ""; - - return new ErrorMessage(Convert.ToInt32(errorCode, CultureInfo.InvariantCulture), errorDescription); - } - - if ((doc.SelectSingleNode("//responseNs:AddPortMappingResponse", nsm)) != null) - return new CreatePortMappingResponseMessage(); - - if ((doc.SelectSingleNode("//responseNs:DeletePortMappingResponse", nsm)) != null) - return new DeletePortMapResponseMessage(); - - if ((node = doc.SelectSingleNode("//responseNs:GetExternalIPAddressResponse", nsm)) != null) { - string newExternalIPAddress = node["NewExternalIPAddress"] != null ? node["NewExternalIPAddress"].InnerText : ""; - return new GetExternalIPAddressResponseMessage(newExternalIPAddress); - } - - if ((node = doc.SelectSingleNode("//responseNs:GetGenericPortMappingEntryResponse", nsm)) != null) - return new GetGenericPortMappingEntryResponseMessage(node, true); - - if ((node = doc.SelectSingleNode("//responseNs:GetSpecificPortMappingEntryResponse", nsm)) != null) - return new GetGenericPortMappingEntryResponseMessage(node, false); - - NatUtility.Log("Unknown message returned. Please send me back the following XML:"); - NatUtility.Log(message); - return null; - } - public abstract HttpRequestOptions Encode(); - public abstract WebRequest Encode(out byte[] body); public virtual string Method { diff --git a/Mono.Nat/Upnp/UpnpNatDevice.cs b/Mono.Nat/Upnp/UpnpNatDevice.cs index 6c4bcd746..22f8ff968 100644 --- a/Mono.Nat/Upnp/UpnpNatDevice.cs +++ b/Mono.Nat/Upnp/UpnpNatDevice.cs @@ -70,7 +70,7 @@ namespace Mono.Nat.Upnp // FIXME: Is this reliable enough. What if we get a hostname as opposed to a proper http address // Are we going to get addresses with the "http://" attached? - if (locationDetails.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase)) + if (locationDetails.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) { NatUtility.Log("Found device at: {0}", locationDetails); // This bit strings out the "http://" from the string @@ -98,7 +98,7 @@ namespace Mono.Nat.Upnp this.localAddress = localAddress; // Split the string at the "location" section so i can extract the ipaddress and service description url - string locationDetails = deviceDetails.Substring(deviceDetails.IndexOf("Location", StringComparison.InvariantCultureIgnoreCase) + 9).Split('\r')[0]; + string locationDetails = deviceDetails.Substring(deviceDetails.IndexOf("Location", StringComparison.OrdinalIgnoreCase) + 9).Split('\r')[0]; this.serviceType = serviceType; // Make sure we have no excess whitespace @@ -106,7 +106,7 @@ namespace Mono.Nat.Upnp // FIXME: Is this reliable enough. What if we get a hostname as opposed to a proper http address // Are we going to get addresses with the "http://" attached? - if (locationDetails.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase)) + if (locationDetails.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) { NatUtility.Log("Found device at: {0}", locationDetails); // This bit strings out the "http://" from the string @@ -171,189 +171,12 @@ namespace Mono.Nat.Upnp get { return serviceType; } } - /// <summary> - /// Begins an async call to get the external ip address of the router - /// </summary> - public override IAsyncResult BeginGetExternalIP(AsyncCallback callback, object asyncState) - { - // Create the port map message - GetExternalIPAddressMessage message = new GetExternalIPAddressMessage(this); - return BeginMessageInternal(message, callback, asyncState, EndGetExternalIPInternal); - } - - /// <summary> - /// Maps the specified port to this computer - /// </summary> - public override IAsyncResult BeginCreatePortMap(Mapping mapping, AsyncCallback callback, object asyncState) - { - CreatePortMappingMessage message = new CreatePortMappingMessage(mapping, localAddress, this); - return BeginMessageInternal(message, callback, asyncState, EndCreatePortMapInternal); - } - public override Task CreatePortMap(Mapping mapping) { CreatePortMappingMessage message = new CreatePortMappingMessage(mapping, localAddress, this); return _httpClient.SendAsync(message.Encode(), message.Method); } - /// <summary> - /// Removes a port mapping from this computer - /// </summary> - public override IAsyncResult BeginDeletePortMap(Mapping mapping, AsyncCallback callback, object asyncState) - { - DeletePortMappingMessage message = new DeletePortMappingMessage(mapping, this); - return BeginMessageInternal(message, callback, asyncState, EndDeletePortMapInternal); - } - - - public override IAsyncResult BeginGetAllMappings(AsyncCallback callback, object asyncState) - { - GetGenericPortMappingEntry message = new GetGenericPortMappingEntry(0, this); - return BeginMessageInternal(message, callback, asyncState, EndGetAllMappingsInternal); - } - - - public override IAsyncResult BeginGetSpecificMapping(Protocol protocol, int port, AsyncCallback callback, object asyncState) - { - GetSpecificPortMappingEntryMessage message = new GetSpecificPortMappingEntryMessage(protocol, port, this); - return this.BeginMessageInternal(message, callback, asyncState, new AsyncCallback(this.EndGetSpecificMappingInternal)); - } - - /// <summary> - /// - /// </summary> - /// <param name="result"></param> - public override void EndCreatePortMap(IAsyncResult result) - { - if (result == null) throw new ArgumentNullException("result"); - - PortMapAsyncResult mappingResult = result as PortMapAsyncResult; - if (mappingResult == null) - throw new ArgumentException("Invalid AsyncResult", "result"); - - // Check if we need to wait for the operation to finish - if (!result.IsCompleted) - result.AsyncWaitHandle.WaitOne(); - - // If we have a saved exception, it means something went wrong during the mapping - // so we just rethrow the exception and let the user figure out what they should do. - if (mappingResult.SavedMessage is ErrorMessage) - { - ErrorMessage msg = mappingResult.SavedMessage as ErrorMessage; - throw new MappingException(msg.ErrorCode, msg.Description); - } - - //return result.AsyncState as Mapping; - } - - - /// <summary> - /// - /// </summary> - /// <param name="result"></param> - public override void EndDeletePortMap(IAsyncResult result) - { - if (result == null) - throw new ArgumentNullException("result"); - - PortMapAsyncResult mappingResult = result as PortMapAsyncResult; - if (mappingResult == null) - throw new ArgumentException("Invalid AsyncResult", "result"); - - // Check if we need to wait for the operation to finish - if (!mappingResult.IsCompleted) - mappingResult.AsyncWaitHandle.WaitOne(); - - // If we have a saved exception, it means something went wrong during the mapping - // so we just rethrow the exception and let the user figure out what they should do. - if (mappingResult.SavedMessage is ErrorMessage) - { - ErrorMessage msg = mappingResult.SavedMessage as ErrorMessage; - throw new MappingException(msg.ErrorCode, msg.Description); - } - - // If all goes well, we just return - //return true; - } - - - public override Mapping[] EndGetAllMappings(IAsyncResult result) - { - if (result == null) - throw new ArgumentNullException("result"); - - GetAllMappingsAsyncResult mappingResult = result as GetAllMappingsAsyncResult; - if (mappingResult == null) - throw new ArgumentException("Invalid AsyncResult", "result"); - - if (!mappingResult.IsCompleted) - mappingResult.AsyncWaitHandle.WaitOne(); - - if (mappingResult.SavedMessage is ErrorMessage) - { - ErrorMessage msg = mappingResult.SavedMessage as ErrorMessage; - if (msg.ErrorCode != 713) - throw new MappingException(msg.ErrorCode, msg.Description); - } - - return mappingResult.Mappings.ToArray(); - } - - - /// <summary> - /// Ends an async request to get the external ip address of the router - /// </summary> - public override IPAddress EndGetExternalIP(IAsyncResult result) - { - if (result == null) throw new ArgumentNullException("result"); - - PortMapAsyncResult mappingResult = result as PortMapAsyncResult; - if (mappingResult == null) - throw new ArgumentException("Invalid AsyncResult", "result"); - - if (!result.IsCompleted) - result.AsyncWaitHandle.WaitOne(); - - if (mappingResult.SavedMessage is ErrorMessage) - { - ErrorMessage msg = mappingResult.SavedMessage as ErrorMessage; - throw new MappingException(msg.ErrorCode, msg.Description); - } - - if (mappingResult.SavedMessage == null) - return null; - else - return ((GetExternalIPAddressResponseMessage)mappingResult.SavedMessage).ExternalIPAddress; - } - - - public override Mapping EndGetSpecificMapping(IAsyncResult result) - { - if (result == null) - throw new ArgumentNullException("result"); - - GetAllMappingsAsyncResult mappingResult = result as GetAllMappingsAsyncResult; - if (mappingResult == null) - throw new ArgumentException("Invalid AsyncResult", "result"); - - if (!mappingResult.IsCompleted) - mappingResult.AsyncWaitHandle.WaitOne(); - - if (mappingResult.SavedMessage is ErrorMessage) - { - ErrorMessage message = mappingResult.SavedMessage as ErrorMessage; - if (message.ErrorCode != 0x2ca) - { - throw new MappingException(message.ErrorCode, message.Description); - } - } - if (mappingResult.Mappings.Count == 0) - return new Mapping(Protocol.Tcp, -1, -1); - - return mappingResult.Mappings[0]; - } - - public override bool Equals(object obj) { UpnpNatDevice device = obj as UpnpNatDevice; @@ -373,256 +196,6 @@ namespace Mono.Nat.Upnp return (this.hostEndPoint.GetHashCode() ^ this.controlUrl.GetHashCode() ^ this.serviceDescriptionUrl.GetHashCode()); } - private IAsyncResult BeginMessageInternal(MessageBase message, AsyncCallback storedCallback, object asyncState, AsyncCallback callback) - { - byte[] body; - WebRequest request = message.Encode(out body); - PortMapAsyncResult mappingResult = PortMapAsyncResult.Create(message, request, storedCallback, asyncState); - - if (body.Length > 0) - { - request.ContentLength = body.Length; - request.BeginGetRequestStream(delegate (IAsyncResult result) - { - try - { - Stream s = request.EndGetRequestStream(result); - s.Write(body, 0, body.Length); - request.BeginGetResponse(callback, mappingResult); - } - catch (Exception ex) - { - mappingResult.Complete(ex); - } - }, null); - } - else - { - request.BeginGetResponse(callback, mappingResult); - } - return mappingResult; - } - - private void CompleteMessage(IAsyncResult result) - { - PortMapAsyncResult mappingResult = result.AsyncState as PortMapAsyncResult; - mappingResult.CompletedSynchronously = result.CompletedSynchronously; - mappingResult.Complete(); - } - - private MessageBase DecodeMessageFromResponse(Stream s, long length) - { - StringBuilder data = new StringBuilder(); - int bytesRead = 0; - int totalBytesRead = 0; - byte[] buffer = new byte[10240]; - - // Read out the content of the message, hopefully picking everything up in the case where we have no contentlength - if (length != -1) - { - while (totalBytesRead < length) - { - bytesRead = s.Read(buffer, 0, buffer.Length); - data.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead)); - totalBytesRead += bytesRead; - } - } - else - { - while ((bytesRead = s.Read(buffer, 0, buffer.Length)) != 0) - data.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead)); - } - - // Once we have our content, we need to see what kind of message it is. It'll either a an error - // or a response based on the action we performed. - return MessageBase.Decode(this, data.ToString()); - } - - private void EndCreatePortMapInternal(IAsyncResult result) - { - EndMessageInternal(result); - CompleteMessage(result); - } - - private void EndMessageInternal(IAsyncResult result) - { - HttpWebResponse response = null; - PortMapAsyncResult mappingResult = result.AsyncState as PortMapAsyncResult; - - try - { - try - { - response = (HttpWebResponse)mappingResult.Request.EndGetResponse(result); - } - catch (WebException ex) - { - // Even if the request "failed" i want to continue on to read out the response from the router - response = ex.Response as HttpWebResponse; - if (response == null) - mappingResult.SavedMessage = new ErrorMessage((int)ex.Status, ex.Message); - } - if (response != null) - mappingResult.SavedMessage = DecodeMessageFromResponse(response.GetResponseStream(), response.ContentLength); - } - - finally - { - if (response != null) - response.Close(); - } - } - - private void EndDeletePortMapInternal(IAsyncResult result) - { - EndMessageInternal(result); - CompleteMessage(result); - } - - private void EndGetAllMappingsInternal(IAsyncResult result) - { - EndMessageInternal(result); - - GetAllMappingsAsyncResult mappingResult = result.AsyncState as GetAllMappingsAsyncResult; - GetGenericPortMappingEntryResponseMessage message = mappingResult.SavedMessage as GetGenericPortMappingEntryResponseMessage; - if (message != null) - { - Mapping mapping = new Mapping(message.Protocol, message.InternalPort, message.ExternalPort, message.LeaseDuration); - mapping.Description = message.PortMappingDescription; - mappingResult.Mappings.Add(mapping); - GetGenericPortMappingEntry next = new GetGenericPortMappingEntry(mappingResult.Mappings.Count, this); - - // It's ok to do this synchronously because we should already be on anther thread - // and this won't block the user. - byte[] body; - WebRequest request = next.Encode(out body); - if (body.Length > 0) - { - request.ContentLength = body.Length; - request.GetRequestStream().Write(body, 0, body.Length); - } - mappingResult.Request = request; - request.BeginGetResponse(EndGetAllMappingsInternal, mappingResult); - return; - } - - CompleteMessage(result); - } - - private void EndGetExternalIPInternal(IAsyncResult result) - { - EndMessageInternal(result); - CompleteMessage(result); - } - - private void EndGetSpecificMappingInternal(IAsyncResult result) - { - EndMessageInternal(result); - - GetAllMappingsAsyncResult mappingResult = result.AsyncState as GetAllMappingsAsyncResult; - GetGenericPortMappingEntryResponseMessage message = mappingResult.SavedMessage as GetGenericPortMappingEntryResponseMessage; - if (message != null) - { - Mapping mapping = new Mapping(mappingResult.SpecificMapping.Protocol, message.InternalPort, mappingResult.SpecificMapping.PublicPort, message.LeaseDuration); - mapping.Description = mappingResult.SpecificMapping.Description; - mappingResult.Mappings.Add(mapping); - } - - CompleteMessage(result); - } - - internal async Task<bool> GetServicesList() - { - // Create a HTTPWebRequest to download the list of services the device offers - var requestOptions = new GetServicesMessage(this.serviceDescriptionUrl, this.hostEndPoint, _logger).Encode(); - - requestOptions.BufferContent = false; - - using (var response = await _httpClient.Get(requestOptions).ConfigureAwait(false)) - { - return ServicesReceived(response); - } - } - - private bool ServicesReceived(Stream s) - { - int abortCount = 0; - int bytesRead = 0; - byte[] buffer = new byte[10240]; - StringBuilder servicesXml = new StringBuilder(); - XmlDocument xmldoc = new XmlDocument(); - - while (true) - { - bytesRead = s.Read(buffer, 0, buffer.Length); - servicesXml.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead)); - try - { - xmldoc.LoadXml(servicesXml.ToString()); - break; - } - catch (XmlException) - { - // If we can't receive the entire XML within 500ms, then drop the connection - // Unfortunately not all routers supply a valid ContentLength (mine doesn't) - // so this hack is needed to keep testing our recieved data until it gets successfully - // parsed by the xmldoc. Without this, the code will never pick up my router. - if (abortCount++ > 50) - { - return false; - } - NatUtility.Log("{0}: Couldn't parse services list", HostEndPoint); - System.Threading.Thread.Sleep(10); - } - } - - NatUtility.Log("{0}: Parsed services list", HostEndPoint); - XmlNamespaceManager ns = new XmlNamespaceManager(xmldoc.NameTable); - ns.AddNamespace("ns", "urn:schemas-upnp-org:device-1-0"); - XmlNodeList nodes = xmldoc.SelectNodes("//*/ns:serviceList", ns); - - foreach (XmlNode node in nodes) - { - //Go through each service there - foreach (XmlNode service in node.ChildNodes) - { - //If the service is a WANIPConnection, then we have what we want - string type = service["serviceType"].InnerText; - NatUtility.Log("{0}: Found service: {1}", HostEndPoint, type); - StringComparison c = StringComparison.OrdinalIgnoreCase; - // TODO: Add support for version 2 of UPnP. - if (type.Equals("urn:schemas-upnp-org:service:WANPPPConnection:1", c) || - type.Equals("urn:schemas-upnp-org:service:WANIPConnection:1", c)) - { - this.controlUrl = service["controlURL"].InnerText; - NatUtility.Log("{0}: Found upnp service at: {1}", HostEndPoint, controlUrl); - try - { - Uri u = new Uri(controlUrl); - if (u.IsAbsoluteUri) - { - EndPoint old = hostEndPoint; - this.hostEndPoint = new IPEndPoint(IPAddress.Parse(u.Host), u.Port); - NatUtility.Log("{0}: Absolute URI detected. Host address is now: {1}", old, HostEndPoint); - this.controlUrl = controlUrl.Substring(u.GetLeftPart(UriPartial.Authority).Length); - NatUtility.Log("{0}: New control url: {1}", HostEndPoint, controlUrl); - } - } - catch - { - NatUtility.Log("{0}: Assuming control Uri is relative: {1}", HostEndPoint, controlUrl); - } - NatUtility.Log("{0}: Handshake Complete", HostEndPoint); - return true; - } - } - } - - //If we get here, it means that we didn't get WANIPConnection service, which means no uPnP forwarding - //So we don't invoke the callback, so this device is never added to our lists - return false; - } - /// <summary> /// Overridden. /// </summary> |
