📄 turnasyncsocket.cxx
字号:
handleStunMessage(*stunMsg); delete stunMsg; } else { RemotePeer* remotePeer = mChannelManager.findRemotePeerByServerToClientChannel(channelNumber); if(remotePeer) { data->offset(4); // move buffer start past framing for callback if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onReceiveSuccess(getSocketDescriptor(), remotePeer->getPeerTuple().getAddress(), remotePeer->getPeerTuple().getPort(), data); } else { WarningLog(<< "TurnAsyncSocket::handleReceivedData: receive channel data for non-existing channel - discarding!"); } } } else // size <= 4 { WarningLog(<< "TurnAsyncSocket::handleReceivedData: not enought data received for framed message - discarding!"); if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onReceiveFailure(getSocketDescriptor(), asio::error_code(reTurn::FrameError, asio::error::misc_category)); } } else { // mTurnFraming is disabled - message could be a Stun Message if first byte is 0 or 1 if((*data)[0] == 0 || (*data)[0] == 1) { StunMessage* stunMsg = new StunMessage(mLocalBinding, StunTuple(mLocalBinding.getTransportType(), mAsyncSocketBase.getConnectedAddress(), mAsyncSocketBase.getConnectedPort()), &(*data)[0], data->size()); if(stunMsg->isValid()) { handleStunMessage(*stunMsg); delete stunMsg; return; } delete stunMsg; } // Not a stun message so assume normal data if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onReceiveSuccess(getSocketDescriptor(), address, port, data); }}asio::error_code TurnAsyncSocket::handleStunMessage(StunMessage& stunMessage){ asio::error_code errorCode; if(stunMessage.isValid()) { if(!stunMessage.checkMessageIntegrity(mHmacKey)) { WarningLog(<< "TurnAsyncSocket::handleStunMessage: Stun message integrity is bad!"); return asio::error_code(reTurn::BadMessageIntegrity, asio::error::misc_category); } // Request is authenticated, process it switch(stunMessage.mClass) { case StunMessage::StunClassRequest: switch (stunMessage.mMethod) { case StunMessage::BindMethod: errorCode = handleBindRequest(stunMessage); break; case StunMessage::SharedSecretMethod: case StunMessage::TurnAllocateMethod: case StunMessage::TurnRefreshMethod: default: // These requests are not handled by a client StunMessage* response = new StunMessage(); response->mClass = StunMessage::StunClassErrorResponse; response->setErrorCode(400, "Invalid Request Method"); // Copy over TransactionId response->mHeader.magicCookieAndTid = stunMessage.mHeader.magicCookieAndTid; sendStunMessage(response); break; } break; case StunMessage::StunClassIndication: switch (stunMessage.mMethod) { case StunMessage::TurnDataMethod: errorCode = handleDataInd(stunMessage); break; case StunMessage::TurnChannelConfirmationMethod: errorCode = handleChannelConfirmation(stunMessage); break; case StunMessage::BindMethod: // A Bind indication is simply a keepalive with no response required break; case StunMessage::TurnSendMethod: // Don't need to handle these - only sent by client, never received default: // Unknown indication - just ignore break; } break; case StunMessage::StunClassSuccessResponse: case StunMessage::StunClassErrorResponse: { // First check if this response if for an active request RequestMap::iterator it = mActiveRequestMap.find(stunMessage.mHeader.magicCookieAndTid); if(it == mActiveRequestMap.end()) { // Stray response - dropping return asio::error_code(reTurn::StrayResponse, asio::error::misc_category); } else { it->second->stopTimer(); // If a realm and nonce attributes are present and the response is a 401 or 438 (Nonce Expired), // then re-issue request with new auth attributes if(stunMessage.mHasRealm && stunMessage.mHasNonce && stunMessage.mHasErrorCode && stunMessage.mErrorCode.errorClass == 4 && ((stunMessage.mErrorCode.number == 1 && mHmacKey.empty()) || // Note if 401 error then ensure we haven't already tried once - if we've tried then mHmacKey will be populated stunMessage.mErrorCode.number == 38)) { mNonce = *stunMessage.mNonce; mRealm = *stunMessage.mRealm; MD5Stream r; r << mUsername << ":" << mRealm << ":" << mPassword; mHmacKey = r.getHex(); // Create a new transaction - by starting with old request StunMessage* newRequest = it->second->mRequestMessage; it->second->mRequestMessage = 0; // clear out pointer in mActiveRequestMap so that it will not be deleted mActiveRequestMap.erase(it); newRequest->createHeader(newRequest->mClass, newRequest->mMethod); // updates TID newRequest->mHasMessageIntegrity = true; newRequest->setUsername(mUsername.c_str()); newRequest->mHmacKey = mHmacKey; newRequest->setRealm(mRealm.c_str()); newRequest->setNonce(mNonce.c_str()); sendStunMessage(newRequest); return errorCode; } mActiveRequestMap.erase(it); } switch (stunMessage.mMethod) { case StunMessage::BindMethod: errorCode = handleBindResponse(stunMessage); break; case StunMessage::SharedSecretMethod: errorCode = handleSharedSecretResponse(stunMessage); break; case StunMessage::TurnAllocateMethod: errorCode = handleAllocateResponse(stunMessage); break; case StunMessage::TurnRefreshMethod: errorCode = handleRefreshResponse(stunMessage); break; default: // Unknown method - just ignore break; } } break; default: // Illegal message class - ignore break; } } else { WarningLog(<< "TurnAsyncSocket::handleStunMessage: Read Invalid StunMsg."); return asio::error_code(reTurn::ErrorParsingMessage, asio::error::misc_category); } return errorCode;}asio::error_codeTurnAsyncSocket::handleDataInd(StunMessage& stunMessage){ if(!stunMessage.mHasTurnPeerAddress || !stunMessage.mHasTurnChannelNumber) { // Missing RemoteAddress or ChannelNumber attribute WarningLog(<< "TurnAsyncSocket::handleDataInd: DataInd missing attributes."); return asio::error_code(reTurn::MissingAttributes, asio::error::misc_category); } StunTuple remoteTuple; remoteTuple.setTransportType(mRelayTransportType); StunMessage::setTupleFromStunAtrAddress(remoteTuple, stunMessage.mTurnPeerAddress); RemotePeer* remotePeer = mChannelManager.findRemotePeerByPeerAddress(remoteTuple); if(!remotePeer) { // Remote Peer not found - discard data WarningLog(<< "TurnAsyncSocket::handleDataInd: Data received from unknown RemotePeer " << remoteTuple << " - discarding"); return asio::error_code(reTurn::UnknownRemoteAddress, asio::error::misc_category); } if(remotePeer->getServerToClientChannel() != 0 && remotePeer->getServerToClientChannel() != stunMessage.mTurnChannelNumber) { // Mismatched channel number WarningLog(<< "TurnAsyncSocket::handleDataInd: Channel number received in DataInd (" << (int)stunMessage.mTurnChannelNumber << ") does not match existing number for RemotePeer (" << (int)remotePeer->getServerToClientChannel() << ")."); return asio::error_code(reTurn::InvalidChannelNumberReceived, asio::error::misc_category); } if(!remotePeer->isServerToClientChannelConfirmed()) { remotePeer->setServerToClientChannel(stunMessage.mTurnChannelNumber); remotePeer->setServerToClientChannelConfirmed(); mChannelManager.addRemotePeerServerToClientChannelLookup(remotePeer); } if(mLocalBinding.getTransportType() == StunTuple::UDP) { // If UDP, then send TurnChannelConfirmationInd StunMessage* channelConfirmationInd = createNewStunMessage(StunMessage::StunClassIndication, StunMessage::TurnChannelConfirmationMethod, false); channelConfirmationInd->mHasTurnPeerAddress = true; channelConfirmationInd->mTurnPeerAddress = stunMessage.mTurnPeerAddress; channelConfirmationInd->mHasTurnChannelNumber = true; channelConfirmationInd->mTurnChannelNumber = stunMessage.mTurnChannelNumber; // send channelConfirmationInd to local client sendStunMessage(channelConfirmationInd); } if(stunMessage.mHasTurnData) { boost::shared_ptr<DataBuffer> data(new DataBuffer(stunMessage.mTurnData->data(), stunMessage.mTurnData->size())); if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onReceiveSuccess(getSocketDescriptor(), remoteTuple.getAddress(), remoteTuple.getPort(), data); } return asio::error_code();}asio::error_codeTurnAsyncSocket::handleChannelConfirmation(StunMessage &stunMessage){ if(!stunMessage.mHasTurnPeerAddress || !stunMessage.mHasTurnChannelNumber) { // Missing RemoteAddress or ChannelNumber attribute WarningLog(<< "TurnAsyncSocket::handleChannelConfirmation: DataInd missing attributes."); return asio::error_code(reTurn::MissingAttributes, asio::error::misc_category); } StunTuple remoteTuple; remoteTuple.setTransportType(mRelayTransportType); StunMessage::setTupleFromStunAtrAddress(remoteTuple, stunMessage.mTurnPeerAddress); RemotePeer* remotePeer = mChannelManager.findRemotePeerByClientToServerChannel(stunMessage.mTurnChannelNumber); if(!remotePeer) { // Remote Peer not found - discard WarningLog(<< "TurnAsyncSocket::handleChannelConfirmation: Received ChannelConfirmationInd for unknown channel (" << stunMessage.mTurnChannelNumber << ") - discarding"); return asio::error_code(reTurn::InvalidChannelNumberReceived, asio::error::misc_category); } if(remotePeer->getPeerTuple() != remoteTuple) { // Mismatched remote address WarningLog(<< "TurnAsyncSocket::handleChannelConfirmation: RemoteAddress associated with channel (" << remotePeer->getPeerTuple() << ") does not match ChannelConfirmationInd (" << remoteTuple << ")."); return asio::error_code(reTurn::UnknownRemoteAddress, asio::error::misc_category); } remotePeer->setClientToServerChannelConfirmed(); return asio::error_code();}asio::error_code TurnAsyncSocket::handleSharedSecretResponse(StunMessage& stunMessage){ if(stunMessage.mClass == StunMessage::StunClassSuccessResponse) { // Copy username and password to callers buffer - checking sizes first if(!stunMessage.mHasUsername || !stunMessage.mHasPassword) { WarningLog(<< "TurnAsyncSocket::handleSharedSecretResponse: Stun response message for SharedSecretRequest is missing username and/or password!"); if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onSharedSecretFailure(getSocketDescriptor(), asio::error_code(MissingAttributes, asio::error::misc_category)); return asio::error_code(MissingAttributes, asio::error::misc_category); } if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onSharedSecretSuccess(getSocketDescriptor(), stunMessage.mUsername->c_str(), stunMessage.mUsername->size(), stunMessage.mPassword->c_str(), stunMessage.mPassword->size()); } else { // Check if success or not if(stunMessage.mHasErrorCode) { if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onSharedSecretFailure(getSocketDescriptor(), asio::error_code(stunMessage.mErrorCode.errorClass * 100 + stunMessage.mErrorCode.number, asio::error::misc_category)); } else { if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onSharedSecretFailure(getSocketDescriptor(), asio::error_code(MissingAttributes, asio::error::misc_category)); return asio::error_code(MissingAttributes, asio::error::misc_category); } } return asio::error_code();}asio::error_codeTurnAsyncSocket::handleBindRequest(StunMessage& stunMessage){ // Note: handling of BindRequest is not fully backwards compatible with RFC3489 - it is inline with bis13 StunMessage* response = new StunMessage(); // form the outgoing message response->mClass = StunMessage::StunClassSuccessResponse; response->mMethod = StunMessage::BindMethod; // Copy over TransactionId response->mHeader.magicCookieAndTid = stunMessage.mHeader.magicCookieAndTid; // Add XOrMappedAddress to response response->mHasXorMappedAddress = true; StunMessage::setStunAtrAddressFromTuple(response->mXorMappedAddress, stunMessage.mRemoteTuple); // send bindResponse to local client sendStunMessage(response); return asio::error_code();}asio::error_code TurnAsyncSocket::handleBindResponse(StunMessage& stunMessage){ if(stunMessage.mClass == StunMessage::StunClassSuccessResponse) { StunTuple reflexiveTuple; reflexiveTuple.setTransportType(mLocalBinding.getTransportType()); if(stunMessage.mHasXorMappedAddress) { StunMessage::setTupleFromStunAtrAddress(reflexiveTuple, stunMessage.mXorMappedAddress); } else if(stunMessage.mHasMappedAddress) // Only look at MappedAddress if XorMappedAddress is not found - for backwards compatibility { StunMessage::setTupleFromStunAtrAddress(reflexiveTuple, stunMessage.mMappedAddress); } else { if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onBindFailure(getSocketDescriptor(), asio::error_code(MissingAttributes, asio::error::misc_category)); return asio::error_code(MissingAttributes, asio::error::misc_category); } if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onBindSuccess(getSocketDescriptor(), reflexiveTuple); } else { // Check if success or not if(stunMessage.mHasErrorCode) { if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onBindFailure(getSocketDescriptor(), asio::error_code(stunMessage.mErrorCode.errorClass * 100 + stunMessage.mErrorCode.number, asio::error::misc_category)); } else { if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onBindFailure(getSocketDescriptor(), asio::error_code(MissingAttributes, asio::error::misc_category)); return asio::error_code(MissingAttributes, asio::error::misc_category); } } return asio::error_code();}asio::error_code TurnAsyncSocket::handleAllocateResponse(StunMessage& stunMessage){ if(stunMessage.mClass == StunMessage::StunClassSuccessResponse) { StunTuple reflexiveTuple; StunTuple relayTuple; if(stunMessage.mHasXorMappedAddress) { reflexiveTuple.setTransportType(mLocalBinding.getTransportType()); StunMessage::setTupleFromStunAtrAddress(reflexiveTuple, stunMessage.mXorMappedAddress); } if(stunMessage.mHasTurnRelayAddress) { relayTuple.setTransportType(mRelayTransportType); StunMessage::setTupleFromStunAtrAddress(relayTuple, stunMessage.mTurnRelayAddress); } if(stunMessage.mHasTurnLifetime) { mLifetime = stunMessage.mTurnLifetime; } else { mLifetime = 0; } // All was well - return 0 errorCode if(mLifetime != 0) { mHaveAllocation = true; startAllocationTimer(); if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onAllocationSuccess(getSocketDescriptor(), reflexiveTuple, relayTuple, mLifetime, stunMessage.mHasTurnBandwidth ? stunMessage.mTurnBandwidth : 0); } else { if(mTurnAsyncSocketHandler) mTurnAsyncSocketHandler->onAllocationFailure(getSocketDescriptor(), asio::error_code(MissingAttributes, asio::error::misc_category));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -