///////////////////////////////////////////////////////////////////////////////// // 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; }
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; }
BOOL CUPnpMgr::CleanedFillupBug() { CSingleLock localLock(&m_cs, TRUE); if (FAILED(m_nat.SearchDevice())) return FALSE; HRESULT hr; USHORT usIndex; USHORT usExternalPort; CString strProtocol; CString strDesc; CString strInternalClient; CString strLocalIP; CArray<CUPnpNatMapping, const CUPnpNatMapping&> arrMapping; CUPnpNatMapping mapping; strLocalIP = GetLocalIPStr(); for (usIndex = 0; usIndex < 128; usIndex++) // 最多查询128项,以防止有些路由器可能会一直返回成功。 { hr = m_nat.GetGenericPortMappingEntry(usIndex, NULL, &usExternalPort, &strProtocol, NULL, &strInternalClient, NULL, &strDesc); if (-1 != strDesc.Find(_T("eMule ("))) // 描述里包含指定字样 { if (strInternalClient == strLocalIP) // 是本机添加的映射 m_nat.DeletePortMapping(CString(_T("")),usExternalPort, strProtocol); else { mapping.m_strInternalClient = strInternalClient; mapping.m_wExternalPort = usExternalPort; mapping.m_strProtocol = strProtocol; arrMapping.Add(mapping); } } if (FAILED(hr)) // 返回Failed结果,表示已经全部取完了。 break; } // 如果同一ip做的eMule映射超过3项,则很有可能是以前的bug所致。则清除。<begin> int i; int iMappingCount; CString strTestIp; while (! arrMapping.IsEmpty()) { strTestIp = arrMapping[0].m_strInternalClient; iMappingCount = 0; for (i = 0; i < arrMapping.GetCount(); i++) { if (strTestIp == arrMapping[i].m_strInternalClient) iMappingCount++; } for (i = arrMapping.GetCount() - 1; i >= 0; i--) { if (strTestIp == arrMapping[i].m_strInternalClient) { if (iMappingCount > 3) { m_nat.DeletePortMapping(CString(_T("")), arrMapping[i].m_wExternalPort, arrMapping[i].m_strProtocol); } arrMapping.RemoveAt(i); } } } // 如果同一ip做的eMule映射超过3项,则很有可能是以前的bug所致。则清除。<end> return TRUE; }