📄 pstun.cxx
字号:
}};bool PSTUNClient::OpenSocket(PUDPSocket & socket, PortInfo & portInfo) const{ PWaitAndSignal mutex(portInfo.mutex); WORD startPort = portInfo.currentPort; do { portInfo.currentPort++; if (portInfo.currentPort > portInfo.maxPort) portInfo.currentPort = portInfo.basePort; if (socket.Listen(1, portInfo.currentPort)) { socket.SetSendAddress(serverAddress, serverPort); socket.SetReadTimeout(replyTimeout); return true; } } while (portInfo.currentPort != startPort); PTRACE(1, "STUN\tFailed to bind to local UDP port in range " << portInfo.currentPort << '-' << portInfo.maxPort); return false;}PSTUNClient::NatTypes PSTUNClient::GetNatType(BOOL force){ if (!force && natType != UnknownNat) return natType; PUDPSocket socket; if (!OpenSocket(socket, singlePortInfo)) return natType = UnknownNat; // RFC3489 discovery /* test I - the client sends a STUN Binding Request to a server, without any flags set in the CHANGE-REQUEST attribute, and without the RESPONSE-ADDRESS attribute. This causes the server to send the response back to the address and port that the request came from. */ PSTUNMessage requestI(PSTUNMessage::BindingRequest); requestI.AddAttribute(PSTUNChangeRequest(false, false)); PSTUNMessage responseI; if (!responseI.Poll(socket, requestI, pollRetries)) { if (socket.GetErrorCode(PChannel::LastWriteError) != PChannel::NoError) { PTRACE(1, "STUN\tError writing to server " << serverAddress << ':' << serverPort << " - " << socket.GetErrorText(PChannel::LastWriteError)); return natType = UnknownNat; // No response usually means blocked } PTRACE(3, "STUN\tNo response to server " << serverAddress << ':' << serverPort << " - " << socket.GetErrorText(PChannel::LastReadError)); return natType = BlockedNat; // No response usually means blocked } PSTUNMappedAddress * mappedAddress = (PSTUNMappedAddress *)responseI.FindAttribute(PSTUNAttribute::MAPPED_ADDRESS); if (mappedAddress == NULL) { PTRACE(2, "STUN\tExpected mapped address attribute from server " << serverAddress << ':' << serverPort); return natType = UnknownNat; // Protocol error } PIPSocket::Address mappedAddressI = mappedAddress->GetIP(); WORD mappedPortI = mappedAddress->port; bool notNAT = socket.GetPort() == mappedPortI && PIPSocket::IsLocalHost(mappedAddressI); /* Test II - the client sends a Binding Request with both the "change IP" and "change port" flags from the CHANGE-REQUEST attribute set. */ PSTUNMessage requestII(PSTUNMessage::BindingRequest); requestII.AddAttribute(PSTUNChangeRequest(true, true)); PSTUNMessage responseII; bool testII = responseII.Poll(socket, requestII, pollRetries); if (notNAT) { // Is not NAT or symmetric firewall return natType = (testII ? OpenNat : SymmetricFirewall); } if (testII) return natType = ConeNat; PSTUNChangedAddress * changedAddress = (PSTUNChangedAddress *)responseI.FindAttribute(PSTUNAttribute::CHANGED_ADDRESS); if (changedAddress == NULL) return natType = UnknownNat; // Protocol error // Send test I to another server, to see if restricted or symmetric PIPSocket::Address secondaryServer = changedAddress->GetIP(); WORD secondaryPort = changedAddress->port; socket.SetSendAddress(secondaryServer, secondaryPort); PSTUNMessage requestI2(PSTUNMessage::BindingRequest); requestI2.AddAttribute(PSTUNChangeRequest(false, false)); PSTUNMessage responseI2; if (!responseI2.Poll(socket, requestI2, pollRetries)) { PTRACE(2, "STUN\tPoll of secondary server " << secondaryServer << ':' << secondaryPort << " failed, NAT partially blocked by firwall rules."); return natType = PartialBlockedNat; } mappedAddress = (PSTUNMappedAddress *)responseI2.FindAttribute(PSTUNAttribute::MAPPED_ADDRESS); if (mappedAddress == NULL) { PTRACE(2, "STUN\tExpected mapped address attribute from server " << serverAddress << ':' << serverPort); return UnknownNat; // Protocol error } if (mappedAddress->port != mappedPortI || mappedAddress->GetIP() != mappedAddressI) return natType = SymmetricNat; socket.SetSendAddress(serverAddress, serverPort); PSTUNMessage requestIII(PSTUNMessage::BindingRequest); requestIII.SetAttribute(PSTUNChangeRequest(false, true)); PSTUNMessage responseIII; return natType = (responseIII.Poll(socket, requestIII, pollRetries) ? RestrictedNat : PortRestrictedNat);}PString PSTUNClient::GetNatTypeString(NatTypes type){ static const char * const Names[NumNatTypes] = { "Unknown NAT", "Open NAT", "Cone NAT", "Restricted NAT", "Port Restricted NAT", "Symmetric NAT", "Symmetric Firewall", "Blocked", "Partially Blocked" }; if (type < NumNatTypes) return Names[type]; return psprintf("<NATType %u>", type);}PSTUNClient::RTPSupportTypes PSTUNClient::IsSupportingRTP(BOOL force){ switch (GetNatType(force)) { // types that do support RTP case OpenNat: case ConeNat: return RTPOK; // types that support RTP if media sent first case SymmetricFirewall: case RestrictedNat: case PortRestrictedNat: return RTPIfSendMedia; // types that do not support RTP case BlockedNat: case SymmetricNat: return RTPUnsupported; // types that have unknown RTP support case UnknownNat: case PartialBlockedNat: default: break; } return RTPUnknown;}BOOL PSTUNClient::GetExternalAddress(PIPSocket::Address & externalAddress, const PTimeInterval & maxAge){ if (cachedExternalAddress.IsValid() && (PTime() - timeAddressObtained > maxAge)) { externalAddress = cachedExternalAddress; return TRUE; } externalAddress = 0; // Set to invalid address PUDPSocket socket; if (!OpenSocket(socket, singlePortInfo)) return false; PSTUNMessage request(PSTUNMessage::BindingRequest); request.AddAttribute(PSTUNChangeRequest(false, false)); PSTUNMessage response; if (!response.Poll(socket, request, pollRetries)) { PTRACE(1, "STUN\tServer " << serverAddress << ':' << serverPort << " unexpectedly went offline."); return false; } PSTUNMappedAddress * mappedAddress = (PSTUNMappedAddress *)response.FindAttribute(PSTUNAttribute::MAPPED_ADDRESS); if (mappedAddress == NULL) { PTRACE(2, "STUN\tExpected mapped address attribute from server " << serverAddress << ':' << serverPort); return false; } externalAddress = cachedExternalAddress = mappedAddress->GetIP(); timeAddressObtained = PTime(); return true;}BOOL PSTUNClient::CreateSocket(PUDPSocket * & socket){ socket = NULL; switch (GetNatType(FALSE)) { case ConeNat : case RestrictedNat : case PortRestrictedNat : break; case SymmetricNat : if (singlePortInfo.basePort == 0 || singlePortInfo.basePort > singlePortInfo.maxPort) { PTRACE(1, "STUN\tInvalid local UDP port range " << singlePortInfo.currentPort << '-' << singlePortInfo.maxPort); return FALSE; } break; default : // UnknownNet, SymmetricFirewall, BlockedNat PTRACE(1, "STUN\tCannot create socket using NAT type " << GetNatTypeName()); return FALSE; } PSTUNUDPSocket * stunSocket = new PSTUNUDPSocket; if (OpenSocket(*stunSocket, singlePortInfo)) { PSTUNMessage request(PSTUNMessage::BindingRequest); request.AddAttribute(PSTUNChangeRequest(false, false)); PSTUNMessage response; if (response.Poll(*stunSocket, request, pollRetries)) { PSTUNMappedAddress * mappedAddress = (PSTUNMappedAddress *)response.FindAttribute(PSTUNAttribute::MAPPED_ADDRESS); if (mappedAddress != NULL) { stunSocket->externalIP = mappedAddress->GetIP(); if (GetNatType(FALSE) != SymmetricNat) stunSocket->port = mappedAddress->port; stunSocket->SetSendAddress(0, 0); stunSocket->SetReadTimeout(PMaxTimeInterval); socket = stunSocket; return true; } PTRACE(2, "STUN\tExpected mapped address attribute from server " << serverAddress << ':' << serverPort); } else PTRACE(1, "STUN\tServer " << serverAddress << ':' << serverPort << " unexpectedly went offline."); } delete stunSocket; return false;}BOOL PSTUNClient::CreateSocketPair(PUDPSocket * & socket1, PUDPSocket * & socket2){ socket1 = NULL; socket2 = NULL; switch (GetNatType(FALSE)) { case ConeNat : case RestrictedNat : case PortRestrictedNat : break; case SymmetricNat : if (pairedPortInfo.basePort == 0 || pairedPortInfo.basePort > pairedPortInfo.maxPort) { PTRACE(1, "STUN\tInvalid local UDP port range " << pairedPortInfo.currentPort << '-' << pairedPortInfo.maxPort); return FALSE; } break; default : // UnknownNet, SymmetricFirewall, BlockedNat PTRACE(1, "STUN\tCannot create socket pair using NAT type " << GetNatTypeName()); return FALSE; } PINDEX i; PList<PSTUNUDPSocket> stunSocket; PList<PSTUNMessage> request; PList<PSTUNMessage> response; for (i = 0; i < numSocketsForPairing; i++) { PINDEX idx = stunSocket.Append(new PSTUNUDPSocket); if (!OpenSocket(stunSocket[idx], pairedPortInfo)) return false; idx = request.Append(new PSTUNMessage(PSTUNMessage::BindingRequest)); request[idx].AddAttribute(PSTUNChangeRequest(false, false)); response.Append(new PSTUNMessage); } for (i = 0; i < numSocketsForPairing; i++) { if (!response[i].Poll(stunSocket[i], request[i], pollRetries)) { PTRACE(1, "STUN\tServer " << serverAddress << ':' << serverPort << " unexpectedly went offline."); return false; } } for (i = 0; i < numSocketsForPairing; i++) { PSTUNMappedAddress * mappedAddress = (PSTUNMappedAddress *)response[i].FindAttribute(PSTUNAttribute::MAPPED_ADDRESS); if (mappedAddress == NULL) { PTRACE(2, "STUN\tExpected mapped address attribute from server " << serverAddress << ':' << serverPort); return false; } if (GetNatType(FALSE) != SymmetricNat) stunSocket[i].port = mappedAddress->port; stunSocket[i].externalIP = mappedAddress->GetIP(); } for (i = 0; i < numSocketsForPairing; i++) { for (PINDEX j = 0; j < numSocketsForPairing; j++) { if ((stunSocket[i].port&1) == 0 && (stunSocket[i].port+1) == stunSocket[j].port) { stunSocket[i].SetSendAddress(0, 0); stunSocket[i].SetReadTimeout(PMaxTimeInterval); stunSocket[j].SetSendAddress(0, 0); stunSocket[j].SetReadTimeout(PMaxTimeInterval); socket1 = &stunSocket[i]; socket2 = &stunSocket[j]; stunSocket.DisallowDeleteObjects(); stunSocket.Remove(socket1); stunSocket.Remove(socket2); stunSocket.AllowDeleteObjects(); return true; } } } PTRACE(2, "STUN\tCould not get a pair of adjacent port numbers from NAT"); return false;}BOOL PSTUNClient::IsAvailable() { switch (GetNatType(FALSE)) { case ConeNat : case RestrictedNat : case PortRestrictedNat : break; case SymmetricNat : if (pairedPortInfo.basePort == 0 || pairedPortInfo.basePort > pairedPortInfo.maxPort) return FALSE; break; default : // UnknownNet, SymmetricFirewall, BlockedNat return FALSE; } return TRUE; }////////////////////////////////////////////////////////////////PSTUNUDPSocket::PSTUNUDPSocket() : externalIP(0){}BOOL PSTUNUDPSocket::GetLocalAddress(Address & addr){ if (!externalIP.IsValid()) return PUDPSocket::GetLocalAddress(addr); addr = externalIP; return true;}BOOL PSTUNUDPSocket::GetLocalAddress(Address & addr, WORD & port){ if (!externalIP.IsValid()) return PUDPSocket::GetLocalAddress(addr, port); addr = externalIP; port = GetPort(); return true;}// End of File ////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -