private bool RemovePortMapping(ExistingUPnPPortMapping portMapping)
        {
            int result = MiniUPnP.UPNPCOMMAND_SUCCESS;

            bool udpResult = true;
            bool tcpResult = true;

            String extPortStr = portMapping.ExternalPort.ToString();

            if ((portMapping.TransportProtocol & PortMappingTransportProtocol.UDP) > 0)
            {
                try
                {
                    result = MiniUPnP.UPNP_DeletePortMapping(urls.controlURL, igddata.ServiceType, extPortStr, "UDP");
                }
                catch (AccessViolationException)
                {
                    // I have no idea why the above method sometimes throws an AccessException.
                    // The odd part about it is that it works perfect, except for the stupid exception.
                    // So the exception can safely be ignored, it just bugs me because it feels like a hack.
                    DebugLog.WriteLine("Ignoring exception from method MiniUPnP.UPNP_DeletePortMapping");
                }

                DebugLog.WriteLine("UPnP: RemovePortMapping: UDP: result = {0}", result);
                udpResult = (result == MiniUPnP.UPNPCOMMAND_SUCCESS);
            }
            if ((portMapping.TransportProtocol & PortMappingTransportProtocol.TCP) > 0)
            {
                try
                {
                    result = MiniUPnP.UPNP_DeletePortMapping(urls.controlURL, igddata.ServiceType, extPortStr, "TCP");
                }
                catch (AccessViolationException)
                {
                    // I have no idea why the above method sometimes throws an AccessException.
                    // The odd part about it is that it works perfect, except for the stupid exception.
                    // So the exception can safely be ignored, it just bugs me because it feels like a hack.
                    DebugLog.WriteLine("Ignoring exception from method MiniUPnP.UPNP_DeletePortMapping");
                }

                DebugLog.WriteLine("UPnP: RemovePortMapping: TCP: result = {0}", result);
                tcpResult = (result == MiniUPnP.UPNPCOMMAND_SUCCESS);
            }

            return(udpResult && tcpResult);
        }
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
        #endregion
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
        #region Update Port Mappings Thread
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

        private void UpdatePortMappingsThread()
        {
            Monitor.Enter(multiThreadLock);
            OnDidBeginWorking();

            // Remove existing mappings scheduled for removal.
            // These are mappings that weren't created by us, but have been explicity set for removal.

            List <ExistingUPnPPortMapping> existingMappingsToRemove;

            existingMappingsToRemove = PortMapper.SharedInstance.ExistingUPnPPortMappingsToRemove;
            lock (existingMappingsToRemove)
            {
                while ((existingMappingsToRemove.Count > 0) && (updatePortMappingsThreadFlags == ThreadFlags.None))
                {
                    ExistingUPnPPortMapping existingMappingToRemove = existingMappingsToRemove[0];

                    RemovePortMapping(existingMappingToRemove);

                    existingMappingsToRemove.RemoveAt(0);
                }
            }

            // We need to safeguard mappings that others might have made.
            // UPnP is quite generous in giving us what we want,
            // even if other mappings are there, especially from the same local machine.

            DoUpdateExistingUPnPPortMappings();

            // Remove mappings scheduled for removal

            List <PortMapping> mappingsToRemove = PortMapper.SharedInstance.PortMappingsToRemove;

            lock (mappingsToRemove)
            {
                while ((mappingsToRemove.Count > 0) && (updatePortMappingsThreadFlags == ThreadFlags.None))
                {
                    PortMapping mappingToRemove = mappingsToRemove[0];

                    if (mappingToRemove.MappingStatus == PortMappingStatus.Mapped)
                    {
                        RemovePortMapping(mappingToRemove);
                    }

                    mappingsToRemove.RemoveAt(0);
                }
            }

            // If the port mapper is running:
            //   -Add new mappings
            // If the port mapper is stopped:
            //   -Remove any existing mappings

            List <PortMapping> mappings = PortMapper.SharedInstance.PortMappings;

            lock (mappings)
            {
                for (int i = 0; i < mappings.Count && updatePortMappingsThreadFlags == ThreadFlags.None; i++)
                {
                    PortMapping currentMapping = mappings[i];
                    bool        isRunning      = PortMapper.SharedInstance.IsRunning;

                    if (currentMapping.MappingStatus == PortMappingStatus.Unmapped && isRunning)
                    {
                        AddPortMapping(currentMapping);
                    }
                    else if (currentMapping.MappingStatus == PortMappingStatus.Mapped && !isRunning)
                    {
                        RemovePortMapping(currentMapping);
                    }
                }
            }

            Monitor.Exit(multiThreadLock);

            if (PortMapper.SharedInstance.IsRunning)
            {
                if ((updatePortMappingsThreadFlags & ThreadFlags.ShouldRestart) > 0)
                {
                    UpdatePortMappings();
                }
                else if ((updatePortMappingsThreadFlags & ThreadFlags.ShouldQuit) > 0)
                {
                    Refresh();
                }
            }

            OnDidEndWorking();
        }
        private void DoUpdateExistingUPnPPortMappings()
        {
            List <ExistingUPnPPortMapping> existingMappings = new List <ExistingUPnPPortMapping>();

            Dictionary <UInt16, ExistingUPnPPortMapping> existingMappingsUdpDict =
                new Dictionary <UInt16, ExistingUPnPPortMapping>();
            Dictionary <UInt16, ExistingUPnPPortMapping> existingMappingsTcpDict =
                new Dictionary <UInt16, ExistingUPnPPortMapping>();

            int r = 0;
            int i = 0;

            byte[] index     = new byte[6];
            byte[] intClient = new byte[16];
            byte[] intPort   = new byte[6];
            byte[] extPort   = new byte[6];
            byte[] protocol  = new byte[4];
            byte[] desc      = new byte[80];
            byte[] enabled   = new byte[6];
            byte[] rHost     = new byte[64];
            byte[] duration  = new byte[16];

            do
            {
                // Convert "int i" to a null-terminated char array
                String iStr     = i.ToString();
                int    maxCount = Math.Min(iStr.Length, 5);
                System.Text.Encoding.ASCII.GetBytes(iStr, 0, maxCount, index, 0);

                // Reset all the other null-terminated char arrays
                intClient[0] = 0;
                intPort[0]   = 0;
                extPort[0]   = 0;
                protocol[0]  = 0;                 // Warning - not in Cocoa version
                desc[0]      = 0;
                enabled[0]   = 0;
                rHost[0]     = 0;
                duration[0]  = 0;

                r = MiniUPnP.UPNPCOMMAND_UNKNOWN_ERROR;
                try
                {
                    r = MiniUPnP.UPNP_GetGenericPortMappingEntry(urls.controlURL, igddata.ServiceType,
                                                                 index,
                                                                 extPort, intClient, intPort,
                                                                 protocol, desc, enabled,
                                                                 rHost, duration);
                }
                catch (AccessViolationException)
                {
                    // I have no idea why the above method sometimes throws an AccessException.
                    // The odd part about it is that all the data gets marshaled over and back properly.
                    // So the exception can safely be ignored, it just bugs me because it feels like a hack.
                    DebugLog.WriteLine("Ignoring exception from method MiniUPnP.UPNP_GetGenericPortMappingEntry");

                    r = MiniUPnP.UPNPCOMMAND_SUCCESS;
                }

                if (r == MiniUPnP.UPNPCOMMAND_SUCCESS)
                {
                    IPAddress iAddr;
                    IPAddress.TryParse(MiniUPnP.NullTerminatedArrayToString(intClient), out iAddr);

                    UInt16 iPort;
                    UInt16.TryParse(MiniUPnP.NullTerminatedArrayToString(intPort), out iPort);

                    UInt16 ePort;
                    UInt16.TryParse(MiniUPnP.NullTerminatedArrayToString(extPort), out ePort);

                    PortMappingTransportProtocol transportProtocol = 0;
                    String protocolStr = MiniUPnP.NullTerminatedArrayToString(protocol);
                    if (protocolStr.Equals("UDP", StringComparison.OrdinalIgnoreCase))
                    {
                        transportProtocol |= PortMappingTransportProtocol.UDP;
                    }
                    if (protocolStr.Equals("TCP", StringComparison.OrdinalIgnoreCase))
                    {
                        transportProtocol |= PortMappingTransportProtocol.TCP;
                    }

                    String description = MiniUPnP.NullTerminatedArrayToString(desc);

                    ExistingUPnPPortMapping existingPM;
                    existingPM = new ExistingUPnPPortMapping(iAddr, iPort, ePort, transportProtocol, description);

                    existingMappings.Add(existingPM);

                    if ((transportProtocol & PortMappingTransportProtocol.UDP) > 0)
                    {
                        existingMappingsUdpDict[ePort] = existingPM;
                    }
                    if ((transportProtocol & PortMappingTransportProtocol.TCP) > 0)
                    {
                        existingMappingsTcpDict[ePort] = existingPM;
                    }

                    DebugLog.WriteLine("Existing UPnP: {0}: {1} {2}->{3}:{4} ({5})",
                                       i, protocolStr, ePort, iAddr, iPort, description);
                }

                i++;
            } while ((r == MiniUPnP.UPNPCOMMAND_SUCCESS) && (updatePortMappingsThreadFlags == ThreadFlags.None));

            // Update stored list of existing mappings
            existingUPnPPortMappings        = existingMappings;
            existingUPnPPortMappingsUdpDict = existingMappingsUdpDict;
            existingUPnPPortMappingsTcpDict = existingMappingsTcpDict;
        }
        /// <summary>
        /// Asynchronously removes the given port mapping.
        /// 
        /// This method will also automatically refresh the UPnP mapping table,
        /// and call the DidReceiveUPNPMappingTable delegate.
        /// </summary>
        /// <param name="pm">
        ///		The port mapping to remove.
        ///	</param>
        public void RemovePortMapping(ExistingUPnPPortMapping pm)
        {
            if(pm == null) return;

            // All public API methods are wrapped in a single thread lock.
            // This frees users to invoke the public API from multiple threads, but provides us a bit of sanity.
            lock (singleThreadLock)
            {
                if (upnpStatus == MappingStatus.Works)
                {
                    lock (existingUPnPPortMappingsToRemove)
                    {
                        existingUPnPPortMappingsToRemove.Add(pm);
                    }

                    if (isRunning)
                    {
                        requestedUPnPMappingTable = true;
                        UpdatePortMappings();
                    }
                }
            }
        }
        private bool RemovePortMapping(ExistingUPnPPortMapping portMapping)
        {
            int result = MiniUPnP.UPNPCOMMAND_SUCCESS;

            bool udpResult = true;
            bool tcpResult = true;

            String extPortStr = portMapping.ExternalPort.ToString();

            if ((portMapping.TransportProtocol & PortMappingTransportProtocol.UDP) > 0)
            {
                try
                {
                    result = MiniUPnP.UPNP_DeletePortMapping(urls.controlURL, igddata.ServiceType, extPortStr, "UDP");
                }
                catch(AccessViolationException)
                {
                    // I have no idea why the above method sometimes throws an AccessException.
                    // The odd part about it is that it works perfect, except for the stupid exception.
                    // So the exception can safely be ignored, it just bugs me because it feels like a hack.
                    DebugLog.WriteLine("Ignoring exception from method MiniUPnP.UPNP_DeletePortMapping");
                }

                DebugLog.WriteLine("UPnP: RemovePortMapping: UDP: result = {0}", result);
                udpResult = (result == MiniUPnP.UPNPCOMMAND_SUCCESS);
            }
            if ((portMapping.TransportProtocol & PortMappingTransportProtocol.TCP) > 0)
            {
                try
                {
                    result = MiniUPnP.UPNP_DeletePortMapping(urls.controlURL, igddata.ServiceType, extPortStr, "TCP");
                }
                catch (AccessViolationException)
                {
                    // I have no idea why the above method sometimes throws an AccessException.
                    // The odd part about it is that it works perfect, except for the stupid exception.
                    // So the exception can safely be ignored, it just bugs me because it feels like a hack.
                    DebugLog.WriteLine("Ignoring exception from method MiniUPnP.UPNP_DeletePortMapping");
                }

                DebugLog.WriteLine("UPnP: RemovePortMapping: TCP: result = {0}", result);
                tcpResult = (result == MiniUPnP.UPNPCOMMAND_SUCCESS);
            }

            return (udpResult && tcpResult);
        }
        private void DoUpdateExistingUPnPPortMappings()
        {
            List<ExistingUPnPPortMapping> existingMappings = new List<ExistingUPnPPortMapping>();

            Dictionary<UInt16, ExistingUPnPPortMapping> existingMappingsUdpDict =
                new Dictionary<UInt16, ExistingUPnPPortMapping>();
            Dictionary<UInt16, ExistingUPnPPortMapping> existingMappingsTcpDict =
                new Dictionary<UInt16, ExistingUPnPPortMapping>();

            int r = 0;
            int i = 0;
            byte[] index = new byte[6];
            byte[] intClient = new byte[16];
            byte[] intPort = new byte[6];
            byte[] extPort = new byte[6];
            byte[] protocol = new byte[4];
            byte[] desc = new byte[80];
            byte[] enabled = new byte[6];
            byte[] rHost = new byte[64];
            byte[] duration = new byte[16];

            do
            {
                // Convert "int i" to a null-terminated char array
                String iStr = i.ToString();
                int maxCount = Math.Min(iStr.Length, 5);
                System.Text.Encoding.ASCII.GetBytes(iStr, 0, maxCount, index, 0);

                // Reset all the other null-terminated char arrays
                intClient[0] = 0;
                intPort[0] = 0;
                extPort[0] = 0;
                protocol[0] = 0;  // Warning - not in Cocoa version
                desc[0] = 0;
                enabled[0] = 0;
                rHost[0] = 0;
                duration[0] = 0;

                r = MiniUPnP.UPNPCOMMAND_UNKNOWN_ERROR;
                try
                {
                    r = MiniUPnP.UPNP_GetGenericPortMappingEntry(urls.controlURL, igddata.ServiceType,
                                                                 index,
                                                                 extPort, intClient, intPort,
                                                                 protocol, desc, enabled,
                                                                 rHost, duration);
                }
                catch (AccessViolationException)
                {
                    // I have no idea why the above method sometimes throws an AccessException.
                    // The odd part about it is that all the data gets marshaled over and back properly.
                    // So the exception can safely be ignored, it just bugs me because it feels like a hack.
                    DebugLog.WriteLine("Ignoring exception from method MiniUPnP.UPNP_GetGenericPortMappingEntry");

                    r = MiniUPnP.UPNPCOMMAND_SUCCESS;
                }

                if (r == MiniUPnP.UPNPCOMMAND_SUCCESS)
                {
                    IPAddress iAddr;
                    IPAddress.TryParse(MiniUPnP.NullTerminatedArrayToString(intClient), out iAddr);

                    UInt16 iPort;
                    UInt16.TryParse(MiniUPnP.NullTerminatedArrayToString(intPort), out iPort);

                    UInt16 ePort;
                    UInt16.TryParse(MiniUPnP.NullTerminatedArrayToString(extPort), out ePort);

                    PortMappingTransportProtocol transportProtocol = 0;
                    String protocolStr = MiniUPnP.NullTerminatedArrayToString(protocol);
                    if (protocolStr.Equals("UDP", StringComparison.OrdinalIgnoreCase))
                    {
                        transportProtocol |= PortMappingTransportProtocol.UDP;
                    }
                    if (protocolStr.Equals("TCP", StringComparison.OrdinalIgnoreCase))
                    {
                        transportProtocol |= PortMappingTransportProtocol.TCP;
                    }

                    String description = MiniUPnP.NullTerminatedArrayToString(desc);

                    ExistingUPnPPortMapping existingPM;
                    existingPM = new ExistingUPnPPortMapping(iAddr, iPort, ePort, transportProtocol, description);

                    existingMappings.Add(existingPM);

                    if ((transportProtocol & PortMappingTransportProtocol.UDP) > 0)
                    {
                        existingMappingsUdpDict[ePort] = existingPM;
                    }
                    if ((transportProtocol & PortMappingTransportProtocol.TCP) > 0)
                    {
                        existingMappingsTcpDict[ePort] = existingPM;
                    }

                    DebugLog.WriteLine("Existing UPnP: {0}: {1} {2}->{3}:{4} ({5})",
                                                        i, protocolStr, ePort, iAddr, iPort, description);
                }

                i++;
            } while ((r == MiniUPnP.UPNPCOMMAND_SUCCESS) && (updatePortMappingsThreadFlags == ThreadFlags.None));

            // Update stored list of existing mappings
            existingUPnPPortMappings = existingMappings;
            existingUPnPPortMappingsUdpDict = existingMappingsUdpDict;
            existingUPnPPortMappingsTcpDict = existingMappingsTcpDict;
        }