| Index: net/third_party/udt/src/core.cpp
|
| ===================================================================
|
| --- net/third_party/udt/src/core.cpp (revision 78992)
|
| +++ net/third_party/udt/src/core.cpp (working copy)
|
| @@ -1,2612 +0,0 @@
|
| -/*****************************************************************************
|
| -Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois.
|
| -All rights reserved.
|
| -
|
| -Redistribution and use in source and binary forms, with or without
|
| -modification, are permitted provided that the following conditions are
|
| -met:
|
| -
|
| -* Redistributions of source code must retain the above
|
| - copyright notice, this list of conditions and the
|
| - following disclaimer.
|
| -
|
| -* Redistributions in binary form must reproduce the
|
| - above copyright notice, this list of conditions
|
| - and the following disclaimer in the documentation
|
| - and/or other materials provided with the distribution.
|
| -
|
| -* Neither the name of the University of Illinois
|
| - nor the names of its contributors may be used to
|
| - endorse or promote products derived from this
|
| - software without specific prior written permission.
|
| -
|
| -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
| -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
| -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
| -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
| -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
| -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
| -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
| -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
| -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
| -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
| -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| -*****************************************************************************/
|
| -
|
| -/*****************************************************************************
|
| -written by
|
| - Yunhong Gu, last updated 01/22/2011
|
| -*****************************************************************************/
|
| -
|
| -#ifndef WIN32
|
| - #include <unistd.h>
|
| - #include <netdb.h>
|
| - #include <arpa/inet.h>
|
| - #include <cerrno>
|
| - #include <cstring>
|
| - #include <cstdlib>
|
| -#else
|
| - #include <winsock2.h>
|
| - #include <ws2tcpip.h>
|
| - #ifdef LEGACY_WIN32
|
| - #include <wspiapi.h>
|
| - #endif
|
| -#endif
|
| -#include <cmath>
|
| -#include "queue.h"
|
| -#include "core.h"
|
| -
|
| -using namespace std;
|
| -
|
| -
|
| -CUDTUnited CUDT::s_UDTUnited;
|
| -
|
| -const UDTSOCKET CUDT::INVALID_SOCK = -1;
|
| -const int CUDT::ERROR = -1;
|
| -
|
| -const UDTSOCKET UDT::INVALID_SOCK = CUDT::INVALID_SOCK;
|
| -const int UDT::ERROR = CUDT::ERROR;
|
| -
|
| -const int32_t CSeqNo::m_iSeqNoTH = 0x3FFFFFFF;
|
| -const int32_t CSeqNo::m_iMaxSeqNo = 0x7FFFFFFF;
|
| -const int32_t CAckNo::m_iMaxAckSeqNo = 0x7FFFFFFF;
|
| -const int32_t CMsgNo::m_iMsgNoTH = 0xFFFFFFF;
|
| -const int32_t CMsgNo::m_iMaxMsgNo = 0x1FFFFFFF;
|
| -
|
| -const int CUDT::m_iVersion = 4;
|
| -const int CUDT::m_iSYNInterval = 10000;
|
| -const int CUDT::m_iSelfClockInterval = 64;
|
| -
|
| -
|
| -CUDT::CUDT()
|
| -{
|
| - m_pSndBuffer = NULL;
|
| - m_pRcvBuffer = NULL;
|
| - m_pSndLossList = NULL;
|
| - m_pRcvLossList = NULL;
|
| - m_pACKWindow = NULL;
|
| - m_pSndTimeWindow = NULL;
|
| - m_pRcvTimeWindow = NULL;
|
| -
|
| - m_pSndQueue = NULL;
|
| - m_pRcvQueue = NULL;
|
| - m_pPeerAddr = NULL;
|
| - m_pSNode = NULL;
|
| - m_pRNode = NULL;
|
| -
|
| - // Initilize mutex and condition variables
|
| - initSynch();
|
| -
|
| - // Default UDT configurations
|
| - m_iMSS = 1500;
|
| - m_bSynSending = true;
|
| - m_bSynRecving = true;
|
| - m_iFlightFlagSize = 25600;
|
| - m_iSndBufSize = 8192;
|
| - m_iRcvBufSize = 8192; //Rcv buffer MUST NOT be bigger than Flight Flag size
|
| - m_Linger.l_onoff = 1;
|
| - m_Linger.l_linger = 180;
|
| - m_iUDPSndBufSize = 65536;
|
| - m_iUDPRcvBufSize = m_iRcvBufSize * m_iMSS;
|
| - m_iSockType = UDT_STREAM;
|
| - m_iIPversion = AF_INET;
|
| - m_bRendezvous = false;
|
| - m_iSndTimeOut = -1;
|
| - m_iRcvTimeOut = -1;
|
| - m_bReuseAddr = true;
|
| - m_llMaxBW = -1;
|
| -
|
| - m_pCCFactory = new CCCFactory<CUDTCC>;
|
| - m_pCC = NULL;
|
| - m_pCache = NULL;
|
| -
|
| - // Initial status
|
| - m_bOpened = false;
|
| - m_bListening = false;
|
| - m_bConnected = false;
|
| - m_bClosing = false;
|
| - m_bShutdown = false;
|
| - m_bBroken = false;
|
| - m_bPeerHealth = true;
|
| - m_ullLingerExpiration = 0;
|
| -}
|
| -
|
| -CUDT::CUDT(const CUDT& ancestor)
|
| -{
|
| - m_pSndBuffer = NULL;
|
| - m_pRcvBuffer = NULL;
|
| - m_pSndLossList = NULL;
|
| - m_pRcvLossList = NULL;
|
| - m_pACKWindow = NULL;
|
| - m_pSndTimeWindow = NULL;
|
| - m_pRcvTimeWindow = NULL;
|
| -
|
| - m_pSndQueue = NULL;
|
| - m_pRcvQueue = NULL;
|
| - m_pPeerAddr = NULL;
|
| - m_pSNode = NULL;
|
| - m_pRNode = NULL;
|
| -
|
| - // Initilize mutex and condition variables
|
| - initSynch();
|
| -
|
| - // Default UDT configurations
|
| - m_iMSS = ancestor.m_iMSS;
|
| - m_bSynSending = ancestor.m_bSynSending;
|
| - m_bSynRecving = ancestor.m_bSynRecving;
|
| - m_iFlightFlagSize = ancestor.m_iFlightFlagSize;
|
| - m_iSndBufSize = ancestor.m_iSndBufSize;
|
| - m_iRcvBufSize = ancestor.m_iRcvBufSize;
|
| - m_Linger = ancestor.m_Linger;
|
| - m_iUDPSndBufSize = ancestor.m_iUDPSndBufSize;
|
| - m_iUDPRcvBufSize = ancestor.m_iUDPRcvBufSize;
|
| - m_iSockType = ancestor.m_iSockType;
|
| - m_iIPversion = ancestor.m_iIPversion;
|
| - m_bRendezvous = ancestor.m_bRendezvous;
|
| - m_iSndTimeOut = ancestor.m_iSndTimeOut;
|
| - m_iRcvTimeOut = ancestor.m_iRcvTimeOut;
|
| - m_bReuseAddr = true; // this must be true, because all accepted sockets shared the same port with the listener
|
| - m_llMaxBW = ancestor.m_llMaxBW;
|
| -
|
| - m_pCCFactory = ancestor.m_pCCFactory->clone();
|
| - m_pCC = NULL;
|
| - m_pCache = ancestor.m_pCache;
|
| -
|
| - // Initial status
|
| - m_bOpened = false;
|
| - m_bListening = false;
|
| - m_bConnected = false;
|
| - m_bClosing = false;
|
| - m_bShutdown = false;
|
| - m_bBroken = false;
|
| - m_bPeerHealth = true;
|
| - m_ullLingerExpiration = 0;
|
| -}
|
| -
|
| -CUDT::~CUDT()
|
| -{
|
| - // release mutex/condtion variables
|
| - destroySynch();
|
| -
|
| - // destroy the data structures
|
| - delete m_pSndBuffer;
|
| - delete m_pRcvBuffer;
|
| - delete m_pSndLossList;
|
| - delete m_pRcvLossList;
|
| - delete m_pACKWindow;
|
| - delete m_pSndTimeWindow;
|
| - delete m_pRcvTimeWindow;
|
| - delete m_pCCFactory;
|
| - delete m_pCC;
|
| - delete m_pPeerAddr;
|
| - delete m_pSNode;
|
| - delete m_pRNode;
|
| -}
|
| -
|
| -void CUDT::setOpt(UDTOpt optName, const void* optval, const int&)
|
| -{
|
| - if (m_bBroken || m_bClosing)
|
| - throw CUDTException(2, 1, 0);
|
| -
|
| - CGuard cg(m_ConnectionLock);
|
| - CGuard sendguard(m_SendLock);
|
| - CGuard recvguard(m_RecvLock);
|
| -
|
| - switch (optName)
|
| - {
|
| - case UDT_MSS:
|
| - if (m_bOpened)
|
| - throw CUDTException(5, 1, 0);
|
| -
|
| - if (*(int*)optval < int(28 + CHandShake::m_iContentSize))
|
| - throw CUDTException(5, 3, 0);
|
| -
|
| - m_iMSS = *(int*)optval;
|
| -
|
| - // Packet size cannot be greater than UDP buffer size
|
| - if (m_iMSS > m_iUDPSndBufSize)
|
| - m_iMSS = m_iUDPSndBufSize;
|
| - if (m_iMSS > m_iUDPRcvBufSize)
|
| - m_iMSS = m_iUDPRcvBufSize;
|
| -
|
| - break;
|
| -
|
| - case UDT_SNDSYN:
|
| - m_bSynSending = *(bool *)optval;
|
| - break;
|
| -
|
| - case UDT_RCVSYN:
|
| - m_bSynRecving = *(bool *)optval;
|
| - break;
|
| -
|
| - case UDT_CC:
|
| - if (m_bConnected)
|
| - throw CUDTException(5, 1, 0);
|
| - if (NULL != m_pCCFactory)
|
| - delete m_pCCFactory;
|
| - m_pCCFactory = ((CCCVirtualFactory *)optval)->clone();
|
| -
|
| - break;
|
| -
|
| - case UDT_FC:
|
| - if (m_bConnected)
|
| - throw CUDTException(5, 2, 0);
|
| -
|
| - if (*(int*)optval < 1)
|
| - throw CUDTException(5, 3);
|
| -
|
| - // Mimimum recv flight flag size is 32 packets
|
| - if (*(int*)optval > 32)
|
| - m_iFlightFlagSize = *(int*)optval;
|
| - else
|
| - m_iFlightFlagSize = 32;
|
| -
|
| - break;
|
| -
|
| - case UDT_SNDBUF:
|
| - if (m_bOpened)
|
| - throw CUDTException(5, 1, 0);
|
| -
|
| - if (*(int*)optval <= 0)
|
| - throw CUDTException(5, 3, 0);
|
| -
|
| - m_iSndBufSize = *(int*)optval / (m_iMSS - 28);
|
| -
|
| - break;
|
| -
|
| - case UDT_RCVBUF:
|
| - if (m_bOpened)
|
| - throw CUDTException(5, 1, 0);
|
| -
|
| - if (*(int*)optval <= 0)
|
| - throw CUDTException(5, 3, 0);
|
| -
|
| - // Mimimum recv buffer size is 32 packets
|
| - if (*(int*)optval > (m_iMSS - 28) * 32)
|
| - m_iRcvBufSize = *(int*)optval / (m_iMSS - 28);
|
| - else
|
| - m_iRcvBufSize = 32;
|
| -
|
| - // recv buffer MUST not be greater than FC size
|
| - if (m_iRcvBufSize > m_iFlightFlagSize)
|
| - m_iRcvBufSize = m_iFlightFlagSize;
|
| -
|
| - break;
|
| -
|
| - case UDT_LINGER:
|
| - m_Linger = *(linger*)optval;
|
| - break;
|
| -
|
| - case UDP_SNDBUF:
|
| - if (m_bOpened)
|
| - throw CUDTException(5, 1, 0);
|
| -
|
| - m_iUDPSndBufSize = *(int*)optval;
|
| -
|
| - if (m_iUDPSndBufSize < m_iMSS)
|
| - m_iUDPSndBufSize = m_iMSS;
|
| -
|
| - break;
|
| -
|
| - case UDP_RCVBUF:
|
| - if (m_bOpened)
|
| - throw CUDTException(5, 1, 0);
|
| -
|
| - m_iUDPRcvBufSize = *(int*)optval;
|
| -
|
| - if (m_iUDPRcvBufSize < m_iMSS)
|
| - m_iUDPRcvBufSize = m_iMSS;
|
| -
|
| - break;
|
| -
|
| - case UDT_RENDEZVOUS:
|
| - if (m_bConnected)
|
| - throw CUDTException(5, 1, 0);
|
| - m_bRendezvous = *(bool *)optval;
|
| - break;
|
| -
|
| - case UDT_SNDTIMEO:
|
| - m_iSndTimeOut = *(int*)optval;
|
| - break;
|
| -
|
| - case UDT_RCVTIMEO:
|
| - m_iRcvTimeOut = *(int*)optval;
|
| - break;
|
| -
|
| - case UDT_REUSEADDR:
|
| - if (m_bOpened)
|
| - throw CUDTException(5, 1, 0);
|
| - m_bReuseAddr = *(bool*)optval;
|
| - break;
|
| -
|
| - case UDT_MAXBW:
|
| - if (m_bConnected)
|
| - throw CUDTException(5, 1, 0);
|
| - m_llMaxBW = *(int64_t*)optval;
|
| - break;
|
| -
|
| - default:
|
| - throw CUDTException(5, 0, 0);
|
| - }
|
| -}
|
| -
|
| -void CUDT::getOpt(UDTOpt optName, void* optval, int& optlen)
|
| -{
|
| - CGuard cg(m_ConnectionLock);
|
| -
|
| - switch (optName)
|
| - {
|
| - case UDT_MSS:
|
| - *(int*)optval = m_iMSS;
|
| - optlen = sizeof(int);
|
| - break;
|
| -
|
| - case UDT_SNDSYN:
|
| - *(bool*)optval = m_bSynSending;
|
| - optlen = sizeof(bool);
|
| - break;
|
| -
|
| - case UDT_RCVSYN:
|
| - *(bool*)optval = m_bSynRecving;
|
| - optlen = sizeof(bool);
|
| - break;
|
| -
|
| - case UDT_CC:
|
| - if (!m_bOpened)
|
| - throw CUDTException(5, 5, 0);
|
| - *(CCC**)optval = m_pCC;
|
| - optlen = sizeof(CCC*);
|
| -
|
| - break;
|
| -
|
| - case UDT_FC:
|
| - *(int*)optval = m_iFlightFlagSize;
|
| - optlen = sizeof(int);
|
| - break;
|
| -
|
| - case UDT_SNDBUF:
|
| - *(int*)optval = m_iSndBufSize * (m_iMSS - 28);
|
| - optlen = sizeof(int);
|
| - break;
|
| -
|
| - case UDT_RCVBUF:
|
| - *(int*)optval = m_iRcvBufSize * (m_iMSS - 28);
|
| - optlen = sizeof(int);
|
| - break;
|
| -
|
| - case UDT_LINGER:
|
| - if (optlen < (int)(sizeof(linger)))
|
| - throw CUDTException(5, 3, 0);
|
| -
|
| - *(linger*)optval = m_Linger;
|
| - optlen = sizeof(linger);
|
| - break;
|
| -
|
| - case UDP_SNDBUF:
|
| - *(int*)optval = m_iUDPSndBufSize;
|
| - optlen = sizeof(int);
|
| - break;
|
| -
|
| - case UDP_RCVBUF:
|
| - *(int*)optval = m_iUDPRcvBufSize;
|
| - optlen = sizeof(int);
|
| - break;
|
| -
|
| - case UDT_RENDEZVOUS:
|
| - *(bool *)optval = m_bRendezvous;
|
| - optlen = sizeof(bool);
|
| - break;
|
| -
|
| - case UDT_SNDTIMEO:
|
| - *(int*)optval = m_iSndTimeOut;
|
| - optlen = sizeof(int);
|
| - break;
|
| -
|
| - case UDT_RCVTIMEO:
|
| - *(int*)optval = m_iRcvTimeOut;
|
| - optlen = sizeof(int);
|
| - break;
|
| -
|
| - case UDT_REUSEADDR:
|
| - *(bool *)optval = m_bReuseAddr;
|
| - optlen = sizeof(bool);
|
| - break;
|
| -
|
| - case UDT_MAXBW:
|
| - *(int64_t*)optval = m_llMaxBW;
|
| - break;
|
| -
|
| - default:
|
| - throw CUDTException(5, 0, 0);
|
| - }
|
| -}
|
| -
|
| -void CUDT::open()
|
| -{
|
| - CGuard cg(m_ConnectionLock);
|
| -
|
| - // Initial sequence number, loss, acknowledgement, etc.
|
| - m_iPktSize = m_iMSS - 28;
|
| - m_iPayloadSize = m_iPktSize - CPacket::m_iPktHdrSize;
|
| -
|
| - m_iEXPCount = 1;
|
| - m_iBandwidth = 1;
|
| - m_iDeliveryRate = 16;
|
| - m_iAckSeqNo = 0;
|
| - m_ullLastAckTime = 0;
|
| -
|
| - // trace information
|
| - m_StartTime = CTimer::getTime();
|
| - m_llSentTotal = m_llRecvTotal = m_iSndLossTotal = m_iRcvLossTotal = m_iRetransTotal = m_iSentACKTotal = m_iRecvACKTotal = m_iSentNAKTotal = m_iRecvNAKTotal = 0;
|
| - m_LastSampleTime = CTimer::getTime();
|
| - m_llTraceSent = m_llTraceRecv = m_iTraceSndLoss = m_iTraceRcvLoss = m_iTraceRetrans = m_iSentACK = m_iRecvACK = m_iSentNAK = m_iRecvNAK = 0;
|
| - m_llSndDuration = m_llSndDurationTotal = 0;
|
| -
|
| - // structures for queue
|
| - if (NULL == m_pSNode)
|
| - m_pSNode = new CSNode;
|
| - m_pSNode->m_pUDT = this;
|
| - m_pSNode->m_llTimeStamp = 1;
|
| - m_pSNode->m_iHeapLoc = -1;
|
| -
|
| - if (NULL == m_pRNode)
|
| - m_pRNode = new CRNode;
|
| - m_pRNode->m_pUDT = this;
|
| - m_pRNode->m_llTimeStamp = 1;
|
| - m_pRNode->m_pPrev = m_pRNode->m_pNext = NULL;
|
| - m_pRNode->m_bOnList = false;
|
| -
|
| - m_iRTT = 10 * m_iSYNInterval;
|
| - m_iRTTVar = m_iRTT >> 1;
|
| - m_ullCPUFrequency = CTimer::getCPUFrequency();
|
| -
|
| - // set up the timers
|
| - m_ullSYNInt = m_iSYNInterval * m_ullCPUFrequency;
|
| -
|
| - // set minimum NAK and EXP timeout to 100ms
|
| - m_ullMinNakInt = 300000 * m_ullCPUFrequency;
|
| - m_ullMinExpInt = 300000 * m_ullCPUFrequency;
|
| -
|
| - m_ullACKInt = m_ullSYNInt;
|
| - m_ullNAKInt = m_ullMinNakInt;
|
| - m_ullEXPInt = m_ullMinExpInt;
|
| - m_llLastRspTime = CTimer::getTime();
|
| -
|
| - CTimer::rdtsc(m_ullNextACKTime);
|
| - m_ullNextACKTime += m_ullSYNInt;
|
| - CTimer::rdtsc(m_ullNextNAKTime);
|
| - m_ullNextNAKTime += m_ullNAKInt;
|
| - CTimer::rdtsc(m_ullNextEXPTime);
|
| - m_ullNextEXPTime += m_ullEXPInt;
|
| -
|
| - m_iPktCount = 0;
|
| - m_iLightACKCount = 1;
|
| -
|
| - m_ullTargetTime = 0;
|
| - m_ullTimeDiff = 0;
|
| -
|
| - // Now UDT is opened.
|
| - m_bOpened = true;
|
| -}
|
| -
|
| -void CUDT::listen()
|
| -{
|
| - CGuard cg(m_ConnectionLock);
|
| -
|
| - if (!m_bOpened)
|
| - throw CUDTException(5, 0, 0);
|
| -
|
| - if (m_bConnected)
|
| - throw CUDTException(5, 2, 0);
|
| -
|
| - // listen can be called more than once
|
| - if (m_bListening)
|
| - return;
|
| -
|
| - // if there is already another socket listening on the same port
|
| - if (m_pRcvQueue->setListener(this) < 0)
|
| - throw CUDTException(5, 11, 0);
|
| -
|
| - m_bListening = true;
|
| -}
|
| -
|
| -void CUDT::connect(const sockaddr* serv_addr)
|
| -{
|
| - CGuard cg(m_ConnectionLock);
|
| -
|
| - if (!m_bOpened)
|
| - throw CUDTException(5, 0, 0);
|
| -
|
| - if (m_bListening)
|
| - throw CUDTException(5, 2, 0);
|
| -
|
| - if (m_bConnected)
|
| - throw CUDTException(5, 2, 0);
|
| -
|
| - // register this socket in the rendezvous queue
|
| - // RendezevousQueue is used to temporarily store incoming handshake, non-rendezvous connections also require this function
|
| - m_pRcvQueue->m_pRendezvousQueue->insert(m_SocketID, m_iIPversion, serv_addr);
|
| -
|
| - CPacket request;
|
| - char* reqdata = new char [m_iPayloadSize];
|
| - CHandShake req;
|
| -
|
| - CPacket response;
|
| - char* resdata = new char [m_iPayloadSize];
|
| - CHandShake res;
|
| -
|
| - // This is my current configurations
|
| - req.m_iVersion = m_iVersion;
|
| - req.m_iType = m_iSockType;
|
| - req.m_iMSS = m_iMSS;
|
| - req.m_iFlightFlagSize = (m_iRcvBufSize < m_iFlightFlagSize)? m_iRcvBufSize : m_iFlightFlagSize;
|
| - req.m_iReqType = (!m_bRendezvous) ? 1 : 0;
|
| - req.m_iID = m_SocketID;
|
| - CIPAddress::ntop(serv_addr, req.m_piPeerIP, m_iIPversion);
|
| -
|
| - // Random Initial Sequence Number
|
| - srand((unsigned int)CTimer::getTime());
|
| - m_iISN = req.m_iISN = (int32_t)(CSeqNo::m_iMaxSeqNo * (double(rand()) / RAND_MAX));
|
| -
|
| - m_iLastDecSeq = req.m_iISN - 1;
|
| - m_iSndLastAck = req.m_iISN;
|
| - m_iSndLastDataAck = req.m_iISN;
|
| - m_iSndCurrSeqNo = req.m_iISN - 1;
|
| - m_iSndLastAck2 = req.m_iISN;
|
| - m_ullSndLastAck2Time = CTimer::getTime();
|
| -
|
| - // Inform the server my configurations.
|
| - request.pack(0, NULL, reqdata, m_iPayloadSize);
|
| - // ID = 0, connection request
|
| - request.m_iID = 0;
|
| -
|
| - // Wait for the negotiated configurations from the peer side.
|
| - response.pack(0, NULL, resdata, m_iPayloadSize);
|
| -
|
| - uint64_t timeo = 3000000;
|
| - if (m_bRendezvous)
|
| - timeo *= 10;
|
| - uint64_t entertime = CTimer::getTime();
|
| - uint64_t last_req_time = 0;
|
| -
|
| - CUDTException e(0, 0);
|
| - char* tmp = NULL;
|
| -
|
| - while (!m_bClosing)
|
| - {
|
| - // avoid sending too many requests, at most 1 request per 250ms
|
| - if (CTimer::getTime() - last_req_time > 250000)
|
| - {
|
| - req.serialize(reqdata, m_iPayloadSize);
|
| - request.setLength(CHandShake::m_iContentSize);
|
| - m_pSndQueue->sendto(serv_addr, request);
|
| -
|
| - last_req_time = CTimer::getTime();
|
| - }
|
| -
|
| - response.setLength(m_iPayloadSize);
|
| - if (m_pRcvQueue->recvfrom(m_SocketID, response) > 0)
|
| - {
|
| - if (m_bRendezvous && ((0 == response.getFlag()) || (1 == response.getType())) && (NULL != tmp))
|
| - {
|
| - // a data packet or a keep-alive packet comes, which means the peer side is already connected
|
| - // in this situation, a previously recorded response (tmp) will be used
|
| - res.deserialize(tmp, CHandShake::m_iContentSize);
|
| - memcpy(m_piSelfIP, res.m_piPeerIP, 16);
|
| - break;
|
| - }
|
| -
|
| - if ((1 != response.getFlag()) || (0 != response.getType()))
|
| - response.setLength(-1);
|
| - else
|
| - {
|
| - res.deserialize(response.m_pcData, response.getLength());
|
| -
|
| - if (m_bRendezvous)
|
| - {
|
| - // regular connect should NOT communicate with rendezvous connect
|
| - // rendezvous connect require 3-way handshake
|
| - if (1 == res.m_iReqType)
|
| - response.setLength(-1);
|
| - else if ((0 == res.m_iReqType) || (0 == req.m_iReqType))
|
| - {
|
| - if (NULL == tmp)
|
| - tmp = new char [m_iPayloadSize];
|
| - res.serialize(tmp, m_iPayloadSize);
|
| -
|
| - req.m_iReqType = -1;
|
| - request.m_iID = res.m_iID;
|
| - response.setLength(-1);
|
| - }
|
| - }
|
| - else
|
| - {
|
| - // set cookie
|
| - if (1 == res.m_iReqType)
|
| - {
|
| - req.m_iReqType = -1;
|
| - req.m_iCookie = res.m_iCookie;
|
| - response.setLength(-1);
|
| - }
|
| - }
|
| - }
|
| -
|
| - // new request/response should be sent out immediately on receving a response
|
| - last_req_time = 0;
|
| - }
|
| -
|
| - if (response.getLength() > 0)
|
| - {
|
| - memcpy(m_piSelfIP, res.m_piPeerIP, 16);
|
| - break;
|
| - }
|
| -
|
| - if (CTimer::getTime() > entertime + timeo)
|
| - {
|
| - // timeout
|
| - e = CUDTException(1, 1, 0);
|
| - break;
|
| - }
|
| - }
|
| -
|
| - delete [] tmp;
|
| - delete [] reqdata;
|
| - delete [] resdata;
|
| -
|
| - // remove from rendezvous queue
|
| - m_pRcvQueue->m_pRendezvousQueue->remove(m_SocketID);
|
| -
|
| - if (e.getErrorCode() == 0)
|
| - {
|
| - if (m_bClosing) // if the socket is closed before connection...
|
| - e = CUDTException(1);
|
| - else if (1002 == res.m_iReqType) // connection request rejected
|
| - e = CUDTException(1, 2, 0);
|
| - else if ((!m_bRendezvous) && (m_iISN != res.m_iISN)) // secuity check
|
| - e = CUDTException(1, 4, 0);
|
| - }
|
| -
|
| - if (e.getErrorCode() != 0)
|
| - {
|
| - throw e;
|
| - }
|
| -
|
| - // Got it. Re-configure according to the negotiated values.
|
| - m_iMSS = res.m_iMSS;
|
| - m_iFlowWindowSize = res.m_iFlightFlagSize;
|
| - m_iPktSize = m_iMSS - 28;
|
| - m_iPayloadSize = m_iPktSize - CPacket::m_iPktHdrSize;
|
| - m_iPeerISN = res.m_iISN;
|
| - m_iRcvLastAck = res.m_iISN;
|
| - m_iRcvLastAckAck = res.m_iISN;
|
| - m_iRcvCurrSeqNo = res.m_iISN - 1;
|
| - m_PeerID = res.m_iID;
|
| -
|
| - // Prepare all data structures
|
| - try
|
| - {
|
| - m_pSndBuffer = new CSndBuffer(32, m_iPayloadSize);
|
| - m_pRcvBuffer = new CRcvBuffer(&(m_pRcvQueue->m_UnitQueue), m_iRcvBufSize);
|
| - // after introducing lite ACK, the sndlosslist may not be cleared in time, so it requires twice space.
|
| - m_pSndLossList = new CSndLossList(m_iFlowWindowSize * 2);
|
| - m_pRcvLossList = new CRcvLossList(m_iFlightFlagSize);
|
| - m_pACKWindow = new CACKWindow(1024);
|
| - m_pRcvTimeWindow = new CPktTimeWindow(16, 64);
|
| - m_pSndTimeWindow = new CPktTimeWindow();
|
| - }
|
| - catch (...)
|
| - {
|
| - throw CUDTException(3, 2, 0);
|
| - }
|
| -
|
| - m_pCC = m_pCCFactory->create();
|
| - m_pCC->m_UDT = m_SocketID;
|
| - m_ullInterval = (uint64_t)(m_pCC->m_dPktSndPeriod * m_ullCPUFrequency);
|
| - m_dCongestionWindow = m_pCC->m_dCWndSize;
|
| -
|
| - CInfoBlock ib;
|
| - ib.m_iIPversion = m_iIPversion;
|
| - CInfoBlock::convert(serv_addr, m_iIPversion, ib.m_piIP);
|
| - if (m_pCache->lookup(&ib) >= 0)
|
| - {
|
| - m_iRTT = ib.m_iRTT;
|
| - m_iBandwidth = ib.m_iBandwidth;
|
| - }
|
| -
|
| - m_pCC->setMSS(m_iMSS);
|
| - m_pCC->setMaxCWndSize((int&)m_iFlowWindowSize);
|
| - m_pCC->setSndCurrSeqNo((int32_t&)m_iSndCurrSeqNo);
|
| - m_pCC->setRcvRate(m_iDeliveryRate);
|
| - m_pCC->setRTT(m_iRTT);
|
| - m_pCC->setBandwidth(m_iBandwidth);
|
| - if (m_llMaxBW > 0) m_pCC->setUserParam((char*)&(m_llMaxBW), 8);
|
| - m_pCC->init();
|
| -
|
| - m_pPeerAddr = (AF_INET == m_iIPversion) ? (sockaddr*)new sockaddr_in : (sockaddr*)new sockaddr_in6;
|
| - memcpy(m_pPeerAddr, serv_addr, (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6));
|
| -
|
| - // And, I am connected too.
|
| - m_bConnected = true;
|
| -
|
| - // register this socket for receiving data packets
|
| - m_pRNode->m_bOnList = true;
|
| - m_pRcvQueue->setNewEntry(this);
|
| -
|
| - // acknowledde any waiting epolls to read/write
|
| - s_UDTUnited.m_EPoll.enable_read(m_SocketID, m_sPollID);
|
| - s_UDTUnited.m_EPoll.enable_write(m_SocketID, m_sPollID);
|
| -}
|
| -
|
| -void CUDT::connect(const sockaddr* peer, CHandShake* hs)
|
| -{
|
| - CGuard cg(m_ConnectionLock);
|
| -
|
| - // Uses the smaller MSS between the peers
|
| - if (hs->m_iMSS > m_iMSS)
|
| - hs->m_iMSS = m_iMSS;
|
| - else
|
| - m_iMSS = hs->m_iMSS;
|
| -
|
| - // exchange info for maximum flow window size
|
| - m_iFlowWindowSize = hs->m_iFlightFlagSize;
|
| - hs->m_iFlightFlagSize = (m_iRcvBufSize < m_iFlightFlagSize)? m_iRcvBufSize : m_iFlightFlagSize;
|
| -
|
| - m_iPeerISN = hs->m_iISN;
|
| -
|
| - m_iRcvLastAck = hs->m_iISN;
|
| - m_iRcvLastAckAck = hs->m_iISN;
|
| - m_iRcvCurrSeqNo = hs->m_iISN - 1;
|
| -
|
| - m_PeerID = hs->m_iID;
|
| - hs->m_iID = m_SocketID;
|
| -
|
| - // use peer's ISN and send it back for security check
|
| - m_iISN = hs->m_iISN;
|
| -
|
| - m_iLastDecSeq = m_iISN - 1;
|
| - m_iSndLastAck = m_iISN;
|
| - m_iSndLastDataAck = m_iISN;
|
| - m_iSndCurrSeqNo = m_iISN - 1;
|
| - m_iSndLastAck2 = m_iISN;
|
| - m_ullSndLastAck2Time = CTimer::getTime();
|
| -
|
| - // this is a reponse handshake
|
| - hs->m_iReqType = -1;
|
| -
|
| - // get local IP address and send the peer its IP address (because UDP cannot get local IP address)
|
| - memcpy(m_piSelfIP, hs->m_piPeerIP, 16);
|
| - CIPAddress::ntop(peer, hs->m_piPeerIP, m_iIPversion);
|
| -
|
| - m_iPktSize = m_iMSS - 28;
|
| - m_iPayloadSize = m_iPktSize - CPacket::m_iPktHdrSize;
|
| -
|
| - // Prepare all structures
|
| - try
|
| - {
|
| - m_pSndBuffer = new CSndBuffer(32, m_iPayloadSize);
|
| - m_pRcvBuffer = new CRcvBuffer(&(m_pRcvQueue->m_UnitQueue), m_iRcvBufSize);
|
| - m_pSndLossList = new CSndLossList(m_iFlowWindowSize * 2);
|
| - m_pRcvLossList = new CRcvLossList(m_iFlightFlagSize);
|
| - m_pACKWindow = new CACKWindow(1024);
|
| - m_pRcvTimeWindow = new CPktTimeWindow(16, 64);
|
| - m_pSndTimeWindow = new CPktTimeWindow();
|
| - }
|
| - catch (...)
|
| - {
|
| - throw CUDTException(3, 2, 0);
|
| - }
|
| -
|
| - m_pCC = m_pCCFactory->create();
|
| - m_pCC->m_UDT = m_SocketID;
|
| - m_ullInterval = (uint64_t)(m_pCC->m_dPktSndPeriod * m_ullCPUFrequency);
|
| - m_dCongestionWindow = m_pCC->m_dCWndSize;
|
| -
|
| - CInfoBlock ib;
|
| - ib.m_iIPversion = m_iIPversion;
|
| - CInfoBlock::convert(peer, m_iIPversion, ib.m_piIP);
|
| - if (m_pCache->lookup(&ib) >= 0)
|
| - {
|
| - m_iRTT = ib.m_iRTT;
|
| - m_iBandwidth = ib.m_iBandwidth;
|
| - }
|
| -
|
| - m_pCC->setMSS(m_iMSS);
|
| - m_pCC->setMaxCWndSize((int&)m_iFlowWindowSize);
|
| - m_pCC->setSndCurrSeqNo((int32_t&)m_iSndCurrSeqNo);
|
| - m_pCC->setRcvRate(m_iDeliveryRate);
|
| - m_pCC->setRTT(m_iRTT);
|
| - m_pCC->setBandwidth(m_iBandwidth);
|
| - if (m_llMaxBW > 0) m_pCC->setUserParam((char*)&(m_llMaxBW), 8);
|
| - m_pCC->init();
|
| -
|
| - m_pPeerAddr = (AF_INET == m_iIPversion) ? (sockaddr*)new sockaddr_in : (sockaddr*)new sockaddr_in6;
|
| - memcpy(m_pPeerAddr, peer, (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6));
|
| -
|
| - // And of course, it is connected.
|
| - m_bConnected = true;
|
| -
|
| - // register this socket for receiving data packets
|
| - m_pRNode->m_bOnList = true;
|
| - m_pRcvQueue->setNewEntry(this);
|
| -
|
| - //send the response to the peer, see listen() for more discussions about this
|
| - CPacket response;
|
| - int size = CHandShake::m_iContentSize;
|
| - char* buffer = new char[size];
|
| - hs->serialize(buffer, size);
|
| - response.pack(0, NULL, buffer, size);
|
| - response.m_iID = m_PeerID;
|
| - m_pSndQueue->sendto(peer, response);
|
| - delete [] buffer;
|
| -}
|
| -
|
| -void CUDT::close()
|
| -{
|
| - if (!m_bOpened)
|
| - return;
|
| -
|
| - if (0 != m_Linger.l_onoff)
|
| - {
|
| - uint64_t entertime = CTimer::getTime();
|
| -
|
| - while (!m_bBroken && m_bConnected && (m_pSndBuffer->getCurrBufSize() > 0) && (CTimer::getTime() - entertime < m_Linger.l_linger * 1000000ULL))
|
| - {
|
| - // linger has been checked by previous close() call and has expired
|
| - if (m_ullLingerExpiration >= entertime)
|
| - break;
|
| -
|
| - if (!m_bSynSending)
|
| - {
|
| - // if this socket enables asynchronous sending, return immediately and let GC to close it later
|
| - if (0 == m_ullLingerExpiration)
|
| - m_ullLingerExpiration = entertime + m_Linger.l_linger * 1000000ULL;
|
| -
|
| - return;
|
| - }
|
| -
|
| - #ifndef WIN32
|
| - timespec ts;
|
| - ts.tv_sec = 0;
|
| - ts.tv_nsec = 1000000;
|
| - nanosleep(&ts, NULL);
|
| - #else
|
| - Sleep(1);
|
| - #endif
|
| - }
|
| - }
|
| -
|
| - // remove this socket from the snd queue
|
| - if (m_bConnected)
|
| - m_pSndQueue->m_pSndUList->remove(this);
|
| -
|
| - // remove itself from all epoll monitoring
|
| - for (set<int>::iterator i = m_sPollID.begin(); i != m_sPollID.end(); ++ i)
|
| - s_UDTUnited.m_EPoll.remove_usock(*i, m_SocketID);
|
| -
|
| - CGuard cg(m_ConnectionLock);
|
| -
|
| - if (!m_bOpened)
|
| - return;
|
| -
|
| - // Inform the threads handler to stop.
|
| - m_bClosing = true;
|
| -
|
| - // Signal the sender and recver if they are waiting for data.
|
| - releaseSynch();
|
| -
|
| - if (m_bListening)
|
| - {
|
| - m_bListening = false;
|
| - m_pRcvQueue->removeListener(this);
|
| - }
|
| - if (m_bConnected)
|
| - {
|
| - if (!m_bShutdown)
|
| - sendCtrl(5);
|
| -
|
| - m_pCC->close();
|
| -
|
| - CInfoBlock ib;
|
| - ib.m_iIPversion = m_iIPversion;
|
| - CInfoBlock::convert(m_pPeerAddr, m_iIPversion, ib.m_piIP);
|
| - ib.m_iRTT = m_iRTT;
|
| - ib.m_iBandwidth = m_iBandwidth;
|
| - m_pCache->update(&ib);
|
| -
|
| - m_bConnected = false;
|
| - }
|
| -
|
| - // waiting all send and recv calls to stop
|
| - CGuard sendguard(m_SendLock);
|
| - CGuard recvguard(m_RecvLock);
|
| -
|
| - // CLOSED.
|
| - m_bOpened = false;
|
| -}
|
| -
|
| -int CUDT::send(const char* data, const int& len)
|
| -{
|
| - if (UDT_DGRAM == m_iSockType)
|
| - throw CUDTException(5, 10, 0);
|
| -
|
| - // throw an exception if not connected
|
| - if (m_bBroken || m_bClosing)
|
| - throw CUDTException(2, 1, 0);
|
| - else if (!m_bConnected)
|
| - throw CUDTException(2, 2, 0);
|
| -
|
| - if (len <= 0)
|
| - return 0;
|
| -
|
| - CGuard sendguard(m_SendLock);
|
| -
|
| - if (m_pSndBuffer->getCurrBufSize() == 0)
|
| - {
|
| - // delay the EXP timer to avoid mis-fired timeout
|
| - uint64_t currtime;
|
| - CTimer::rdtsc(currtime);
|
| - m_ullNextEXPTime = currtime + m_ullEXPInt;
|
| - }
|
| -
|
| - if (m_iSndBufSize <= m_pSndBuffer->getCurrBufSize())
|
| - {
|
| - if (!m_bSynSending)
|
| - throw CUDTException(6, 1, 0);
|
| - else
|
| - {
|
| - // wait here during a blocking sending
|
| - #ifndef WIN32
|
| - pthread_mutex_lock(&m_SendBlockLock);
|
| - if (m_iSndTimeOut < 0)
|
| - {
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (m_iSndBufSize <= m_pSndBuffer->getCurrBufSize()) && m_bPeerHealth)
|
| - pthread_cond_wait(&m_SendBlockCond, &m_SendBlockLock);
|
| - }
|
| - else
|
| - {
|
| - uint64_t exptime = CTimer::getTime() + m_iSndTimeOut * 1000ULL;
|
| - timespec locktime;
|
| -
|
| - locktime.tv_sec = exptime / 1000000;
|
| - locktime.tv_nsec = (exptime % 1000000) * 1000;
|
| -
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (m_iSndBufSize <= m_pSndBuffer->getCurrBufSize()) && m_bPeerHealth && (CTimer::getTime() < exptime))
|
| - pthread_cond_timedwait(&m_SendBlockCond, &m_SendBlockLock, &locktime);
|
| - }
|
| - pthread_mutex_unlock(&m_SendBlockLock);
|
| - #else
|
| - if (m_iSndTimeOut < 0)
|
| - {
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (m_iSndBufSize <= m_pSndBuffer->getCurrBufSize()) && m_bPeerHealth)
|
| - WaitForSingleObject(m_SendBlockCond, INFINITE);
|
| - }
|
| - else
|
| - {
|
| - uint64_t exptime = CTimer::getTime() + m_iSndTimeOut * 1000ULL;
|
| -
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (m_iSndBufSize <= m_pSndBuffer->getCurrBufSize()) && m_bPeerHealth && (CTimer::getTime() < exptime))
|
| - WaitForSingleObject(m_SendBlockCond, DWORD((exptime - CTimer::getTime()) / 1000));
|
| - }
|
| - #endif
|
| -
|
| - // check the connection status
|
| - if (m_bBroken || m_bClosing)
|
| - throw CUDTException(2, 1, 0);
|
| - else if (!m_bConnected)
|
| - throw CUDTException(2, 2, 0);
|
| - else if (!m_bPeerHealth)
|
| - {
|
| - m_bPeerHealth = true;
|
| - throw CUDTException(7);
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (m_iSndBufSize <= m_pSndBuffer->getCurrBufSize())
|
| - {
|
| - if (m_iSndTimeOut >= 0)
|
| - throw CUDTException(6, 1, 0);
|
| -
|
| - return 0;
|
| - }
|
| -
|
| - int size = (m_iSndBufSize - m_pSndBuffer->getCurrBufSize()) * m_iPayloadSize;
|
| - if (size > len)
|
| - size = len;
|
| -
|
| - // record total time used for sending
|
| - if (0 == m_pSndBuffer->getCurrBufSize())
|
| - m_llSndDurationCounter = CTimer::getTime();
|
| -
|
| - // insert the user buffer into the sening list
|
| - m_pSndBuffer->addBuffer(data, size);
|
| -
|
| - // insert this socket to snd list if it is not on the list yet
|
| - m_pSndQueue->m_pSndUList->update(this, false);
|
| -
|
| - if (m_iSndBufSize <= m_pSndBuffer->getCurrBufSize())
|
| - {
|
| - // write is not available any more
|
| - s_UDTUnited.m_EPoll.disable_write(m_SocketID, m_sPollID);
|
| - }
|
| -
|
| - return size;
|
| -}
|
| -
|
| -int CUDT::recv(char* data, const int& len)
|
| -{
|
| - if (UDT_DGRAM == m_iSockType)
|
| - throw CUDTException(5, 10, 0);
|
| -
|
| - // throw an exception if not connected
|
| - if (!m_bConnected)
|
| - throw CUDTException(2, 2, 0);
|
| - else if ((m_bBroken || m_bClosing) && (0 == m_pRcvBuffer->getRcvDataSize()))
|
| - throw CUDTException(2, 1, 0);
|
| -
|
| - if (len <= 0)
|
| - return 0;
|
| -
|
| - CGuard recvguard(m_RecvLock);
|
| -
|
| - if (0 == m_pRcvBuffer->getRcvDataSize())
|
| - {
|
| - if (!m_bSynRecving)
|
| - throw CUDTException(6, 2, 0);
|
| - else
|
| - {
|
| - #ifndef WIN32
|
| - pthread_mutex_lock(&m_RecvDataLock);
|
| - if (m_iRcvTimeOut < 0)
|
| - {
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (0 == m_pRcvBuffer->getRcvDataSize()))
|
| - pthread_cond_wait(&m_RecvDataCond, &m_RecvDataLock);
|
| - }
|
| - else
|
| - {
|
| - uint64_t exptime = CTimer::getTime() + m_iRcvTimeOut * 1000ULL;
|
| - timespec locktime;
|
| -
|
| - locktime.tv_sec = exptime / 1000000;
|
| - locktime.tv_nsec = (exptime % 1000000) * 1000;
|
| -
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (0 == m_pRcvBuffer->getRcvDataSize()))
|
| - {
|
| - pthread_cond_timedwait(&m_RecvDataCond, &m_RecvDataLock, &locktime);
|
| - if (CTimer::getTime() >= exptime)
|
| - break;
|
| - }
|
| - }
|
| - pthread_mutex_unlock(&m_RecvDataLock);
|
| - #else
|
| - if (m_iRcvTimeOut < 0)
|
| - {
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (0 == m_pRcvBuffer->getRcvDataSize()))
|
| - WaitForSingleObject(m_RecvDataCond, INFINITE);
|
| - }
|
| - else
|
| - {
|
| - uint64_t enter_time = CTimer::getTime();
|
| -
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (0 == m_pRcvBuffer->getRcvDataSize()))
|
| - {
|
| - int diff = int(CTimer::getTime() - enter_time) / 1000;
|
| - if (diff >= m_iRcvTimeOut)
|
| - break;
|
| - WaitForSingleObject(m_RecvDataCond, DWORD(m_iRcvTimeOut - diff ));
|
| - }
|
| - }
|
| - #endif
|
| - }
|
| - }
|
| -
|
| - // throw an exception if not connected
|
| - if (!m_bConnected)
|
| - throw CUDTException(2, 2, 0);
|
| - else if ((m_bBroken || m_bClosing) && (0 == m_pRcvBuffer->getRcvDataSize()))
|
| - throw CUDTException(2, 1, 0);
|
| -
|
| - int res = m_pRcvBuffer->readBuffer(data, len);
|
| -
|
| - if (m_pRcvBuffer->getRcvDataSize() <= 0)
|
| - {
|
| - // read is not available any more
|
| - s_UDTUnited.m_EPoll.disable_read(m_SocketID, m_sPollID);
|
| - }
|
| -
|
| - if ((res <= 0) && (m_iRcvTimeOut >= 0))
|
| - throw CUDTException(6, 2, 0);
|
| -
|
| - return res;
|
| -}
|
| -
|
| -int CUDT::sendmsg(const char* data, const int& len, const int& msttl, const bool& inorder)
|
| -{
|
| - if (UDT_STREAM == m_iSockType)
|
| - throw CUDTException(5, 9, 0);
|
| -
|
| - // throw an exception if not connected
|
| - if (m_bBroken || m_bClosing)
|
| - throw CUDTException(2, 1, 0);
|
| - else if (!m_bConnected)
|
| - throw CUDTException(2, 2, 0);
|
| -
|
| - if (len <= 0)
|
| - return 0;
|
| -
|
| - if (len > m_iSndBufSize * m_iPayloadSize)
|
| - throw CUDTException(5, 12, 0);
|
| -
|
| - CGuard sendguard(m_SendLock);
|
| -
|
| - if (m_pSndBuffer->getCurrBufSize() == 0)
|
| - {
|
| - // delay the EXP timer to avoid mis-fired timeout
|
| - uint64_t currtime;
|
| - CTimer::rdtsc(currtime);
|
| - m_ullNextEXPTime = currtime + m_ullEXPInt;
|
| - }
|
| -
|
| - if ((m_iSndBufSize - m_pSndBuffer->getCurrBufSize()) * m_iPayloadSize < len)
|
| - {
|
| - if (!m_bSynSending)
|
| - throw CUDTException(6, 1, 0);
|
| - else
|
| - {
|
| - // wait here during a blocking sending
|
| - #ifndef WIN32
|
| - pthread_mutex_lock(&m_SendBlockLock);
|
| - if (m_iSndTimeOut < 0)
|
| - {
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && ((m_iSndBufSize - m_pSndBuffer->getCurrBufSize()) * m_iPayloadSize < len))
|
| - pthread_cond_wait(&m_SendBlockCond, &m_SendBlockLock);
|
| - }
|
| - else
|
| - {
|
| - uint64_t exptime = CTimer::getTime() + m_iSndTimeOut * 1000ULL;
|
| - timespec locktime;
|
| -
|
| - locktime.tv_sec = exptime / 1000000;
|
| - locktime.tv_nsec = (exptime % 1000000) * 1000;
|
| -
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && ((m_iSndBufSize - m_pSndBuffer->getCurrBufSize()) * m_iPayloadSize < len) && (CTimer::getTime() < exptime))
|
| - pthread_cond_timedwait(&m_SendBlockCond, &m_SendBlockLock, &locktime);
|
| - }
|
| - pthread_mutex_unlock(&m_SendBlockLock);
|
| - #else
|
| - if (m_iSndTimeOut < 0)
|
| - {
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && ((m_iSndBufSize - m_pSndBuffer->getCurrBufSize()) * m_iPayloadSize < len))
|
| - WaitForSingleObject(m_SendBlockCond, INFINITE);
|
| - }
|
| - else
|
| - {
|
| - uint64_t exptime = CTimer::getTime() + m_iSndTimeOut * 1000ULL;
|
| -
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && ((m_iSndBufSize - m_pSndBuffer->getCurrBufSize()) * m_iPayloadSize < len) && (CTimer::getTime() < exptime))
|
| - WaitForSingleObject(m_SendBlockCond, DWORD((exptime - CTimer::getTime()) / 1000));
|
| - }
|
| - #endif
|
| -
|
| - // check the connection status
|
| - if (m_bBroken || m_bClosing)
|
| - throw CUDTException(2, 1, 0);
|
| - else if (!m_bConnected)
|
| - throw CUDTException(2, 2, 0);
|
| - }
|
| - }
|
| -
|
| - if ((m_iSndBufSize - m_pSndBuffer->getCurrBufSize()) * m_iPayloadSize < len)
|
| - {
|
| - if (m_iSndTimeOut >= 0)
|
| - throw CUDTException(6, 1, 0);
|
| -
|
| - return 0;
|
| - }
|
| -
|
| - // record total time used for sending
|
| - if (0 == m_pSndBuffer->getCurrBufSize())
|
| - m_llSndDurationCounter = CTimer::getTime();
|
| -
|
| - // insert the user buffer into the sening list
|
| - m_pSndBuffer->addBuffer(data, len, msttl, inorder);
|
| -
|
| - // insert this socket to the snd list if it is not on the list yet
|
| - m_pSndQueue->m_pSndUList->update(this, false);
|
| -
|
| - if (m_iSndBufSize <= m_pSndBuffer->getCurrBufSize())
|
| - {
|
| - // write is not available any more
|
| - s_UDTUnited.m_EPoll.disable_write(m_SocketID, m_sPollID);
|
| - }
|
| -
|
| - return len;
|
| -}
|
| -
|
| -int CUDT::recvmsg(char* data, const int& len)
|
| -{
|
| - if (UDT_STREAM == m_iSockType)
|
| - throw CUDTException(5, 9, 0);
|
| -
|
| - // throw an exception if not connected
|
| - if (!m_bConnected)
|
| - throw CUDTException(2, 2, 0);
|
| -
|
| - if (len <= 0)
|
| - return 0;
|
| -
|
| - CGuard recvguard(m_RecvLock);
|
| -
|
| - if (m_bBroken || m_bClosing)
|
| - {
|
| - int res = m_pRcvBuffer->readMsg(data, len);
|
| - if (0 == res)
|
| - {
|
| - // read is not available
|
| - s_UDTUnited.m_EPoll.disable_read(m_SocketID, m_sPollID);
|
| -
|
| - throw CUDTException(2, 1, 0);
|
| - }
|
| - else
|
| - return res;
|
| - }
|
| -
|
| - if (!m_bSynRecving)
|
| - {
|
| - int res = m_pRcvBuffer->readMsg(data, len);
|
| - if (0 == res)
|
| - throw CUDTException(6, 2, 0);
|
| - else
|
| - return res;
|
| - }
|
| -
|
| - int res = 0;
|
| - bool timeout = false;
|
| -
|
| - do
|
| - {
|
| - #ifndef WIN32
|
| - pthread_mutex_lock(&m_RecvDataLock);
|
| -
|
| - if (m_iRcvTimeOut < 0)
|
| - {
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (0 == (res = m_pRcvBuffer->readMsg(data, len))))
|
| - pthread_cond_wait(&m_RecvDataCond, &m_RecvDataLock);
|
| - }
|
| - else
|
| - {
|
| - uint64_t exptime = CTimer::getTime() + m_iRcvTimeOut * 1000ULL;
|
| - timespec locktime;
|
| -
|
| - locktime.tv_sec = exptime / 1000000;
|
| - locktime.tv_nsec = (exptime % 1000000) * 1000;
|
| -
|
| - if (pthread_cond_timedwait(&m_RecvDataCond, &m_RecvDataLock, &locktime) == ETIMEDOUT)
|
| - timeout = true;
|
| -
|
| - res = m_pRcvBuffer->readMsg(data, len);
|
| - }
|
| - pthread_mutex_unlock(&m_RecvDataLock);
|
| - #else
|
| - if (m_iRcvTimeOut < 0)
|
| - {
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (0 == (res = m_pRcvBuffer->readMsg(data, len))))
|
| - WaitForSingleObject(m_RecvDataCond, INFINITE);
|
| - }
|
| - else
|
| - {
|
| - if (WaitForSingleObject(m_RecvDataCond, DWORD(m_iRcvTimeOut)) == WAIT_TIMEOUT)
|
| - timeout = true;
|
| -
|
| - res = m_pRcvBuffer->readMsg(data, len);
|
| - }
|
| - #endif
|
| -
|
| - if (m_bBroken || m_bClosing)
|
| - throw CUDTException(2, 1, 0);
|
| - else if (!m_bConnected)
|
| - throw CUDTException(2, 2, 0);
|
| - } while ((0 == res) && !timeout);
|
| -
|
| - if (m_pRcvBuffer->getRcvMsgNum() <= 0)
|
| - {
|
| - // read is not available any more
|
| - s_UDTUnited.m_EPoll.disable_read(m_SocketID, m_sPollID);
|
| - }
|
| -
|
| - if ((res <= 0) && (m_iRcvTimeOut >= 0))
|
| - throw CUDTException(6, 2, 0);
|
| -
|
| - return res;
|
| -}
|
| -
|
| -int64_t CUDT::sendfile(fstream& ifs, int64_t& offset, const int64_t& size, const int& block)
|
| -{
|
| - if (UDT_DGRAM == m_iSockType)
|
| - throw CUDTException(5, 10, 0);
|
| -
|
| - if (m_bBroken || m_bClosing)
|
| - throw CUDTException(2, 1, 0);
|
| - else if (!m_bConnected)
|
| - throw CUDTException(2, 2, 0);
|
| -
|
| - if (size <= 0)
|
| - return 0;
|
| -
|
| - CGuard sendguard(m_SendLock);
|
| -
|
| - if (m_pSndBuffer->getCurrBufSize() == 0)
|
| - {
|
| - // delay the EXP timer to avoid mis-fired timeout
|
| - uint64_t currtime;
|
| - CTimer::rdtsc(currtime);
|
| - m_ullNextEXPTime = currtime + m_ullEXPInt;
|
| - }
|
| -
|
| - int64_t tosend = size;
|
| - int unitsize;
|
| -
|
| - // positioning...
|
| - try
|
| - {
|
| - ifs.seekg((streamoff)offset);
|
| - }
|
| - catch (...)
|
| - {
|
| - throw CUDTException(4, 1);
|
| - }
|
| -
|
| - // sending block by block
|
| - while (tosend > 0)
|
| - {
|
| - if (ifs.fail())
|
| - throw CUDTException(4, 4);
|
| -
|
| - if (ifs.eof())
|
| - break;
|
| -
|
| - unitsize = int((tosend >= block) ? block : tosend);
|
| -
|
| - #ifndef WIN32
|
| - pthread_mutex_lock(&m_SendBlockLock);
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (m_iSndBufSize <= m_pSndBuffer->getCurrBufSize()) && m_bPeerHealth)
|
| - pthread_cond_wait(&m_SendBlockCond, &m_SendBlockLock);
|
| - pthread_mutex_unlock(&m_SendBlockLock);
|
| - #else
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (m_iSndBufSize <= m_pSndBuffer->getCurrBufSize()) && m_bPeerHealth)
|
| - WaitForSingleObject(m_SendBlockCond, INFINITE);
|
| - #endif
|
| -
|
| - if (m_bBroken || m_bClosing)
|
| - throw CUDTException(2, 1, 0);
|
| - else if (!m_bConnected)
|
| - throw CUDTException(2, 2, 0);
|
| - else if (!m_bPeerHealth)
|
| - {
|
| - // reset peer health status, once this error returns, the app should handle the situation at the peer side
|
| - m_bPeerHealth = true;
|
| - throw CUDTException(7);
|
| - }
|
| -
|
| - // record total time used for sending
|
| - if (0 == m_pSndBuffer->getCurrBufSize())
|
| - m_llSndDurationCounter = CTimer::getTime();
|
| -
|
| - int64_t sentsize = m_pSndBuffer->addBufferFromFile(ifs, unitsize);
|
| -
|
| - if (sentsize > 0)
|
| - {
|
| - tosend -= sentsize;
|
| - offset += sentsize;
|
| - }
|
| -
|
| - // insert this socket to snd list if it is not on the list yet
|
| - m_pSndQueue->m_pSndUList->update(this, false);
|
| - }
|
| -
|
| - if (m_iSndBufSize <= m_pSndBuffer->getCurrBufSize())
|
| - {
|
| - // write is not available any more
|
| - s_UDTUnited.m_EPoll.disable_write(m_SocketID, m_sPollID);
|
| - }
|
| -
|
| - return size - tosend;
|
| -}
|
| -
|
| -int64_t CUDT::recvfile(fstream& ofs, int64_t& offset, const int64_t& size, const int& block)
|
| -{
|
| - if (UDT_DGRAM == m_iSockType)
|
| - throw CUDTException(5, 10, 0);
|
| -
|
| - if (!m_bConnected)
|
| - throw CUDTException(2, 2, 0);
|
| - else if ((m_bBroken || m_bClosing) && (0 == m_pRcvBuffer->getRcvDataSize()))
|
| - throw CUDTException(2, 1, 0);
|
| -
|
| - if (size <= 0)
|
| - return 0;
|
| -
|
| - CGuard recvguard(m_RecvLock);
|
| -
|
| - int64_t torecv = size;
|
| - int unitsize = block;
|
| - int recvsize;
|
| -
|
| - // positioning...
|
| - try
|
| - {
|
| - ofs.seekp((streamoff)offset);
|
| - }
|
| - catch (...)
|
| - {
|
| - throw CUDTException(4, 3);
|
| - }
|
| -
|
| - // receiving... "recvfile" is always blocking
|
| - while (torecv > 0)
|
| - {
|
| - if (ofs.fail())
|
| - {
|
| - // send the sender a signal so it will not be blocked forever
|
| - int32_t err_code = CUDTException::EFILE;
|
| - sendCtrl(8, &err_code);
|
| -
|
| - throw CUDTException(4, 4);
|
| - }
|
| -
|
| - #ifndef WIN32
|
| - pthread_mutex_lock(&m_RecvDataLock);
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (0 == m_pRcvBuffer->getRcvDataSize()))
|
| - pthread_cond_wait(&m_RecvDataCond, &m_RecvDataLock);
|
| - pthread_mutex_unlock(&m_RecvDataLock);
|
| - #else
|
| - while (!m_bBroken && m_bConnected && !m_bClosing && (0 == m_pRcvBuffer->getRcvDataSize()))
|
| - WaitForSingleObject(m_RecvDataCond, INFINITE);
|
| - #endif
|
| -
|
| - if (!m_bConnected)
|
| - throw CUDTException(2, 2, 0);
|
| - else if ((m_bBroken || m_bClosing) && (0 == m_pRcvBuffer->getRcvDataSize()))
|
| - throw CUDTException(2, 1, 0);
|
| -
|
| - unitsize = int((torecv >= block) ? block : torecv);
|
| - recvsize = m_pRcvBuffer->readBufferToFile(ofs, unitsize);
|
| -
|
| - if (recvsize > 0)
|
| - {
|
| - torecv -= recvsize;
|
| - offset += recvsize;
|
| - }
|
| - }
|
| -
|
| - if (m_pRcvBuffer->getRcvDataSize() <= 0)
|
| - {
|
| - // read is not available any more
|
| - s_UDTUnited.m_EPoll.disable_read(m_SocketID, m_sPollID);
|
| - }
|
| -
|
| - return size - torecv;
|
| -}
|
| -
|
| -void CUDT::sample(CPerfMon* perf, bool clear)
|
| -{
|
| - if (!m_bConnected)
|
| - throw CUDTException(2, 2, 0);
|
| - if (m_bBroken || m_bClosing)
|
| - throw CUDTException(2, 1, 0);
|
| -
|
| - uint64_t currtime = CTimer::getTime();
|
| - perf->msTimeStamp = (currtime - m_StartTime) / 1000;
|
| -
|
| - perf->pktSent = m_llTraceSent;
|
| - perf->pktRecv = m_llTraceRecv;
|
| - perf->pktSndLoss = m_iTraceSndLoss;
|
| - perf->pktRcvLoss = m_iTraceRcvLoss;
|
| - perf->pktRetrans = m_iTraceRetrans;
|
| - perf->pktSentACK = m_iSentACK;
|
| - perf->pktRecvACK = m_iRecvACK;
|
| - perf->pktSentNAK = m_iSentNAK;
|
| - perf->pktRecvNAK = m_iRecvNAK;
|
| - perf->usSndDuration = m_llSndDuration;
|
| -
|
| - perf->pktSentTotal = m_llSentTotal;
|
| - perf->pktRecvTotal = m_llRecvTotal;
|
| - perf->pktSndLossTotal = m_iSndLossTotal;
|
| - perf->pktRcvLossTotal = m_iRcvLossTotal;
|
| - perf->pktRetransTotal = m_iRetransTotal;
|
| - perf->pktSentACKTotal = m_iSentACKTotal;
|
| - perf->pktRecvACKTotal = m_iRecvACKTotal;
|
| - perf->pktSentNAKTotal = m_iSentNAKTotal;
|
| - perf->pktRecvNAKTotal = m_iRecvNAKTotal;
|
| - perf->usSndDurationTotal = m_llSndDurationTotal;
|
| -
|
| - double interval = double(currtime - m_LastSampleTime);
|
| -
|
| - perf->mbpsSendRate = double(m_llTraceSent) * m_iPayloadSize * 8.0 / interval;
|
| - perf->mbpsRecvRate = double(m_llTraceRecv) * m_iPayloadSize * 8.0 / interval;
|
| -
|
| - perf->usPktSndPeriod = m_ullInterval / double(m_ullCPUFrequency);
|
| - perf->pktFlowWindow = m_iFlowWindowSize;
|
| - perf->pktCongestionWindow = (int)m_dCongestionWindow;
|
| - perf->pktFlightSize = CSeqNo::seqlen(const_cast<int32_t&>(m_iSndLastAck), CSeqNo::incseq(m_iSndCurrSeqNo)) - 1;
|
| - perf->msRTT = m_iRTT/1000.0;
|
| - perf->mbpsBandwidth = m_iBandwidth * m_iPayloadSize * 8.0 / 1000000.0;
|
| -
|
| - #ifndef WIN32
|
| - if (0 == pthread_mutex_trylock(&m_ConnectionLock))
|
| - #else
|
| - if (WAIT_OBJECT_0 == WaitForSingleObject(m_ConnectionLock, 0))
|
| - #endif
|
| - {
|
| - perf->byteAvailSndBuf = (NULL == m_pSndBuffer) ? 0 : (m_iSndBufSize - m_pSndBuffer->getCurrBufSize()) * m_iMSS;
|
| - perf->byteAvailRcvBuf = (NULL == m_pRcvBuffer) ? 0 : m_pRcvBuffer->getAvailBufSize() * m_iMSS;
|
| -
|
| - #ifndef WIN32
|
| - pthread_mutex_unlock(&m_ConnectionLock);
|
| - #else
|
| - ReleaseMutex(m_ConnectionLock);
|
| - #endif
|
| - }
|
| - else
|
| - {
|
| - perf->byteAvailSndBuf = 0;
|
| - perf->byteAvailRcvBuf = 0;
|
| - }
|
| -
|
| - if (clear)
|
| - {
|
| - m_llTraceSent = m_llTraceRecv = m_iTraceSndLoss = m_iTraceRcvLoss = m_iTraceRetrans = m_iSentACK = m_iRecvACK = m_iSentNAK = m_iRecvNAK = 0;
|
| - m_llSndDuration = 0;
|
| - m_LastSampleTime = currtime;
|
| - }
|
| -}
|
| -
|
| -void CUDT::initSynch()
|
| -{
|
| - #ifndef WIN32
|
| - pthread_mutex_init(&m_SendBlockLock, NULL);
|
| - pthread_cond_init(&m_SendBlockCond, NULL);
|
| - pthread_mutex_init(&m_RecvDataLock, NULL);
|
| - pthread_cond_init(&m_RecvDataCond, NULL);
|
| - pthread_mutex_init(&m_SendLock, NULL);
|
| - pthread_mutex_init(&m_RecvLock, NULL);
|
| - pthread_mutex_init(&m_AckLock, NULL);
|
| - pthread_mutex_init(&m_ConnectionLock, NULL);
|
| - #else
|
| - m_SendBlockLock = CreateMutex(NULL, false, NULL);
|
| - m_SendBlockCond = CreateEvent(NULL, false, false, NULL);
|
| - m_RecvDataLock = CreateMutex(NULL, false, NULL);
|
| - m_RecvDataCond = CreateEvent(NULL, false, false, NULL);
|
| - m_SendLock = CreateMutex(NULL, false, NULL);
|
| - m_RecvLock = CreateMutex(NULL, false, NULL);
|
| - m_AckLock = CreateMutex(NULL, false, NULL);
|
| - m_ConnectionLock = CreateMutex(NULL, false, NULL);
|
| - #endif
|
| -}
|
| -
|
| -void CUDT::destroySynch()
|
| -{
|
| - #ifndef WIN32
|
| - pthread_mutex_destroy(&m_SendBlockLock);
|
| - pthread_cond_destroy(&m_SendBlockCond);
|
| - pthread_mutex_destroy(&m_RecvDataLock);
|
| - pthread_cond_destroy(&m_RecvDataCond);
|
| - pthread_mutex_destroy(&m_SendLock);
|
| - pthread_mutex_destroy(&m_RecvLock);
|
| - pthread_mutex_destroy(&m_AckLock);
|
| - pthread_mutex_destroy(&m_ConnectionLock);
|
| - #else
|
| - CloseHandle(m_SendBlockLock);
|
| - CloseHandle(m_SendBlockCond);
|
| - CloseHandle(m_RecvDataLock);
|
| - CloseHandle(m_RecvDataCond);
|
| - CloseHandle(m_SendLock);
|
| - CloseHandle(m_RecvLock);
|
| - CloseHandle(m_AckLock);
|
| - CloseHandle(m_ConnectionLock);
|
| - #endif
|
| -}
|
| -
|
| -void CUDT::releaseSynch()
|
| -{
|
| - #ifndef WIN32
|
| - // wake up user calls
|
| - pthread_mutex_lock(&m_SendBlockLock);
|
| - pthread_cond_signal(&m_SendBlockCond);
|
| - pthread_mutex_unlock(&m_SendBlockLock);
|
| -
|
| - pthread_mutex_lock(&m_SendLock);
|
| - pthread_mutex_unlock(&m_SendLock);
|
| -
|
| - pthread_mutex_lock(&m_RecvDataLock);
|
| - pthread_cond_signal(&m_RecvDataCond);
|
| - pthread_mutex_unlock(&m_RecvDataLock);
|
| -
|
| - pthread_mutex_lock(&m_RecvLock);
|
| - pthread_mutex_unlock(&m_RecvLock);
|
| - #else
|
| - SetEvent(m_SendBlockCond);
|
| - WaitForSingleObject(m_SendLock, INFINITE);
|
| - ReleaseMutex(m_SendLock);
|
| - SetEvent(m_RecvDataCond);
|
| - WaitForSingleObject(m_RecvLock, INFINITE);
|
| - ReleaseMutex(m_RecvLock);
|
| - #endif
|
| -}
|
| -
|
| -void CUDT::sendCtrl(const int& pkttype, void* lparam, void* rparam, const int& size)
|
| -{
|
| - CPacket ctrlpkt;
|
| -
|
| - switch (pkttype)
|
| - {
|
| - case 2: //010 - Acknowledgement
|
| - {
|
| - int32_t ack;
|
| -
|
| - // If there is no loss, the ACK is the current largest sequence number plus 1;
|
| - // Otherwise it is the smallest sequence number in the receiver loss list.
|
| - if (0 == m_pRcvLossList->getLossLength())
|
| - ack = CSeqNo::incseq(m_iRcvCurrSeqNo);
|
| - else
|
| - ack = m_pRcvLossList->getFirstLostSeq();
|
| -
|
| - if (ack == m_iRcvLastAckAck)
|
| - break;
|
| -
|
| - // send out a lite ACK
|
| - // to save time on buffer processing and bandwidth/AS measurement, a lite ACK only feeds back an ACK number
|
| - if (4 == size)
|
| - {
|
| - ctrlpkt.pack(pkttype, NULL, &ack, size);
|
| - ctrlpkt.m_iID = m_PeerID;
|
| - m_pSndQueue->sendto(m_pPeerAddr, ctrlpkt);
|
| -
|
| - break;
|
| - }
|
| -
|
| - uint64_t currtime;
|
| - CTimer::rdtsc(currtime);
|
| -
|
| - // There are new received packets to acknowledge, update related information.
|
| - if (CSeqNo::seqcmp(ack, m_iRcvLastAck) > 0)
|
| - {
|
| - int acksize = CSeqNo::seqoff(m_iRcvLastAck, ack);
|
| -
|
| - m_iRcvLastAck = ack;
|
| -
|
| - m_pRcvBuffer->ackData(acksize);
|
| -
|
| - // signal a waiting "recv" call if there is any data available
|
| - #ifndef WIN32
|
| - pthread_mutex_lock(&m_RecvDataLock);
|
| - if (m_bSynRecving)
|
| - pthread_cond_signal(&m_RecvDataCond);
|
| - pthread_mutex_unlock(&m_RecvDataLock);
|
| - #else
|
| - if (m_bSynRecving)
|
| - SetEvent(m_RecvDataCond);
|
| - #endif
|
| -
|
| - // acknowledge any waiting epolls to read
|
| - s_UDTUnited.m_EPoll.enable_read(m_SocketID, m_sPollID);
|
| - }
|
| - else if (ack == m_iRcvLastAck)
|
| - {
|
| - if ((currtime - m_ullLastAckTime) < ((m_iRTT + 4 * m_iRTTVar) * m_ullCPUFrequency))
|
| - break;
|
| - }
|
| - else
|
| - break;
|
| -
|
| - // Send out the ACK only if has not been received by the sender before
|
| - if (CSeqNo::seqcmp(m_iRcvLastAck, m_iRcvLastAckAck) > 0)
|
| - {
|
| - int32_t data[6];
|
| -
|
| - m_iAckSeqNo = CAckNo::incack(m_iAckSeqNo);
|
| - data[0] = m_iRcvLastAck;
|
| - data[1] = m_iRTT;
|
| - data[2] = m_iRTTVar;
|
| - data[3] = m_pRcvBuffer->getAvailBufSize();
|
| - // a minimum flow window of 2 is used, even if buffer is full, to break potential deadlock
|
| - if (data[3] < 2)
|
| - data[3] = 2;
|
| -
|
| - if (currtime - m_ullLastAckTime > m_ullSYNInt)
|
| - {
|
| - data[4] = m_pRcvTimeWindow->getPktRcvSpeed();
|
| - data[5] = m_pRcvTimeWindow->getBandwidth();
|
| - ctrlpkt.pack(pkttype, &m_iAckSeqNo, data, 24);
|
| -
|
| - CTimer::rdtsc(m_ullLastAckTime);
|
| - }
|
| - else
|
| - {
|
| - ctrlpkt.pack(pkttype, &m_iAckSeqNo, data, 16);
|
| - }
|
| -
|
| - ctrlpkt.m_iID = m_PeerID;
|
| - m_pSndQueue->sendto(m_pPeerAddr, ctrlpkt);
|
| -
|
| - m_pACKWindow->store(m_iAckSeqNo, m_iRcvLastAck);
|
| -
|
| - ++ m_iSentACK;
|
| - ++ m_iSentACKTotal;
|
| - }
|
| -
|
| - break;
|
| - }
|
| -
|
| - case 6: //110 - Acknowledgement of Acknowledgement
|
| - ctrlpkt.pack(pkttype, lparam);
|
| - ctrlpkt.m_iID = m_PeerID;
|
| - m_pSndQueue->sendto(m_pPeerAddr, ctrlpkt);
|
| -
|
| - break;
|
| -
|
| - case 3: //011 - Loss Report
|
| - {
|
| - if (NULL != rparam)
|
| - {
|
| - if (1 == size)
|
| - {
|
| - // only 1 loss packet
|
| - ctrlpkt.pack(pkttype, NULL, (int32_t *)rparam + 1, 4);
|
| - }
|
| - else
|
| - {
|
| - // more than 1 loss packets
|
| - ctrlpkt.pack(pkttype, NULL, rparam, 8);
|
| - }
|
| -
|
| - ctrlpkt.m_iID = m_PeerID;
|
| - m_pSndQueue->sendto(m_pPeerAddr, ctrlpkt);
|
| -
|
| - ++ m_iSentNAK;
|
| - ++ m_iSentNAKTotal;
|
| - }
|
| - else if (m_pRcvLossList->getLossLength() > 0)
|
| - {
|
| - // this is periodically NAK report; make sure NAK cannot be sent back too often
|
| -
|
| - // read loss list from the local receiver loss list
|
| - int32_t* data = new int32_t[m_iPayloadSize / 4];
|
| - int losslen;
|
| - m_pRcvLossList->getLossArray(data, losslen, m_iPayloadSize / 4);
|
| -
|
| - if (0 < losslen)
|
| - {
|
| - ctrlpkt.pack(pkttype, NULL, data, losslen * 4);
|
| - ctrlpkt.m_iID = m_PeerID;
|
| - m_pSndQueue->sendto(m_pPeerAddr, ctrlpkt);
|
| -
|
| - ++ m_iSentNAK;
|
| - ++ m_iSentNAKTotal;
|
| - }
|
| -
|
| - delete [] data;
|
| - }
|
| -
|
| - // update next NAK time, which should wait enough time for the retansmission, but not too long
|
| - m_ullNAKInt = (m_iRTT + 4 * m_iRTTVar) * m_ullCPUFrequency;
|
| - int rcv_speed = m_pRcvTimeWindow->getPktRcvSpeed();
|
| - if (rcv_speed > 0)
|
| - m_ullNAKInt += (m_pRcvLossList->getLossLength() * 1000000ULL / rcv_speed) * m_ullCPUFrequency;
|
| - if (m_ullNAKInt < m_ullMinNakInt)
|
| - m_ullNAKInt = m_ullMinNakInt;
|
| -
|
| - break;
|
| - }
|
| -
|
| - case 4: //100 - Congestion Warning
|
| - ctrlpkt.pack(pkttype);
|
| - ctrlpkt.m_iID = m_PeerID;
|
| - m_pSndQueue->sendto(m_pPeerAddr, ctrlpkt);
|
| -
|
| - CTimer::rdtsc(m_ullLastWarningTime);
|
| -
|
| - break;
|
| -
|
| - case 1: //001 - Keep-alive
|
| - ctrlpkt.pack(pkttype);
|
| - ctrlpkt.m_iID = m_PeerID;
|
| - m_pSndQueue->sendto(m_pPeerAddr, ctrlpkt);
|
| -
|
| - break;
|
| -
|
| - case 0: //000 - Handshake
|
| - ctrlpkt.pack(pkttype, NULL, rparam, sizeof(CHandShake));
|
| - ctrlpkt.m_iID = m_PeerID;
|
| - m_pSndQueue->sendto(m_pPeerAddr, ctrlpkt);
|
| -
|
| - break;
|
| -
|
| - case 5: //101 - Shutdown
|
| - ctrlpkt.pack(pkttype);
|
| - ctrlpkt.m_iID = m_PeerID;
|
| - m_pSndQueue->sendto(m_pPeerAddr, ctrlpkt);
|
| -
|
| - break;
|
| -
|
| - case 7: //111 - Msg drop request
|
| - ctrlpkt.pack(pkttype, lparam, rparam, 8);
|
| - ctrlpkt.m_iID = m_PeerID;
|
| - m_pSndQueue->sendto(m_pPeerAddr, ctrlpkt);
|
| -
|
| - break;
|
| -
|
| - case 8: //1000 - acknowledge the peer side a special error
|
| - ctrlpkt.pack(pkttype, lparam);
|
| - ctrlpkt.m_iID = m_PeerID;
|
| - m_pSndQueue->sendto(m_pPeerAddr, ctrlpkt);
|
| -
|
| - break;
|
| -
|
| - case 32767: //0x7FFF - Resevered for future use
|
| - break;
|
| -
|
| - default:
|
| - break;
|
| - }
|
| -}
|
| -
|
| -void CUDT::processCtrl(CPacket& ctrlpkt)
|
| -{
|
| - // Just heard from the peer, reset the expiration count.
|
| - m_iEXPCount = 1;
|
| - m_llLastRspTime = CTimer::getTime();
|
| -
|
| - if ((CSeqNo::incseq(m_iSndCurrSeqNo) == m_iSndLastAck) || (2 == ctrlpkt.getType()) || (3 == ctrlpkt.getType()))
|
| - {
|
| - uint64_t currtime;
|
| - CTimer::rdtsc(currtime);
|
| - if (!m_pCC->m_bUserDefinedRTO)
|
| - m_ullNextEXPTime = currtime + m_ullEXPInt;
|
| - else
|
| - m_ullNextEXPTime = currtime + m_pCC->m_iRTO * m_ullCPUFrequency;
|
| - }
|
| -
|
| - switch (ctrlpkt.getType())
|
| - {
|
| - case 2: //010 - Acknowledgement
|
| - {
|
| - int32_t ack;
|
| -
|
| - // process a lite ACK
|
| - if (4 == ctrlpkt.getLength())
|
| - {
|
| - ack = *(int32_t *)ctrlpkt.m_pcData;
|
| - if (CSeqNo::seqcmp(ack, const_cast<int32_t&>(m_iSndLastAck)) >= 0)
|
| - {
|
| - m_iFlowWindowSize -= CSeqNo::seqoff(const_cast<int32_t&>(m_iSndLastAck), ack);
|
| - m_iSndLastAck = ack;
|
| - }
|
| -
|
| - break;
|
| - }
|
| -
|
| - // read ACK seq. no.
|
| - ack = ctrlpkt.getAckSeqNo();
|
| -
|
| - // send ACK acknowledgement
|
| - // number of ACK2 can be much less than number of ACK
|
| - uint64_t currtime = CTimer::getTime();
|
| - if ((currtime - m_ullSndLastAck2Time > (uint64_t)m_iSYNInterval) || (ack == m_iSndLastAck2))
|
| - {
|
| - sendCtrl(6, &ack);
|
| - m_iSndLastAck2 = ack;
|
| - m_ullSndLastAck2Time = currtime;
|
| - }
|
| -
|
| - // Got data ACK
|
| - ack = *(int32_t *)ctrlpkt.m_pcData;
|
| -
|
| - // check the validation of the ack
|
| - if (CSeqNo::seqcmp(ack, CSeqNo::incseq(m_iSndCurrSeqNo)) > 0)
|
| - {
|
| - //this should not happen: attack or bug
|
| - m_bBroken = true;
|
| - m_iBrokenCounter = 0;
|
| - break;
|
| - }
|
| -
|
| - if (CSeqNo::seqcmp(ack, const_cast<int32_t&>(m_iSndLastAck)) >= 0)
|
| - {
|
| - // Update Flow Window Size, must update before and together with m_iSndLastAck
|
| - m_iFlowWindowSize = *((int32_t *)ctrlpkt.m_pcData + 3);
|
| - m_iSndLastAck = ack;
|
| - }
|
| -
|
| - // protect packet retransmission
|
| - CGuard::enterCS(m_AckLock);
|
| -
|
| - int offset = CSeqNo::seqoff((int32_t&)m_iSndLastDataAck, ack);
|
| - if (offset <= 0)
|
| - {
|
| - // discard it if it is a repeated ACK
|
| - CGuard::leaveCS(m_AckLock);
|
| - break;
|
| - }
|
| -
|
| - // acknowledge the sending buffer
|
| - m_pSndBuffer->ackData(offset);
|
| -
|
| - // record total time used for sending
|
| - m_llSndDuration += currtime - m_llSndDurationCounter;
|
| - m_llSndDurationTotal += currtime - m_llSndDurationCounter;
|
| - m_llSndDurationCounter = currtime;
|
| -
|
| - // update sending variables
|
| - m_iSndLastDataAck = ack;
|
| - m_pSndLossList->remove(CSeqNo::decseq((int32_t&)m_iSndLastDataAck));
|
| -
|
| - CGuard::leaveCS(m_AckLock);
|
| -
|
| - #ifndef WIN32
|
| - pthread_mutex_lock(&m_SendBlockLock);
|
| - if (m_bSynSending)
|
| - pthread_cond_signal(&m_SendBlockCond);
|
| - pthread_mutex_unlock(&m_SendBlockLock);
|
| - #else
|
| - if (m_bSynSending)
|
| - SetEvent(m_SendBlockCond);
|
| - #endif
|
| -
|
| - // acknowledde any waiting epolls to write
|
| - s_UDTUnited.m_EPoll.enable_write(m_SocketID, m_sPollID);
|
| -
|
| - // insert this socket to snd list if it is not on the list yet
|
| - m_pSndQueue->m_pSndUList->update(this, false);
|
| -
|
| - // Update RTT
|
| - //m_iRTT = *((int32_t *)ctrlpkt.m_pcData + 1);
|
| - //m_iRTTVar = *((int32_t *)ctrlpkt.m_pcData + 2);
|
| - int rtt = *((int32_t *)ctrlpkt.m_pcData + 1);
|
| - m_iRTTVar = (m_iRTTVar * 3 + abs(rtt - m_iRTT)) >> 2;
|
| - m_iRTT = (m_iRTT * 7 + rtt) >> 3;
|
| -
|
| - m_pCC->setRTT(m_iRTT);
|
| -
|
| - m_ullEXPInt = (m_iRTT + 4 * m_iRTTVar) * m_ullCPUFrequency + m_ullSYNInt;
|
| - if (m_ullEXPInt < m_ullMinExpInt)
|
| - m_ullEXPInt = m_ullMinExpInt;
|
| -
|
| - if (ctrlpkt.getLength() > 16)
|
| - {
|
| - // Update Estimated Bandwidth and packet delivery rate
|
| - if (*((int32_t *)ctrlpkt.m_pcData + 4) > 0)
|
| - m_iDeliveryRate = (m_iDeliveryRate * 7 + *((int32_t *)ctrlpkt.m_pcData + 4)) >> 3;
|
| -
|
| - if (*((int32_t *)ctrlpkt.m_pcData + 5) > 0)
|
| - m_iBandwidth = (m_iBandwidth * 7 + *((int32_t *)ctrlpkt.m_pcData + 5)) >> 3;
|
| -
|
| - m_pCC->setRcvRate(m_iDeliveryRate);
|
| - m_pCC->setBandwidth(m_iBandwidth);
|
| - }
|
| -
|
| - m_pCC->onACK(ack);
|
| - // update CC parameters
|
| - m_ullInterval = (uint64_t)(m_pCC->m_dPktSndPeriod * m_ullCPUFrequency);
|
| - m_dCongestionWindow = m_pCC->m_dCWndSize;
|
| -
|
| - ++ m_iRecvACK;
|
| - ++ m_iRecvACKTotal;
|
| -
|
| - break;
|
| - }
|
| -
|
| - case 6: //110 - Acknowledgement of Acknowledgement
|
| - {
|
| - int32_t ack;
|
| - int rtt = -1;
|
| -
|
| - // update RTT
|
| - rtt = m_pACKWindow->acknowledge(ctrlpkt.getAckSeqNo(), ack);
|
| - if (rtt <= 0)
|
| - break;
|
| -
|
| - //if increasing delay detected...
|
| - // sendCtrl(4);
|
| -
|
| - // RTT EWMA
|
| - m_iRTTVar = (m_iRTTVar * 3 + abs(rtt - m_iRTT)) >> 2;
|
| - m_iRTT = (m_iRTT * 7 + rtt) >> 3;
|
| -
|
| - m_pCC->setRTT(m_iRTT);
|
| -
|
| - m_ullEXPInt = (m_iRTT + 4 * m_iRTTVar) * m_ullCPUFrequency + m_ullSYNInt;
|
| - if (m_ullEXPInt < m_ullMinExpInt)
|
| - m_ullEXPInt = m_ullMinExpInt;
|
| -
|
| - // update last ACK that has been received by the sender
|
| - if (CSeqNo::seqcmp(ack, m_iRcvLastAckAck) > 0)
|
| - m_iRcvLastAckAck = ack;
|
| -
|
| - break;
|
| - }
|
| -
|
| - case 3: //011 - Loss Report
|
| - {
|
| - int32_t* losslist = (int32_t *)(ctrlpkt.m_pcData);
|
| -
|
| - m_pCC->onLoss(losslist, ctrlpkt.getLength() / 4);
|
| - // update CC parameters
|
| - m_ullInterval = (uint64_t)(m_pCC->m_dPktSndPeriod * m_ullCPUFrequency);
|
| - m_dCongestionWindow = m_pCC->m_dCWndSize;
|
| -
|
| - bool secure = true;
|
| -
|
| - // decode loss list message and insert loss into the sender loss list
|
| - for (int i = 0, n = (int)(ctrlpkt.getLength() / 4); i < n; ++ i)
|
| - {
|
| - if (0 != (losslist[i] & 0x80000000))
|
| - {
|
| - if ((CSeqNo::seqcmp(losslist[i] & 0x7FFFFFFF, losslist[i + 1]) > 0) || (CSeqNo::seqcmp(losslist[i + 1], const_cast<int32_t&>(m_iSndCurrSeqNo)) > 0))
|
| - {
|
| - // seq_a must not be greater than seq_b; seq_b must not be greater than the most recent sent seq
|
| - secure = false;
|
| - break;
|
| - }
|
| -
|
| - int num = 0;
|
| - if (CSeqNo::seqcmp(losslist[i] & 0x7FFFFFFF, const_cast<int32_t&>(m_iSndLastAck)) >= 0)
|
| - num = m_pSndLossList->insert(losslist[i] & 0x7FFFFFFF, losslist[i + 1]);
|
| - else if (CSeqNo::seqcmp(losslist[i + 1], const_cast<int32_t&>(m_iSndLastAck)) >= 0)
|
| - num = m_pSndLossList->insert(const_cast<int32_t&>(m_iSndLastAck), losslist[i + 1]);
|
| -
|
| - m_iTraceSndLoss += num;
|
| - m_iSndLossTotal += num;
|
| -
|
| - ++ i;
|
| - }
|
| - else if (CSeqNo::seqcmp(losslist[i], const_cast<int32_t&>(m_iSndLastAck)) >= 0)
|
| - {
|
| - if (CSeqNo::seqcmp(losslist[i], const_cast<int32_t&>(m_iSndCurrSeqNo)) > 0)
|
| - {
|
| - //seq_a must not be greater than the most recent sent seq
|
| - secure = false;
|
| - break;
|
| - }
|
| -
|
| - int num = m_pSndLossList->insert(losslist[i], losslist[i]);
|
| -
|
| - m_iTraceSndLoss += num;
|
| - m_iSndLossTotal += num;
|
| - }
|
| - }
|
| -
|
| - if (!secure)
|
| - {
|
| - //this should not happen: attack or bug
|
| - m_bBroken = true;
|
| - m_iBrokenCounter = 0;
|
| - break;
|
| - }
|
| -
|
| - // the lost packet (retransmission) should be sent out immediately
|
| - m_pSndQueue->m_pSndUList->update(this);
|
| -
|
| - ++ m_iRecvNAK;
|
| - ++ m_iRecvNAKTotal;
|
| -
|
| - break;
|
| - }
|
| -
|
| - case 4: //100 - Delay Warning
|
| - // One way packet delay is increasing, so decrease the sending rate
|
| - m_ullInterval = (uint64_t)ceil(m_ullInterval * 1.125);
|
| - m_iLastDecSeq = m_iSndCurrSeqNo;
|
| -
|
| - break;
|
| -
|
| - case 1: //001 - Keep-alive
|
| - // The only purpose of keep-alive packet is to tell that the peer is still alive
|
| - // nothing needs to be done.
|
| -
|
| - break;
|
| -
|
| - case 0: //000 - Handshake
|
| - if ((((CHandShake*)(ctrlpkt.m_pcData))->m_iReqType > 0) || (m_bRendezvous && (((CHandShake*)(ctrlpkt.m_pcData))->m_iReqType != -2)))
|
| - {
|
| - // The peer side has not received the handshake message, so it keeps querying
|
| - // resend the handshake packet
|
| -
|
| - CHandShake initdata;
|
| - initdata.m_iISN = m_iISN;
|
| - initdata.m_iMSS = m_iMSS;
|
| - initdata.m_iFlightFlagSize = m_iFlightFlagSize;
|
| - initdata.m_iReqType = (!m_bRendezvous) ? -1 : -2;
|
| - initdata.m_iID = m_SocketID;
|
| -
|
| - char buffer[1500];
|
| - int size = 1500;
|
| - initdata.serialize(buffer, size);
|
| - sendCtrl(0, NULL, buffer, size);
|
| - }
|
| -
|
| - break;
|
| -
|
| - case 5: //101 - Shutdown
|
| - m_bShutdown = true;
|
| - m_bClosing = true;
|
| - m_bBroken = true;
|
| - m_iBrokenCounter = 60;
|
| -
|
| - // Signal the sender and recver if they are waiting for data.
|
| - releaseSynch();
|
| -
|
| - CTimer::triggerEvent();
|
| -
|
| - break;
|
| -
|
| - case 7: //111 - Msg drop request
|
| - m_pRcvBuffer->dropMsg(ctrlpkt.getMsgSeq());
|
| - m_pRcvLossList->remove(*(int32_t*)ctrlpkt.m_pcData, *(int32_t*)(ctrlpkt.m_pcData + 4));
|
| -
|
| - // move forward with current recv seq no.
|
| - if ((CSeqNo::seqcmp(*(int32_t*)ctrlpkt.m_pcData, CSeqNo::incseq(m_iRcvCurrSeqNo)) <= 0)
|
| - && (CSeqNo::seqcmp(*(int32_t*)(ctrlpkt.m_pcData + 4), m_iRcvCurrSeqNo) > 0))
|
| - {
|
| - m_iRcvCurrSeqNo = *(int32_t*)(ctrlpkt.m_pcData + 4);
|
| - }
|
| -
|
| - break;
|
| -
|
| - case 8: // 1000 - An error has happened to the peer side
|
| - //int err_type = packet.getAddInfo();
|
| -
|
| - // currently only this error is signalled from the peer side
|
| - // if recvfile() failes (e.g., due to disk fail), blcoked sendfile/send should return immediately
|
| - // giving the app a chance to fix the issue
|
| -
|
| - m_bPeerHealth = false;
|
| -
|
| - break;
|
| -
|
| - case 32767: //0x7FFF - reserved and user defined messages
|
| - m_pCC->processCustomMsg(&ctrlpkt);
|
| - // update CC parameters
|
| - m_ullInterval = (uint64_t)(m_pCC->m_dPktSndPeriod * m_ullCPUFrequency);
|
| - m_dCongestionWindow = m_pCC->m_dCWndSize;
|
| -
|
| - break;
|
| -
|
| - default:
|
| - break;
|
| - }
|
| -}
|
| -
|
| -int CUDT::packData(CPacket& packet, uint64_t& ts)
|
| -{
|
| - int payload = 0;
|
| - bool probe = false;
|
| -
|
| - uint64_t entertime;
|
| - CTimer::rdtsc(entertime);
|
| -
|
| - if ((0 != m_ullTargetTime) && (entertime > m_ullTargetTime))
|
| - m_ullTimeDiff += entertime - m_ullTargetTime;
|
| -
|
| - // Loss retransmission always has higher priority.
|
| - if ((packet.m_iSeqNo = m_pSndLossList->getLostSeq()) >= 0)
|
| - {
|
| - // protect m_iSndLastDataAck from updating by ACK processing
|
| - CGuard ackguard(m_AckLock);
|
| -
|
| - int offset = CSeqNo::seqoff((int32_t&)m_iSndLastDataAck, packet.m_iSeqNo);
|
| - if (offset < 0)
|
| - return 0;
|
| -
|
| - int msglen;
|
| -
|
| - payload = m_pSndBuffer->readData(&(packet.m_pcData), offset, packet.m_iMsgNo, msglen);
|
| -
|
| - if (-1 == payload)
|
| - {
|
| - int32_t seqpair[2];
|
| - seqpair[0] = packet.m_iSeqNo;
|
| - seqpair[1] = CSeqNo::incseq(seqpair[0], msglen);
|
| - sendCtrl(7, &packet.m_iMsgNo, seqpair, 8);
|
| -
|
| - // only one msg drop request is necessary
|
| - m_pSndLossList->remove(seqpair[1]);
|
| -
|
| - // skip all dropped packets
|
| - if (CSeqNo::seqcmp(const_cast<int32_t&>(m_iSndCurrSeqNo), CSeqNo::incseq(seqpair[1])) < 0)
|
| - m_iSndCurrSeqNo = CSeqNo::incseq(seqpair[1]);
|
| -
|
| - return 0;
|
| - }
|
| - else if (0 == payload)
|
| - return 0;
|
| -
|
| - ++ m_iTraceRetrans;
|
| - ++ m_iRetransTotal;
|
| - }
|
| - else
|
| - {
|
| - // If no loss, pack a new packet.
|
| -
|
| - // check congestion/flow window limit
|
| - int cwnd = (m_iFlowWindowSize < (int)m_dCongestionWindow) ? m_iFlowWindowSize : (int)m_dCongestionWindow;
|
| - if (cwnd >= CSeqNo::seqlen(const_cast<int32_t&>(m_iSndLastAck), CSeqNo::incseq(m_iSndCurrSeqNo)))
|
| - {
|
| - if (0 != (payload = m_pSndBuffer->readData(&(packet.m_pcData), packet.m_iMsgNo)))
|
| - {
|
| - m_iSndCurrSeqNo = CSeqNo::incseq(m_iSndCurrSeqNo);
|
| - m_pCC->setSndCurrSeqNo((int32_t&)m_iSndCurrSeqNo);
|
| -
|
| - packet.m_iSeqNo = m_iSndCurrSeqNo;
|
| -
|
| - // every 16 (0xF) packets, a packet pair is sent
|
| - if (0 == (packet.m_iSeqNo & 0xF))
|
| - probe = true;
|
| - }
|
| - else
|
| - {
|
| - m_ullTargetTime = 0;
|
| - m_ullTimeDiff = 0;
|
| - ts = 0;
|
| - return 0;
|
| - }
|
| - }
|
| - else
|
| - {
|
| - m_ullTargetTime = 0;
|
| - m_ullTimeDiff = 0;
|
| - ts = 0;
|
| - return 0;
|
| - }
|
| - }
|
| -
|
| - packet.m_iTimeStamp = int(CTimer::getTime() - m_StartTime);
|
| - packet.m_iID = m_PeerID;
|
| - packet.setLength(payload);
|
| -
|
| - m_pCC->onPktSent(&packet);
|
| - //m_pSndTimeWindow->onPktSent(packet.m_iTimeStamp);
|
| -
|
| - ++ m_llTraceSent;
|
| - ++ m_llSentTotal;
|
| -
|
| - if (probe)
|
| - {
|
| - // sends out probing packet pair
|
| - ts = entertime;
|
| - probe = false;
|
| - }
|
| - else
|
| - {
|
| - #ifndef NO_BUSY_WAITING
|
| - ts = entertime + m_ullInterval;
|
| - #else
|
| - if (m_ullTimeDiff >= m_ullInterval)
|
| - {
|
| - ts = entertime;
|
| - m_ullTimeDiff -= m_ullInterval;
|
| - }
|
| - else
|
| - {
|
| - ts = entertime + m_ullInterval - m_ullTimeDiff;
|
| - m_ullTimeDiff = 0;
|
| - }
|
| - #endif
|
| - }
|
| -
|
| - m_ullTargetTime = ts;
|
| -
|
| - return payload;
|
| -}
|
| -
|
| -int CUDT::processData(CUnit* unit)
|
| -{
|
| - CPacket& packet = unit->m_Packet;
|
| -
|
| - // Just heard from the peer, reset the expiration count.
|
| - m_iEXPCount = 1;
|
| - m_llLastRspTime = CTimer::getTime();
|
| -
|
| - if (CSeqNo::incseq(m_iSndCurrSeqNo) == m_iSndLastAck)
|
| - {
|
| - uint64_t currtime;
|
| - CTimer::rdtsc(currtime);
|
| - if (!m_pCC->m_bUserDefinedRTO)
|
| - m_ullNextEXPTime = currtime + m_ullEXPInt;
|
| - else
|
| - m_ullNextEXPTime = currtime + m_pCC->m_iRTO * m_ullCPUFrequency;
|
| - }
|
| -
|
| - m_pCC->onPktReceived(&packet);
|
| -
|
| - ++ m_iPktCount;
|
| -
|
| - // update time information
|
| - m_pRcvTimeWindow->onPktArrival();
|
| -
|
| - // check if it is probing packet pair
|
| - if (0 == (packet.m_iSeqNo & 0xF))
|
| - m_pRcvTimeWindow->probe1Arrival();
|
| - else if (1 == (packet.m_iSeqNo & 0xF))
|
| - m_pRcvTimeWindow->probe2Arrival();
|
| -
|
| - ++ m_llTraceRecv;
|
| - ++ m_llRecvTotal;
|
| -
|
| - int32_t offset = CSeqNo::seqoff(m_iRcvLastAck, packet.m_iSeqNo);
|
| - if ((offset < 0) || (offset >= m_pRcvBuffer->getAvailBufSize()))
|
| - return -1;
|
| -
|
| - if (m_pRcvBuffer->addData(unit, offset) < 0)
|
| - return -1;
|
| -
|
| - // Loss detection.
|
| - if (CSeqNo::seqcmp(packet.m_iSeqNo, CSeqNo::incseq(m_iRcvCurrSeqNo)) > 0)
|
| - {
|
| - // If loss found, insert them to the receiver loss list
|
| - m_pRcvLossList->insert(CSeqNo::incseq(m_iRcvCurrSeqNo), CSeqNo::decseq(packet.m_iSeqNo));
|
| -
|
| - // pack loss list for NAK
|
| - int32_t lossdata[2];
|
| - lossdata[0] = CSeqNo::incseq(m_iRcvCurrSeqNo) | 0x80000000;
|
| - lossdata[1] = CSeqNo::decseq(packet.m_iSeqNo);
|
| -
|
| - // Generate loss report immediately.
|
| - sendCtrl(3, NULL, lossdata, (CSeqNo::incseq(m_iRcvCurrSeqNo) == CSeqNo::decseq(packet.m_iSeqNo)) ? 1 : 2);
|
| -
|
| - int loss = CSeqNo::seqlen(m_iRcvCurrSeqNo, packet.m_iSeqNo) - 2;
|
| - m_iTraceRcvLoss += loss;
|
| - m_iRcvLossTotal += loss;
|
| - }
|
| -
|
| - // This is not a regular fixed size packet...
|
| - //an irregular sized packet usually indicates the end of a message, so send an ACK immediately
|
| - if (packet.getLength() != m_iPayloadSize)
|
| - CTimer::rdtsc(m_ullNextACKTime);
|
| -
|
| - // Update the current largest sequence number that has been received.
|
| - // Or it is a retransmitted packet, remove it from receiver loss list.
|
| - if (CSeqNo::seqcmp(packet.m_iSeqNo, m_iRcvCurrSeqNo) > 0)
|
| - m_iRcvCurrSeqNo = packet.m_iSeqNo;
|
| - else
|
| - m_pRcvLossList->remove(packet.m_iSeqNo);
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -int CUDT::listen(sockaddr* addr, CPacket& packet)
|
| -{
|
| - if (m_bClosing)
|
| - return 1002;
|
| -
|
| - if (packet.getLength() != CHandShake::m_iContentSize)
|
| - return 1004;
|
| -
|
| - CHandShake hs;
|
| - hs.deserialize(packet.m_pcData, packet.getLength());
|
| -
|
| - // SYN cookie
|
| - char clienthost[NI_MAXHOST];
|
| - char clientport[NI_MAXSERV];
|
| - getnameinfo(addr, (AF_INET == m_iVersion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6), clienthost, sizeof(clienthost), clientport, sizeof(clientport), NI_NUMERICHOST|NI_NUMERICSERV);
|
| - int64_t timestamp = (CTimer::getTime() - m_StartTime) / 60000000; // secret changes every one minute
|
| - char cookiestr[1024];
|
| - sprintf(cookiestr, "%s:%s:%lld", clienthost, clientport, (long long int)timestamp);
|
| - unsigned char cookie[16];
|
| - CMD5::compute(cookiestr, cookie);
|
| -
|
| - if (1 == hs.m_iReqType)
|
| - {
|
| - hs.m_iCookie = *(int*)cookie;
|
| - packet.m_iID = hs.m_iID;
|
| - int size = packet.getLength();
|
| - hs.serialize(packet.m_pcData, size);
|
| - m_pSndQueue->sendto(addr, packet);
|
| - return 0;
|
| - }
|
| - else
|
| - {
|
| - if (hs.m_iCookie != *(int*)cookie)
|
| - {
|
| - timestamp --;
|
| - sprintf(cookiestr, "%s:%s:%lld", clienthost, clientport, (long long int)timestamp);
|
| - CMD5::compute(cookiestr, cookie);
|
| -
|
| - if (hs.m_iCookie != *(int*)cookie)
|
| - return -1;
|
| - }
|
| - }
|
| -
|
| - int32_t id = hs.m_iID;
|
| -
|
| - // When a peer side connects in...
|
| - if ((1 == packet.getFlag()) && (0 == packet.getType()))
|
| - {
|
| - if ((hs.m_iVersion != m_iVersion) || (hs.m_iType != m_iSockType))
|
| - {
|
| - // mismatch, reject the request
|
| - hs.m_iReqType = 1002;
|
| - int size = CHandShake::m_iContentSize;
|
| - hs.serialize(packet.m_pcData, size);
|
| - packet.m_iID = id;
|
| - m_pSndQueue->sendto(addr, packet);
|
| - }
|
| - else
|
| - {
|
| - int result = s_UDTUnited.newConnection(m_SocketID, addr, &hs);
|
| - if (result == -1)
|
| - hs.m_iReqType = 1002;
|
| -
|
| - // send back a response if connection failed or connection already existed
|
| - // new connection response should be sent in connect()
|
| - if (result != 1)
|
| - {
|
| - int size = CHandShake::m_iContentSize;
|
| - hs.serialize(packet.m_pcData, size);
|
| - packet.m_iID = id;
|
| - m_pSndQueue->sendto(addr, packet);
|
| - }
|
| - else
|
| - {
|
| - // a mew connection has been created, enable epoll for read
|
| - s_UDTUnited.m_EPoll.enable_read(m_SocketID, m_sPollID);
|
| - }
|
| - }
|
| - }
|
| -
|
| - return hs.m_iReqType;
|
| -}
|
| -
|
| -void CUDT::checkTimers()
|
| -{
|
| - // update CC parameters
|
| - m_ullInterval = (uint64_t)(m_pCC->m_dPktSndPeriod * m_ullCPUFrequency);
|
| - m_dCongestionWindow = m_pCC->m_dCWndSize;
|
| - //uint64_t minint = (uint64_t)(m_ullCPUFrequency * m_pSndTimeWindow->getMinPktSndInt() * 0.9);
|
| - //if (m_ullInterval < minint)
|
| - // m_ullInterval = minint;
|
| -
|
| - uint64_t currtime;
|
| - CTimer::rdtsc(currtime);
|
| -
|
| - if ((currtime > m_ullNextACKTime) || ((m_pCC->m_iACKInterval > 0) && (m_pCC->m_iACKInterval <= m_iPktCount)))
|
| - {
|
| - // ACK timer expired or ACK interval is reached
|
| -
|
| - sendCtrl(2);
|
| - CTimer::rdtsc(currtime);
|
| - if (m_pCC->m_iACKPeriod > 0)
|
| - m_ullNextACKTime = currtime + m_pCC->m_iACKPeriod * m_ullCPUFrequency;
|
| - else
|
| - m_ullNextACKTime = currtime + m_ullACKInt;
|
| -
|
| - m_iPktCount = 0;
|
| - m_iLightACKCount = 1;
|
| - }
|
| - else if (m_iSelfClockInterval * m_iLightACKCount <= m_iPktCount)
|
| - {
|
| - //send a "light" ACK
|
| - sendCtrl(2, NULL, NULL, 4);
|
| - ++ m_iLightACKCount;
|
| - }
|
| -
|
| - // we are not sending back repeated NAK anymore and rely on the sender's EXP for retransmission
|
| - //if ((m_pRcvLossList->getLossLength() > 0) && (currtime > m_ullNextNAKTime))
|
| - //{
|
| - // // NAK timer expired, and there is loss to be reported.
|
| - // sendCtrl(3);
|
| - //
|
| - // CTimer::rdtsc(currtime);
|
| - // m_ullNextNAKTime = currtime + m_ullNAKInt;
|
| - //}
|
| -
|
| - if (currtime > m_ullNextEXPTime)
|
| - {
|
| - // Haven't receive any information from the peer, is it dead?!
|
| - // timeout: at least 16 expirations and must be greater than 10 seconds
|
| - if ((m_iEXPCount > 16) && (CTimer::getTime() - m_llLastRspTime > 10000000))
|
| - {
|
| - //
|
| - // Connection is broken.
|
| - // UDT does not signal any information about this instead of to stop quietly.
|
| - // Apllication will detect this when it calls any UDT methods next time.
|
| - //
|
| - m_bClosing = true;
|
| - m_bBroken = true;
|
| - m_iBrokenCounter = 30;
|
| -
|
| - // update snd U list to remove this socket
|
| - m_pSndQueue->m_pSndUList->update(this);
|
| -
|
| - releaseSynch();
|
| -
|
| - // a broken socket can be "write" to learn the error
|
| - s_UDTUnited.m_EPoll.enable_write(m_SocketID, m_sPollID);
|
| -
|
| - CTimer::triggerEvent();
|
| -
|
| - return;
|
| - }
|
| -
|
| - // sender: Insert all the packets sent after last received acknowledgement into the sender loss list.
|
| - // recver: Send out a keep-alive packet
|
| - if (m_pSndBuffer->getCurrBufSize() > 0)
|
| - {
|
| - if ((CSeqNo::incseq(m_iSndCurrSeqNo) != m_iSndLastAck) && (m_pSndLossList->getLossLength() == 0))
|
| - {
|
| - // resend all unacknowledged packets on timeout, but only if there is no packet in the loss list
|
| - int32_t csn = m_iSndCurrSeqNo;
|
| - int num = m_pSndLossList->insert(const_cast<int32_t&>(m_iSndLastAck), csn);
|
| - m_iTraceSndLoss += num;
|
| - m_iSndLossTotal += num;
|
| - }
|
| -
|
| - m_pCC->onTimeout();
|
| - // update CC parameters
|
| - m_ullInterval = (uint64_t)(m_pCC->m_dPktSndPeriod * m_ullCPUFrequency);
|
| - m_dCongestionWindow = m_pCC->m_dCWndSize;
|
| -
|
| - // immediately restart transmission
|
| - m_pSndQueue->m_pSndUList->update(this);
|
| - }
|
| - else
|
| - {
|
| - sendCtrl(1);
|
| - }
|
| -
|
| - ++ m_iEXPCount;
|
| - m_ullEXPInt = (m_iEXPCount * (m_iRTT + 4 * m_iRTTVar) + m_iSYNInterval) * m_ullCPUFrequency;
|
| - if (m_ullEXPInt < m_iEXPCount * m_ullMinExpInt)
|
| - m_ullEXPInt = m_iEXPCount * m_ullMinExpInt;
|
| - CTimer::rdtsc(m_ullNextEXPTime);
|
| - m_ullNextEXPTime += m_ullEXPInt;
|
| - }
|
| -}
|
| -
|
| -void CUDT::addEPoll(const int eid)
|
| -{
|
| - CGuard::enterCS(s_UDTUnited.m_EPoll.m_EPollLock);
|
| - m_sPollID.insert(eid);
|
| - CGuard::leaveCS(s_UDTUnited.m_EPoll.m_EPollLock);
|
| -
|
| - if (!m_bConnected || m_bBroken || m_bClosing)
|
| - return;
|
| -
|
| - if ((UDT_STREAM == m_iSockType) && (m_pRcvBuffer->getRcvDataSize() > 0))
|
| - s_UDTUnited.m_EPoll.enable_read(m_SocketID, m_sPollID);
|
| - else if ((UDT_DGRAM == m_iSockType) && (m_pRcvBuffer->getRcvMsgNum() > 0))
|
| - s_UDTUnited.m_EPoll.enable_read(m_SocketID, m_sPollID);
|
| -
|
| - if (m_iSndBufSize <= m_pSndBuffer->getCurrBufSize())
|
| - s_UDTUnited.m_EPoll.enable_write(m_SocketID, m_sPollID);
|
| -}
|
| -
|
| -void CUDT::removeEPoll(const int eid)
|
| -{
|
| - s_UDTUnited.m_EPoll.disable_read(m_SocketID, m_sPollID);
|
| - s_UDTUnited.m_EPoll.disable_write(m_SocketID, m_sPollID);
|
| -
|
| - CGuard::enterCS(s_UDTUnited.m_EPoll.m_EPollLock);
|
| - m_sPollID.erase(eid);
|
| - CGuard::leaveCS(s_UDTUnited.m_EPoll.m_EPollLock);
|
| -}
|
|
|