public override Task DeletePortMapAsync(Mapping mapping) { Guard.IsNotNull(mapping, "mapping"); if (mapping.PrivateIP.Equals(IPAddress.None)) { mapping.PrivateIP = DeviceInfo.LocalAddress; } NatDiscoverer.TraceSource.LogInfo("DeletePortMapAsync - Deleteing port mapping {0}", mapping); var message = new DeletePortMappingRequestMessage(mapping); return(_soapClient .InvokeAsync("DeletePortMapping", message.ToXml()) .TimeoutAfter(TimeSpan.FromSeconds(4)) .ContinueWith(task => { if (!task.IsFaulted) { UnregisterMapping(mapping); } else { MappingException e = task.Exception.InnerException as MappingException; if (e != null && e.ErrorCode != UpnpConstants.NoSuchEntryInArray) { throw e; } } })); }
public override Task <Mapping> GetSpecificMappingAsync(Protocol protocol, int publicPort) { Guard.IsTrue(protocol == Protocol.Tcp || protocol == Protocol.Udp, "protocol"); Guard.IsInRange(publicPort, 0, ushort.MaxValue, "port"); NatDiscoverer.TraceSource.LogInfo("GetSpecificMappingAsync - Getting mapping for protocol: {0} port: {1}", Enum.GetName(typeof(Protocol), protocol), publicPort); var message = new GetSpecificPortMappingEntryRequestMessage(protocol, publicPort); return(_soapClient .InvokeAsync("GetSpecificPortMappingEntry", message.ToXml()) .TimeoutAfter(TimeSpan.FromSeconds(4)) .ContinueWith(task => { if (!task.IsFaulted) { var responseData = task.Result; var messageResponse = new GetPortMappingEntryResponseMessage(responseData, DeviceInfo.ServiceType, false); return new Mapping(messageResponse.Protocol , IPAddress.Parse(messageResponse.InternalClient) , messageResponse.InternalPort , publicPort // messageResponse.ExternalPort is short.MaxValue , messageResponse.LeaseDuration , messageResponse.PortMappingDescription); } else { MappingException e = task.Exception.InnerException as MappingException; if (e != null && e.ErrorCode == UpnpConstants.NoSuchEntryInArray) { return null; } // DD-WRT Linux base router (and others probably) fails with 402-InvalidArgument // when no mapping is found in the mappings table if (e != null && e.ErrorCode == UpnpConstants.InvalidArguments) { NatDiscoverer.TraceSource.LogWarn("Router failed with 402-InvalidArgument. Mapping not found is assumed."); return null; } throw task.Exception.InnerException; } })); }
private async Task <Mapping> InternalCreatePortMapAsync(Mapping mapping, bool create) { List <byte> package = new List <byte>(); package.Add(PmpConstants.Version); package.Add(mapping.NetworkProtocolType == NetworkProtocolType.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 (UdpClient 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 = $"Failed to {type} portmap (protocol={mapping.NetworkProtocolType}, private port={mapping.PrivatePort})"; NatDiscoverer.TraceSource.LogError(message); MappingException pmpException = e as MappingException; throw new MappingException(message, pmpException); } return(mapping); }
public override Task CreatePortMapAsync(Mapping mapping) { Guard.IsNotNull(mapping, "mapping"); if (mapping.PrivateIP.Equals(IPAddress.None)) { mapping.PrivateIP = DeviceInfo.LocalAddress; } NatDiscoverer.TraceSource.LogInfo("CreatePortMapAsync - Creating port mapping {0}", mapping); var message = new CreatePortMappingRequestMessage(mapping); return(_soapClient .InvokeAsync("AddPortMapping", message.ToXml()) .TimeoutAfter(TimeSpan.FromSeconds(4)) .ContinueWith(task => { if (!task.IsFaulted) { RegisterMapping(mapping); } else { MappingException me = task.Exception.InnerException as MappingException; if (me == null) { throw task.Exception.InnerException; } 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 me; case UpnpConstants.ConflictInMappingEntry: NatDiscoverer.TraceSource.LogWarn("Conflict with an already existing mapping"); throw me; default: throw me; } } })); }
public void GetGenericMappingAsync(int index, List <Mapping> mappings, TaskCompletionSource <IEnumerable <Mapping> > taskCompletionSource) { var message = new GetGenericPortMappingEntry(index); _soapClient .InvokeAsync("GetGenericPortMappingEntry", message.ToXml()) .TimeoutAfter(TimeSpan.FromSeconds(4)) .ContinueWith(task => { if (!task.IsFaulted) { var responseData = task.Result; var responseMessage = new GetPortMappingEntryResponseMessage(responseData, DeviceInfo.ServiceType, true); IPAddress internalClientIp; if (!IPAddress.TryParse(responseMessage.InternalClient, out internalClientIp)) { NatDiscoverer.TraceSource.LogWarn("InternalClient is not an IP address. Mapping ignored!"); } else { var mapping = new Mapping(responseMessage.Protocol , internalClientIp , responseMessage.InternalPort , responseMessage.ExternalPort , responseMessage.LeaseDuration , responseMessage.PortMappingDescription); mappings.Add(mapping); } GetGenericMappingAsync(index + 1, mappings, taskCompletionSource); } else { MappingException e = task.Exception.InnerException as MappingException; if (e == null) { throw task.Exception.InnerException; } if (e.ErrorCode == UpnpConstants.SpecifiedArrayIndexInvalid || e.ErrorCode == UpnpConstants.NoSuchEntryInArray) { // there are no more mappings taskCompletionSource.SetResult(mappings); return; } // DD-WRT Linux base router (and others probably) fails with 402-InvalidArgument when index is out of range if (e.ErrorCode == UpnpConstants.InvalidArguments) { NatDiscoverer.TraceSource.LogWarn("Router failed with 402-InvalidArgument. No more mappings is assumed."); taskCompletionSource.SetResult(mappings); return; } throw task.Exception.InnerException; } }); }