2#include "../AsyncSocketBase.hxx"
7#include "../ReTurnSubsystem.hxx"
9#define RESIPROCATE_SUBSYSTEM ReTurnSubsystem::RETURN
16#define UDP_MAX_RETRANSMITS 7
17#define TCP_RESPONSE_TIME 39500
19#define UDP_FINAL_REQUEST_TIME (UDP_RT0 * UDP_Rm)
22#define TURN_CHANNEL_BINDING_REFRESH_SECONDS 240
24#define SOFTWARE_STRING "reTURN Sync Client 0.3 - RFC5389/turn-12"
26#ifdef BOOST_ASIO_HAS_STD_CHRONO
27using namespace std::chrono;
30using namespace std::chrono;
42 mLocalBinding(
StunTuple::None , address, port),
44 mHaveAllocation(false),
45 mActiveDestination(0),
46 mReadTimer(mIOService),
57 char* password,
unsigned int passwordSize)
59 asio::error_code errorCode;
75 StunMessage* response = sendRequestAndGetResponse(request, errorCode,
false);
92 WarningLog(<<
"Stun response message for SharedSecretRequest is missing username and/or password!");
100 WarningLog( <<
"Stun response message for SharedSecretRequest contains data that is too large to return!");
136 const uint32_t remainder = unpaddedSize % 4,
137 paddedSize = remainder ? unpaddedSize + 4 - remainder : unpaddedSize;
147 asio::error_code errorCode;
160 StunMessage* response = sendRequestAndGetResponse(request, errorCode);
188 unsigned int bandwidth,
189 unsigned char requestedProps,
193 asio::error_code errorCode;
259 StunMessage* response = sendRequestAndGetResponse(request, errorCode);
313 asio::error_code errorCode;
330 StunMessage* response = sendRequestAndGetResponse(request, errorCode);
411 asio::error_code errorCode;
421 return connect(address.to_string(), port);
450TurnSocket::channelBind(
RemotePeer& remotePeer)
452 asio::error_code ret;
464 StunMessage* response = sendRequestAndGetResponse(request, ret);
488 asio::error_code errorCode;
520TurnSocket::sendTo(
const asio::ip::address& address,
unsigned short port,
const char* buffer,
unsigned int size)
538 return sendTo(remotePeer, buffer, size);
542 return sendTo(*remotePeer, buffer, size);
552 asio::error_code ret = checkIfAllocationRefreshRequired();
559 ret = checkIfChannelBindingRefreshRequired();
569 unsigned short channelNumber = remotePeer.
getChannel();
570 channelNumber = htons(channelNumber);
571 memcpy(&framing[0], &channelNumber, 2);
574 turnDataSize = htons(turnDataSize);
575 memcpy((
void*)&framing[2], &turnDataSize, 2);
577 std::vector<asio::const_buffer> bufs;
578 bufs.push_back(asio::buffer(framing,
sizeof(framing)));
579 bufs.push_back(asio::buffer(buffer, size));
583 static const char zeros[3] = { 0, 0, 0 };
595 ind.mCntTurnXorPeerAddress = 1;
600 memcpy(&ind.mTurnXorPeerAddress[0].addr.ipv6, remotePeer.
getPeerTuple().
getAddress().to_v6().to_bytes().data(),
sizeof(ind.mTurnXorPeerAddress[0].addr.ipv6));
609 ind.setTurnData(buffer, size);
623 WarningLog(<<
"TurnSocket: " <<
mReceivedWhileWaiting.size() <<
" packets received while waiting for a response, not yet received - dropping the oldest");
630TurnSocket::receive(
char* buffer,
unsigned int& size,
unsigned int timeout, asio::ip::address* sourceAddress,
unsigned short* sourcePort)
632 asio::error_code errorCode;
644 unsigned int readSize;
657 errorCode =
rawRead(timeout, &readSize, sourceAddress, sourcePort);
667 return handleRawData(
mReadBuffer, readSize, readSize, buffer, size);
675 const unsigned char firstByte = (
unsigned char)
mReadBuffer[0];
682 DebugLog(<<
"TurnSocket::receive: discarding a packet that isn't valid STUN");
687 unsigned int tempsize = size;
688 errorCode = handleStunMessage(*stunMsg, buffer, tempsize, sourceAddress, sourcePort);
689 if(!errorCode && tempsize == 0)
700 else if((firstByte & 0xC0) != 0x40)
702 DebugLog(<<
"TurnSocket::receive: discarding a packet that is neither STUN nor channel data");
707 unsigned short channelNumber;
709 channelNumber = ntohs(channelNumber);
716 dataLen = ntohs(dataLen);
726 errorCode = handleRawData(&
mReadBuffer[4], readSize-4, dataLen, buffer, size);
747TurnSocket::receiveFrom(
const asio::ip::address& address,
unsigned short port,
char* buffer,
unsigned int& size,
unsigned int timeout)
749 asio::ip::address sourceAddress;
750 unsigned short sourcePort;
752 asio::error_code errorCode;
758 errorCode =
receive(buffer, size, timeout, &sourceAddress, &sourcePort);
761 if(sourceAddress != address || sourcePort != port)
763 WarningLog(<<
"Recevied message but not from requested address/port - Discarding.");
772TurnSocket::handleRawData(
char* data,
unsigned int dataSize,
unsigned int expectedSize,
char* buffer,
unsigned int& bufferSize)
774 asio::error_code errorCode;
776 if(dataSize != expectedSize)
779 WarningLog(<<
"Did not read entire message: read=" << dataSize <<
" wanted=" << expectedSize);
783 if(dataSize > bufferSize)
786 WarningLog(<<
"Passed in buffer not large enough.");
791 memcpy(buffer, data, dataSize);
792 bufferSize = dataSize;
798TurnSocket::handleStunMessage(
StunMessage& stunMessage,
char* buffer,
unsigned int& size, asio::ip::address* sourceAddress,
unsigned short* sourcePort)
800 asio::error_code errorCode;
801 if(stunMessage.isValid())
805 if(stunMessage.mUnknownRequiredAttributes.numAttributes > 0)
808 WarningLog(<<
"DataInd with unknown comprehension required attributes.");
812 if(stunMessage.mCntTurnXorPeerAddress == 0 || !stunMessage.mHasTurnData)
819 StunTuple remoteTuple;
826 if(stunMessage.mTurnData->size() > size)
829 WarningLog(<<
"Passed in buffer not large enough.");
833 memcpy(buffer, stunMessage.mTurnData->data(), stunMessage.mTurnData->size());
834 size = (
unsigned int)stunMessage.mTurnData->size();
836 if(sourceAddress != 0)
838 *sourceAddress = remoteTuple.getAddress();
842 *sourcePort = remoteTuple.getPort();
854 response.mHeader.magicCookieAndTid = stunMessage.mHeader.magicCookieAndTid;
856 if(stunMessage.mUnknownRequiredAttributes.numAttributes > 0)
859 WarningLog(<<
"BindRequest with unknown comprehension required attributes.");
864 response.mHasUnknownAttributes =
true;
865 response.mUnknownAttributes = stunMessage.mUnknownRequiredAttributes;
872 response.mHasXorMappedAddress =
true;
883 unsigned int bufferSize = 512;
885 unsigned int writeSize = response.stunEncodeMessage((
char*)buffer.data(), bufferSize);
887 errorCode =
rawWrite(buffer.data(), writeSize);
918 mReadTimer.expires_after(milliseconds(timeout));
941TurnSocket::checkIfAllocationRefreshRequired()
948 return asio::error_code();
952TurnSocket::checkIfChannelBindingRefreshRequired()
954 asio::error_code ret;
957 time_t now = time(0);
961 if(it->second != 0 && now >= it->second)
969 ret = channelBind(*remotePeer);
978TurnSocket::sendRequestAndGetResponse(
StunMessage& request, asio::error_code& errorCode,
bool addAuthInfo)
980 bool sendRequest =
true;
983 unsigned int totalTime = 0;
984 unsigned int requestsSent = 0;
985 unsigned int readsize = 0;
995 request.mHasMessageIntegrity =
true;
1015 if(requestsSent > 0)
1017 DebugLog(<<
"TurnSocket: retranmitting request...");
1025 sendRequest =
false;
1029 errorCode =
rawRead(timeout, &readsize);
1032 if(errorCode == asio::error::operation_aborted)
1034 totalTime += timeout;
1037 InfoLog(<<
"Timed out waiting for Stun response!");
1049 timeout = (timeout*2);
1061 const unsigned char firstByte = (
unsigned char)
mReadBuffer[0];
1064 DebugLog(<<
"TurnSocket: discarding a packet that is neither STUN nor channel data, while waiting for a response");
1072 if(response->isValid() && response->mUnknownRequiredAttributes.numAttributes == 0)
1086 if(!response->checkMessageIntegrity(request.mHmacKey))
1088 WarningLog(<<
"Stun response message integrity is bad!");
1095 if(!(response->mHeader.magicCookieAndTid == request.mHeader.magicCookieAndTid))
1097 InfoLog(<<
"Stun response TID does not match request - discarding!");
1105 if(response->mHasRealm &&
1106 response->mHasNonce &&
1107 response->mHasErrorCode &&
1108 response->mErrorCode.errorClass == 4 &&
1110 response->mErrorCode.number == 38))
1112 mNonce = *response->mNonce;
1113 mRealm = *response->mRealm;
1117 request.createHeader(request.mClass, request.mMethod);
1119 return sendRequestAndGetResponse(request, errorCode,
true);
1122 errorCode = asio::error_code(
reTurn::Success, asio::error::misc_category);
1127 WarningLog(<<
"Stun response message is invalid!");
#define WarningLog(args_)
#define resip_assert(x)
This file needs to work for both C and C++ code.
#define TURN_CHANNEL_BINDING_REFRESH_SECONDS
#define UDP_FINAL_REQUEST_TIME
#define TCP_RESPONSE_TIME
#define UDP_MAX_RETRANSMITS
static size_t channelDataPadding(size_t length)
Over TCP and TLS, a TURN ChannelData message is padded to a multiple of 4 bytes, the padding not coun...
RemotePeer * findRemotePeerByChannel(unsigned short channelNumber)
RemotePeer * findRemotePeerByPeerAddress(const StunTuple &peerAddress)
RemotePeer * createChannelBinding(const StunTuple &peerTuple)
unsigned short getChannel() const
void setChannelConfirmed()
const StunTuple & getPeerTuple() const
bool isChannelConfirmed() const
bool mHasTurnChannelNumber
static const uint8_t IPv4Family
define stun address families
static const uint16_t StunClassSuccessResponse
static const uint16_t SharedSecretMethod
static const uint16_t BindMethod
bool mHasTurnRequestedTransport
StunAtrAddress mMappedAddress
static const uint8_t PropsNone
void createHeader(uint16_t stunclass, uint16_t method)
static const uint16_t TurnSendMethod
uint64_t mTurnReservationToken
bool mHasTurnXorRelayedAddress
uint8_t mTurnRequestedTransport
static const uint16_t StunClassErrorResponse
uint16_t mTurnChannelNumber
static const uint16_t StunClassRequest
StunAtrAddress mTurnXorPeerAddress[TURN_MAX_XOR_PEER_ADDR]
static const uint16_t TurnAllocateMethod
StunAtrAddress mXorMappedAddress
static const uint32_t RequestedTransportTcp
static const uint16_t TurnDataMethod
static void setStunAtrAddressFromTuple(StunAtrAddress &address, const StunTuple &tuple)
static const uint8_t IPv6Family
int mCntTurnXorPeerAddress
bool mHasTurnReservationToken
static const uint16_t TurnRefreshMethod
static const uint32_t RequestedTransportUdp
StunAtrAddress mTurnXorRelayedAddress
static const uint16_t TurnChannelBindMethod
TurnAtrEvenPort mTurnEvenPort
static const uint16_t StunClassIndication
bool mHasXorMappedAddress
static void setTupleFromStunAtrAddress(StunTuple &tuple, const StunAtrAddress &address)
TransportType getTransportType() const
const asio::ip::address & getAddress() const
unsigned int getPort() const
void setTransportType(TransportType transport)
void setSoftware(const char *software)
asio::error_code destroyAllocation()
virtual void cancelSocket()=0
void handleRawRead(const asio::error_code &errorCode, size_t bytesRead)
StunTuple & getReflexiveTuple()
StunTuple mReflexiveTuple
asio::steady_timer mReadTimer
asio::error_code receive(char *buffer, unsigned int &size, unsigned int timeout, asio::ip::address *sourceAddress=0, unsigned short *sourcePort=0)
static unsigned int UnspecifiedBandwidth
ChannelManager mChannelManager
static asio::ip::address UnspecifiedIpAddress
asio::error_code sendTo(const asio::ip::address &address, unsigned short port, const char *buffer, unsigned int size)
TurnSocket(const asio::ip::address &address=UnspecifiedIpAddress, unsigned short port=0)
virtual asio::error_code rawWrite(const char *buffer, unsigned int size)=0
virtual asio::error_code connect(const std::string &address, unsigned short port)=0
asio::error_code receiveFrom(const asio::ip::address &address, unsigned short port, char *buffer, unsigned int &size, unsigned int timeout)
asio::error_code mReadErrorCode
asio::error_code clearActiveDestination()
time_t mAllocationRefreshTime
ChannelBindingRefreshTimeMap mChannelBindingRefreshTimes
asio::error_code bindRequest()
unsigned int getLifetime()
asio::error_code requestSharedSecret(char *username, unsigned int usernameSize, char *password, unsigned int passwordSize)
unsigned char mRequestedProps
RemotePeer * mActiveDestination
void startReadTimer(unsigned int timeout)
void setUsernameAndPassword(const char *username, const char *password, bool shortTermAuth=false)
asio::error_code refreshAllocation()
virtual asio::error_code rawRead(unsigned int timeout, unsigned int *bytesRead, asio::ip::address *sourceAddress=0, unsigned short *sourcePort=0)=0
uint64_t mReservationToken
asio::error_code setActiveDestination(const asio::ip::address &address, unsigned short port)
static unsigned short UnspecifiedToken
unsigned int mRequestedLifetime
static const size_t MaxReceivedWhileWaiting
static unsigned int UnspecifiedLifetime
asio::error_code createAllocation(unsigned int lifetime=UnspecifiedLifetime, unsigned int bandwidth=UnspecifiedBandwidth, unsigned char requestedProps=StunMessage::PropsNone, uint64_t reservationToken=UnspecifiedToken, StunTuple::TransportType requestedTransportType=StunTuple::None)
StunTuple & getRelayTuple()
StunTuple mConnectedTuple
asio::error_code send(const char *buffer, unsigned int size)
unsigned int mRequestedBandwidth
unsigned int getBandwidth()
void handleRawReadTimeout(const asio::error_code &errorCode)
std::deque< std::vector< char > > mReceivedWhileWaiting
StunTuple::TransportType mRequestedTransportType
void queueReceived(unsigned int size)
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
const char * c_str() const
Returns a null-terminated string representing.
static const PreallocateType Preallocate
used only to disambiguate constructors
Data & append(const char *str, size_type len)
Appends the specified number of bytes to the end of this Data.
bool empty() const noexcept
Checks whether the Data is empty.
size_type size() const noexcept
Returns the number of bytes in this Data.
static const ErrorType MissingAuthenticationAttributes
static const ErrorType ErrorParsingMessage
static const ErrorType NotConnected
static const ErrorType InvalidChannelNumberReceived
static const ErrorType Success
static const ErrorType BadMessageIntegrity
static const ErrorType MissingAttributes
static const ErrorType ResponseTimeout
static const ErrorType BufferTooSmall
static const ErrorType NoActiveDestination
static const ErrorType ReadError
static const ErrorType NoAllocation
static const ErrorType AlreadyAllocated
static const ErrorType UnknownRequiredAttributes
static const ErrorType FrameError
static const ErrorType InvalidRequestedTransport
dcm! – add UnusedChecking(_enum) below;
std::unique_lock< RecursiveMutex > RecursiveLock
unsigned __int64 uint64_t