private bool AddPortMapping(PortMapping portMapping) { portMapping.SetMappingStatus(PortMappingStatus.Trying); String intPortStr = portMapping.LocalPort.ToString(); String intClient = PortMapper.SharedInstance.LocalIPAddress.ToString(); String description = GetPortMappingDescription(); bool done = false; int attemptCount = 0; do { int udpErrCode = 0; int tcpErrCode = 0; bool udpResult = true; bool tcpResult = true; UInt16 extPort; if (portMapping.DesiredExternalPort < (65535 - 40)) { extPort = (UInt16)(portMapping.DesiredExternalPort + attemptCount); } else { extPort = (UInt16)(portMapping.DesiredExternalPort - attemptCount); } String extPortStr = extPort.ToString(); if ((portMapping.TransportProtocol & PortMappingTransportProtocol.UDP) > 0) { ExistingUPnPPortMapping existingPM; if (existingUPnPPortMappingsUdpDict.TryGetValue(extPort, out existingPM)) { udpErrCode = 718; DebugLog.WriteLine("UPnP: AddPortMapping: UDP: mapping already exists"); } else { udpErrCode = MiniUPnP.UPNP_AddPortMapping(urls.controlURL, igddata.ServiceType, extPortStr, intPortStr, intClient, description, "UDP"); DebugLog.WriteLine("UPnP: AddPortMapping: UDP: result = {0}", udpErrCode); } udpResult = (udpErrCode == MiniUPnP.UPNPCOMMAND_SUCCESS); } if ((portMapping.TransportProtocol & PortMappingTransportProtocol.TCP) > 0) { ExistingUPnPPortMapping existingPM; if (existingUPnPPortMappingsTcpDict.TryGetValue(extPort, out existingPM)) { tcpErrCode = 718; DebugLog.WriteLine("UPnP: AddPortMapping: TCP: mapping already exists"); } else { tcpErrCode = MiniUPnP.UPNP_AddPortMapping(urls.controlURL, igddata.ServiceType, extPortStr, intPortStr, intClient, description, "TCP"); DebugLog.WriteLine("UPnP: AddPortMapping: TCP: result = {0}", tcpErrCode); } tcpResult = (tcpErrCode == MiniUPnP.UPNPCOMMAND_SUCCESS); } if (udpResult && !tcpResult) { DebugLog.WriteLine("Deleting UDP mapping"); try { 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"); } } if (tcpResult && !udpResult) { DebugLog.WriteLine("Deleting TCP mapping"); try { 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"); } } if (udpResult && tcpResult) { // All attempted port mappings were successful portMapping.SetExternalPort(extPort); portMapping.SetMappingStatus(PortMappingStatus.Mapped); return(true); } attemptCount++; if (attemptCount >= 10) { // We've tried 10 different mappings and still no success done = true; } else if (!udpResult && udpErrCode != 718) { // We received non-conflict error done = true; } else if (!tcpResult && tcpErrCode != 718) { // We received non-conflict error done = true; } } while (!done); portMapping.SetMappingStatus(PortMappingStatus.Unmapped); return(false); }
private bool RemovePortMapping(PortMapping portMapping) { // Make sure the mapping still belongs to us IPAddress ourIP = PortMapper.SharedInstance.LocalIPAddress; String ourDescription = GetPortMappingDescription(); bool udpMappingStolen = false; bool tcpMappingStolen = false; if ((portMapping.TransportProtocol & PortMappingTransportProtocol.UDP) > 0) { ExistingUPnPPortMapping existingPM; if (existingUPnPPortMappingsUdpDict.TryGetValue(portMapping.ExternalPort, out existingPM)) { if (!existingPM.LocalAddress.Equals(ourIP) || !existingPM.Description.Equals(ourDescription)) { // The mapping was stolen by another machine or process // Do not remove it, but for our purposes we can consider it removed DebugLog.WriteLine("UPnP: RemovePortMapping: UDP mapping stolen"); udpMappingStolen = true; } } } if ((portMapping.TransportProtocol & PortMappingTransportProtocol.TCP) > 0) { ExistingUPnPPortMapping existingPM; if (existingUPnPPortMappingsTcpDict.TryGetValue(portMapping.ExternalPort, out existingPM)) { if (!existingPM.LocalAddress.Equals(ourIP) || !existingPM.Description.Equals(ourDescription)) { // The mapping was stolen by another machine or process // Do not remove it, but for our purposes we can consider it removed DebugLog.WriteLine("UPnP: RemovePortMapping: TCM mapping stolen"); tcpMappingStolen = true; } } } int result = MiniUPnP.UPNPCOMMAND_SUCCESS; bool udpResult = true; bool tcpResult = true; String extPortStr = portMapping.ExternalPort.ToString(); if ((portMapping.TransportProtocol & PortMappingTransportProtocol.UDP) > 0 && !udpMappingStolen) { 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 && !tcpMappingStolen) { 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); } portMapping.SetMappingStatus(PortMappingStatus.Unmapped); return(udpResult && tcpResult); }
private bool ApplyPortMapping(PortMapping portMapping, bool remove, ref NATPMP.natpmp_t natpmp) { NATPMP.natpmpresp_t response = new NATPMP.natpmpresp_t(); int r; Win32.TimeValue timeout = new Win32.TimeValue(); Win32.FileDescriptorSet fds = new Win32.FileDescriptorSet(1); if (!remove) { portMapping.SetMappingStatus(PortMappingStatus.Trying); } PortMappingTransportProtocol protocol = portMapping.TransportProtocol; for (int i = 1; i <= 2; i++) { PortMappingTransportProtocol currentProtocol; if (i == 1) { currentProtocol = PortMappingTransportProtocol.UDP; } else { currentProtocol = PortMappingTransportProtocol.TCP; } if (protocol == currentProtocol || protocol == PortMappingTransportProtocol.Both) { r = NATPMP.sendnewportmappingrequest(ref natpmp, (i == 1) ? NATPMP.PROTOCOL_UDP : NATPMP.PROTOCOL_TCP, portMapping.LocalPort, portMapping.DesiredExternalPort, (uint)(remove ? 0 : 3600)); do { fds.Count = 1; fds.Array[0] = (IntPtr)natpmp.s; NATPMP.getnatpmprequesttimeout(ref natpmp, ref timeout); Win32.select(0, ref fds, IntPtr.Zero, IntPtr.Zero, ref timeout); r = NATPMP.readnatpmpresponseorretry(ref natpmp, ref response); }while(r == NATPMP.ERR_TRYAGAIN); if (r < 0) { portMapping.SetMappingStatus(PortMappingStatus.Unmapped); return(false); } } } if (remove) { portMapping.SetMappingStatus(PortMappingStatus.Unmapped); } else { updateInterval = Math.Min(updateInterval, response.pnu_newportmapping.lifetime / 2); if (updateInterval < 60) { DebugLog.WriteLine("NAT-PMP: ApplyPortMapping: Caution - new port mapping had a lifetime < 120 ({0})", response.pnu_newportmapping.lifetime); updateInterval = 60; } portMapping.SetExternalPort(response.pnu_newportmapping.mappedpublicport); portMapping.SetMappingStatus(PortMappingStatus.Mapped); } return(true); }