using Open.Nat; using System; using System.Collections.Generic; using System.Threading; namespace Pulsar.Server.Networking { public class UPnPService { /// /// Used to keep track of all created mappings. /// private readonly Dictionary _mappings = new Dictionary(); /// /// The discovered UPnP device. /// private NatDevice _device; /// /// The NAT discoverer used to discover NAT-UPnP devices. /// private NatDiscoverer _discoverer; /// /// Initializes the discovery of new UPnP devices. /// public UPnPService() { _discoverer = new NatDiscoverer(); } /// /// Creates a new port mapping on the UPnP device. /// /// The port to map. public async void CreatePortMapAsync(int port) { try { var cts = new CancellationTokenSource(10000); _device = await _discoverer.DiscoverDeviceAsync(PortMapper.Upnp, cts); Mapping mapping = new Mapping(Protocol.Tcp, port, port); await _device.CreatePortMapAsync(mapping); if (_mappings.ContainsKey(mapping.PrivatePort)) _mappings[mapping.PrivatePort] = mapping; else _mappings.Add(mapping.PrivatePort, mapping); } catch (Exception ex) when (ex is MappingException || ex is NatDeviceNotFoundException) { } } /// /// Deletes an existing port mapping. /// /// The port mapping to delete. public async void DeletePortMapAsync(int port) { if (_mappings.TryGetValue(port, out var mapping)) { try { await _device.DeletePortMapAsync(mapping); _mappings.Remove(mapping.PrivatePort); } catch (Exception ex) when (ex is MappingException || ex is NatDeviceNotFoundException) { } } } } }