📄 turnsocket.cxx
字号:
#include "TurnSocket.hxx"#include "ErrorCode.hxx"#include <boost/bind.hpp>#include <rutil/Lock.hxx>#include <rutil/WinLeakCheck.hxx>#include <rutil/Logger.hxx>#include "../ReTurnSubsystem.hxx"#define RESIPROCATE_SUBSYSTEM ReTurnSubsystem::RETURNusing namespace std;#define UDP_RT0 100 // RTO - Estimate of Roundtrip time - 100ms is recommened for fixed line transport - the initial value should be configurable // Should also be calculation this on the fly#define UDP_MAX_RETRANSMITS 7 // Defined by RFC3489-bis11#define TCP_RESPONSE_TIME 7900 // Defined by RFC3489-bis11#define UDP_FINAL_REQUEST_TIME (UDP_RT0 * 16) // Defined by RFC3489-bis11namespace reTurn {// Initialize static membersunsigned int TurnSocket::UnspecifiedLifetime = 0xFFFFFFFF;unsigned int TurnSocket::UnspecifiedBandwidth = 0xFFFFFFFF; unsigned short TurnSocket::UnspecifiedPort = 0;asio::ip::address TurnSocket::UnspecifiedIpAddress = asio::ip::address::from_string("0.0.0.0");TurnSocket::TurnSocket(const asio::ip::address& address, unsigned short port) : mLocalBinding(StunTuple::None /* Set properly by sub class */, address, port), mHaveAllocation(false), mActiveDestination(0), mReadTimer(mIOService), mConnected(false){}TurnSocket::~TurnSocket(){}asio::error_code TurnSocket::requestSharedSecret(char* username, unsigned int usernameSize, char* password, unsigned int passwordSize){ asio::error_code errorCode; resip::Lock lock(mMutex); // Should we check here if TLS and deny? // Ensure Connected if(!mConnected) { return asio::error_code(reTurn::NotConnected, asio::error::misc_category); } // Form Shared Secret request StunMessage request; request.createHeader(StunMessage::StunClassRequest, StunMessage::SharedSecretMethod); // Get Response StunMessage* response = sendRequestAndGetResponse(request, errorCode); if(response == 0) { return errorCode; } // Check if success or not if(response->mHasErrorCode) { errorCode = asio::error_code(response->mErrorCode.errorClass * 100 + response->mErrorCode.number, asio::error::misc_category); delete response; return errorCode; } // Copy username and password to callers buffer - checking sizes first if(!response->mHasUsername || !response->mHasPassword) { WarningLog(<< "Stun response message for SharedSecretRequest is missing username and/or password!"); errorCode = asio::error_code(reTurn::MissingAuthenticationAttributes, asio::error::misc_category); delete response; return errorCode; } if(response->mUsername->size() > usernameSize || response->mPassword->size() > passwordSize) { WarningLog( << "Stun response message for SharedSecretRequest contains data that is too large to return!"); errorCode = asio::error_code(reTurn::BufferTooSmall, asio::error::misc_category); delete response; return errorCode; } // Copy username and password to passed in buffers memcpy(username, response->mUsername->c_str(), response->mUsername->size()+1); memcpy(password, response->mPassword->c_str(), response->mPassword->size()+1); // All was well - return 0 errorCode delete response; return errorCode;}void TurnSocket::setUsernameAndPassword(const char* username, const char* password){ mUsername = username; mPassword = password;}asio::error_code TurnSocket::bindRequest(){ asio::error_code errorCode; resip::Lock lock(mMutex); // Ensure Connected if(!mConnected) { return asio::error_code(reTurn::NotConnected, asio::error::misc_category); } // Form Stun Bind request StunMessage request; request.createHeader(StunMessage::StunClassRequest, StunMessage::BindMethod); if(!mUsername.empty()) { request.mHasMessageIntegrity = true; request.setUsername(mUsername.c_str()); request.mHmacKey = mPassword; } StunMessage* response = sendRequestAndGetResponse(request, errorCode); if(response == 0) { return errorCode; } mReflexiveTuple.setTransportType(mLocalBinding.getTransportType()); if(response->mHasXorMappedAddress) { StunMessage::setTupleFromStunAtrAddress(mReflexiveTuple, response->mXorMappedAddress); } else if(response->mHasMappedAddress) // Only look at MappedAddress if XorMappedAddress is not found - for backwards compatibility { StunMessage::setTupleFromStunAtrAddress(mReflexiveTuple, response->mMappedAddress); } // Check if success or not if(response->mHasErrorCode) { errorCode = asio::error_code(response->mErrorCode.errorClass * 100 + response->mErrorCode.number, asio::error::misc_category); } delete response; return errorCode;}asio::error_code TurnSocket::createAllocation(unsigned int lifetime, unsigned int bandwidth, unsigned short requestedPortProps, unsigned short requestedPort, StunTuple::TransportType requestedTransportType, const asio::ip::address &requestedIpAddress){ asio::error_code errorCode; resip::Lock lock(mMutex); // Store Allocation Properties mRequestedLifetime = lifetime; mRequestedBandwidth = bandwidth; mRequestedPortProps = requestedPortProps; mRequestedPort = requestedPort; mRequestedTransportType = requestedTransportType; mRequestedIpAddress = requestedIpAddress; // Ensure Connected if(!mConnected) { return asio::error_code(reTurn::NotConnected, asio::error::misc_category); } if(mHaveAllocation) { return asio::error_code(reTurn::AlreadyAllocated, asio::error::misc_category); } // Form Turn Allocate request StunMessage request; request.createHeader(StunMessage::StunClassRequest, StunMessage::TurnAllocateMethod); if(mRequestedLifetime != UnspecifiedLifetime) { request.mHasTurnLifetime = true; request.mTurnLifetime = mRequestedLifetime; } if(mRequestedBandwidth != UnspecifiedBandwidth) { request.mHasTurnBandwidth = true; request.mTurnBandwidth = mRequestedBandwidth; } if(mRequestedTransportType != StunTuple::None && mRequestedTransportType != StunTuple::TLS) { request.mHasTurnRequestedTransport = true; if(mRequestedTransportType == StunTuple::UDP) { request.mTurnRequestedTransport = StunMessage::RequestedTransportUdp; } else if(mRequestedTransportType == StunTuple::TCP && mLocalBinding.getTransportType() != StunTuple::UDP) // Ensure client is not requesting TCP over a UDP transport { request.mTurnRequestedTransport = StunMessage::RequestedTransportTcp; } else { return asio::error_code(reTurn::InvalidRequestedTransport, asio::error::misc_category); } } if(mRequestedIpAddress != UnspecifiedIpAddress) { request.mHasTurnRequestedIp = true; StunTuple requestedIpTuple(StunTuple::None, requestedIpAddress, 0); StunMessage::setStunAtrAddressFromTuple(request.mTurnRequestedIp, requestedIpTuple); } if(mRequestedPortProps != StunMessage::PortPropsNone || mRequestedPort != UnspecifiedPort) { request.mHasTurnRequestedPortProps = true; request.mTurnRequestedPortProps.props = mRequestedPortProps; request.mTurnRequestedPortProps.port = mRequestedPort; } request.mHasMessageIntegrity = true; request.setUsername(mUsername.data()); request.mHmacKey = mPassword; StunMessage* response = sendRequestAndGetResponse(request, errorCode); if(response == 0) { return errorCode; } if(response->mHasXorMappedAddress) { mReflexiveTuple.setTransportType(mLocalBinding.getTransportType()); StunMessage::setTupleFromStunAtrAddress(mReflexiveTuple, response->mXorMappedAddress); } if(response->mHasTurnRelayAddress) { // Transport Type is requested type or socket type if(request.mHasTurnRequestedTransport) { mRelayTuple.setTransportType(request.mHasTurnRequestedTransport == StunMessage::RequestedTransportUdp ? StunTuple::UDP : StunTuple::TCP); } else { mRelayTuple.setTransportType(mLocalBinding.getTransportType()); } StunMessage::setTupleFromStunAtrAddress(mRelayTuple, response->mTurnRelayAddress); } if(response->mHasTurnLifetime) { mLifetime = response->mTurnLifetime; } if(response->mHasTurnBandwidth) { mBandwidth = response->mTurnBandwidth; } // Check if success or not if(response->mHasErrorCode) { errorCode = asio::error_code(response->mErrorCode.errorClass * 100 + response->mErrorCode.number, asio::error::misc_category); delete response; return errorCode; } // All was well - return 0 errorCode if(mLifetime != 0) { mHaveAllocation = true; mAllocationRefreshTime = time(0) + ((mLifetime*5)/8); // Allocation refresh should sent before 3/4 lifetime - use 5/8 lifetime } delete response; return errorCode;}asio::error_code TurnSocket::refreshAllocation(){ asio::error_code errorCode; resip::Lock lock(mMutex); // Form Turn Allocate request StunMessage request; request.createHeader(StunMessage::StunClassRequest, StunMessage::TurnRefreshMethod); if(mRequestedLifetime != UnspecifiedLifetime) { request.mHasTurnLifetime = true; request.mTurnLifetime = mRequestedLifetime; } if(mRequestedBandwidth != UnspecifiedBandwidth) { request.mHasTurnBandwidth = true; request.mTurnBandwidth = mRequestedBandwidth; } request.mHasMessageIntegrity = true; request.setUsername(mUsername.data()); request.mHmacKey = mPassword; StunMessage* response = sendRequestAndGetResponse(request, errorCode); if(response == 0) { return errorCode; } // Check if success or not if(response->mHasErrorCode) { if(mRequestedLifetime != 0) { mHaveAllocation = false; } errorCode = asio::error_code(response->mErrorCode.errorClass * 100 + response->mErrorCode.number, asio::error::misc_category); delete response; return errorCode; } // All was well - return 0 errorCode if(mLifetime != 0) { mHaveAllocation = true; mAllocationRefreshTime = time(0) + ((mLifetime*5)/8); // Allocation refresh should sent before 3/4 lifetime - use 5/8 lifetime } else { mHaveAllocation = false; } delete response; return errorCode;}asio::error_code TurnSocket::destroyAllocation(){ resip::Lock lock(mMutex); if(mHaveAllocation) { mRequestedLifetime = 0; mRequestedBandwidth = UnspecifiedBandwidth; mRequestedPortProps = StunMessage::PortPropsNone; mRequestedPort = UnspecifiedPort; mRequestedTransportType = StunTuple::None;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -