///////////////////////////////////////////////////////////////////////////////// // Adds a NAT Port Mapping // Params: // UPNPNAT_MAPPING *mapping -> Port Mapping Data // If mapping->externalPort is 0, then // mapping->externalPort gets the value of mapping->internalPort // bool tryRandom: // If If mapping->externalPort is in use, tries to find a free // random external port. // // Return: // UNAT_OK: // Successfull. // UNAT_EXTERNAL_PORT_IN_USE: // Error, you are trying to add a port mapping with an external port // in use. // UNAT_NOT_IN_LAN: // Error, you aren't in a LAN -> no router or firewall // UNAT_ERROR: // Error, use GetLastError() to get an error description. ///////////////////////////////////////////////////////////////////////////////// MyUPnP::UPNPNAT_RETURN MyUPnP::AddNATPortMapping(UPNPNAT_MAPPING *mapping, bool tryRandom) { CString ProtoStr, Proto; if(!IsLANIP(GetLocalIP())){ SetLastError(GetResString(IDS_UPNPSTATUS_NOTINLAN)); //zz_fly :: localize output return UNAT_NOT_IN_LAN; } if (!isComplete()) { Search(); if (!isComplete()) { SetLastError(GetResString(IDS_UPNPSTATUS_ERROR)); //zz_fly :: localize output return UNAT_ERROR; } } if (mapping->protocol == UNAT_TCP){ Proto = _T("TCP"); ProtoStr = _T("TCP"); } else { Proto = _T("UDP"); ProtoStr = _T("UDP"); } if(mapping->externalPort == 0) mapping->externalPort = mapping->internalPort; //WORD rndPort = mapping->externalPort; for (int retries = 200; retries>0; retries--) { CString Desc; Desc.Format(_T("eMule (%s) [%s: %u]"), mapping->description, ProtoStr, mapping->externalPort); if (addPortmap(mapping->externalPort, mapping->internalPort, GetLocalIPStr(), Desc, Proto)) { m_Mappings.AddTail(*mapping); SetLastError(GetResString(IDS_UPNPSTATUS_OK)); //zz_fly :: localize output return UNAT_OK; } if (!tryRandom) { SetLastError(GetResString(IDS_UPNPSTATUS_PORTINUSE)); //zz_fly :: localize output return UNAT_EXTERNAL_PORT_IN_USE; } mapping->externalPort = (WORD)(2049 + (65535 - 2049) * rand() / (RAND_MAX + 1)); } SetLastError(GetResString(IDS_UPNPSTATUS_PORTINUSE2)); //zz_fly :: localize output return UNAT_EXTERNAL_PORT_IN_USE; }
///////////////////////////////////////////////////////////////////////////////// // Removes a NAT Port Mapping // Params: // UPNPNAT_MAPPING *mapping -> Port Mapping Data // Should be the same struct passed to AddNATPortMapping // bool removeFromList -> Remove the port mapping from the internal list // Should by allways true (dafault value if not passed). // If you set it to false can cause an unexpected error. // // // Return: // UNAT_OK: // Successfull. // UNAT_NOT_OWNED_PORTMAPPING: // Error, you are trying to remove a port mapping not owned by this class // UNAT_NOT_IN_LAN: // Error, you aren't in a LAN -> no router or firewall // UNAT_ERROR: // Error, use GetLastError() to get an error description. ///////////////////////////////////////////////////////////////////////////////// MyUPnP::UPNPNAT_RETURN MyUPnP::RemoveNATPortMapping(UPNPNAT_MAPPING mapping, bool removeFromList) { if(!IsLANIP(GetLocalIP())){ SetLastError(GetResString(IDS_UPNPSTATUS_NOTINLAN)); //zz_fly :: localize output return UNAT_NOT_IN_LAN; } if (!isComplete()) { Search(); if (!isComplete()) { SetLastError(GetResString(IDS_UPNPSTATUS_ERROR)); //zz_fly :: localize output return UNAT_ERROR; } } for(POSITION pos = m_Mappings.GetHeadPosition(); pos!=NULL; m_Mappings.GetNext(pos)){ UPNPNAT_MAPPING search = m_Mappings.GetAt(pos); if (search.externalPort == mapping.externalPort && search.protocol == mapping.protocol) { CString Proto; if (mapping.protocol == UNAT_TCP) Proto = _T("TCP"); else Proto = _T("UDP"); if (deletePortmap(mapping.externalPort, Proto)) { if(removeFromList) m_Mappings.RemoveAt(pos); SetLastError(_T("Removed")); return UNAT_OK; } else { SetLastError(_T("Error getting StaticPortMappingCollection")); return UNAT_ERROR; } } } SetLastError(_T("Port mapping not owned by this class")); return UNAT_NOT_OWNED_PORTMAPPING; }
HRESULT CUPnpMgr::AddNATPortMapping(CUPnpNatMapping &mapping, BOOL bTryRandom) { CSingleLock localLock(&m_cs, TRUE); if(!IsLANIP(GetLocalIP())) return E_UNAT_NOT_IN_LAN; if (FAILED(m_nat.SearchDevice())) return E_UNAT_CANNOT_FIND_ROUTER; HRESULT hr; CString strDesc; int i; if(0 == mapping.m_wExternalPort) mapping.m_wExternalPort = mapping.m_wInternalPort; mapping.m_strInternalClient = GetLocalIPStr(); for (i = 0; i < RANDOM_RETRY_TIMES; i++) { strDesc.Format(_T("%s [%s: %u]"), mapping.m_strDescription, mapping.m_strProtocol, mapping.m_wExternalPort); hr = m_nat.AddPortMapping(CString(_T("")), mapping.m_wExternalPort, mapping.m_strProtocol, mapping.m_wInternalPort, mapping.m_strInternalClient, strDesc); switch(hr) { case S_OK: { CString strInternalClient; hr = m_nat.GetSpecificPortMappingEntry(CString(_T("")), mapping.m_wExternalPort, mapping.m_strProtocol, NULL, &strInternalClient, NULL, NULL, NULL); if (SUCCEEDED(hr) && strInternalClient == mapping.m_strInternalClient) // 看PortMapping是否真的加进去了。 { CUPnpNatMappingKey key; key.m_strRemoteHost.Empty(); key.m_usExternalPort = mapping.m_wExternalPort; key.m_strProtocol = mapping.m_strProtocol; m_setAddedMapping.insert(key); WriteAddedMappingToFile(); return S_OK; } else // 如果添加请求成功返回而又不在列表中,则有可能是列表已满。 return E_UNAT_ENTRY_MAYBE_FULL; break; } case E_UNAT_ACTION_HTTP_ERRORCODE: { if (718 == m_nat.GetLastActionErrorCode() && bTryRandom) mapping.m_wExternalPort = (WORD)(2049 + (65535 - 2049) * 1 *rand() / (RAND_MAX + 1)); else return E_UNAT_ACTION_HTTP_ERRORCODE; break; } case E_UNAT_TIMEOUT: { // 为防止可能出现“实际加上了”但等待回复超时的情况,凡是执行了操作的都记下来,以便之后尝试清除一下。 CUPnpNatMappingKey key; key.m_strRemoteHost.Empty(); key.m_usExternalPort = mapping.m_wExternalPort; key.m_strProtocol = mapping.m_strProtocol; m_setAddedMapping.insert(key); WriteAddedMappingToFile(); return E_UNAT_TIMEOUT; // 超时未返回则直接返回,而不去重试。(因为此刻可能实际上添加成功,而不停去添加,可能造成路由器表项充满。) break; } default: return hr; } } return E_UNAT_REACH_RAND_PORT_RETRY_TIMES; }