/*****************************************************************************
Copyright � 2001 - 2006, The Board of Trustees of the University of Illinois.
All Rights Reserved.
UDP-based Data Transfer Library (UDT) version 3
Laboratory for Advanced Computing (LAC)
National Center for Data Mining (NCDM)
University of Illinois at Chicago
http://www.lac.uic.edu/
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or (at
your option) any later version.
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*****************************************************************************/
/*****************************************************************************
This file contains the implementation of main algorithms of UDT protocol and
the implementation of core UDT interfaces.
Reference:
UDT programming manual
UDT protocol specification (draft-gg-udt-xx.txt)
*****************************************************************************/
/*****************************************************************************
written by
Yunhong Gu [gu@lac.uic.edu], last updated 12/09/2006
*****************************************************************************/
#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>
#endif
#include <cmath>
#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;
CUDT::CUDT():
//
// These constants are defined in UDT specification. They MUST NOT be changed!
//
m_iVersion(3),
m_iSYNInterval(10000),
m_iSelfClockInterval(64),
m_iQuickStartPkts(16)
{
m_pChannel = NULL;
m_pSndBuffer = NULL;
m_pRcvBuffer = NULL;
m_pSndLossList = NULL;
m_pRcvLossList = NULL;
m_pTimer = NULL;
m_pIrrPktList = NULL;
m_pACKWindow = NULL;
m_pSndTimeWindow = NULL;
m_pRcvTimeWindow = NULL;
// Initilize mutex and condition variables
initSynch();
// Default UDT configurations
m_iMSS = 1500;
m_bSynSending = true;
m_bSynRecving = true;
m_iFlightFlagSize = 25600;
m_iSndQueueLimit = 20000000;
m_iUDTBufSize = 20000000;
m_Linger.l_onoff = 1;
m_Linger.l_linger = 180;
m_iUDPSndBufSize = 65536;
m_iUDPRcvBufSize = 10000000;
m_iMaxMsg = 9000;
m_iMsgTTL = -1;
m_iIPversion = AF_INET;
m_bRendezvous = false;
m_iSndTimeOut = -1;
m_iRcvTimeOut = -1;
#ifdef CUSTOM_CC
m_pCCFactory = new CCCFactory<CCC>;
#else
m_pCCFactory = NULL;
#endif
m_pCC = NULL;
m_iRTT = 10 * m_iSYNInterval;
m_iRTTVar = m_iRTT >> 1;
m_ullCPUFrequency = CTimer::getCPUFrequency();
// Initial status
m_bOpened = false;
m_bConnected = false;
m_bBroken = false;
m_pcTmpBuf = NULL;
}
CUDT::CUDT(const CUDT& ancestor):
m_iVersion(ancestor.m_iVersion),
m_iSYNInterval(ancestor.m_iSYNInterval),
m_iSelfClockInterval(ancestor.m_iSelfClockInterval),
m_iQuickStartPkts(ancestor.m_iQuickStartPkts)
{
m_pChannel = NULL;
m_pSndBuffer = NULL;
m_pRcvBuffer = NULL;
m_pSndLossList = NULL;
m_pRcvLossList = NULL;
m_pTimer = NULL;
m_pIrrPktList = NULL;
m_pACKWindow = NULL;
m_pSndTimeWindow = NULL;
m_pRcvTimeWindow = 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_iSndQueueLimit = ancestor.m_iSndQueueLimit;
m_iUDTBufSize = ancestor.m_iUDTBufSize;
m_Linger = ancestor.m_Linger;
m_iUDPSndBufSize = ancestor.m_iUDPSndBufSize;
m_iUDPRcvBufSize = ancestor.m_iUDPRcvBufSize;
m_iMaxMsg = ancestor.m_iMaxMsg;
m_iMsgTTL = ancestor.m_iMsgTTL;
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;
#ifdef CUSTOM_CC
m_pCCFactory = ancestor.m_pCCFactory->clone();
#else
m_pCCFactory = NULL;
#endif
m_pCC = NULL;
m_iRTT = ancestor.m_iRTT;
m_iRTTVar = ancestor.m_iRTTVar;
m_ullCPUFrequency = ancestor.m_ullCPUFrequency;
// Initial status
m_bOpened = false;
m_bConnected = false;
m_bBroken = false;
m_pcTmpBuf = NULL;
}
CUDT::~CUDT()
{
// release mutex/condtion variables
destroySynch();
// destroy the data structures
if (m_pChannel)
delete m_pChannel;
if (m_pSndBuffer)
delete m_pSndBuffer;
if (m_pRcvBuffer)
delete m_pRcvBuffer;
if (m_pSndLossList)
delete m_pSndLossList;
if (m_pRcvLossList)
delete m_pRcvLossList;
if (m_pTimer)
delete m_pTimer;
if (m_pIrrPktList)
delete m_pIrrPktList;
if (m_pACKWindow)
delete m_pACKWindow;
if (m_pSndTimeWindow)
delete m_pSndTimeWindow;
if (m_pRcvTimeWindow)
delete m_pRcvTimeWindow;
if (m_pCCFactory)
delete m_pCCFactory;
if (m_pCC)
delete m_pCC;
if (m_pcTmpBuf)
delete [] m_pcTmpBuf;
}
void CUDT::setOpt(UDTOpt optName, const void* optval, const int&)
{
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 < 28)
throw CUDTException(5, 3, 0);
m_iMSS = *(int*)optval;
break;
case UDT_SNDSYN:
m_bSynSending = *(bool *)optval;
break;
case UDT_RCVSYN:
m_bSynRecving = *(bool *)optval;
break;
case UDT_CC:
#ifndef CUSTOM_CC
throw CUDTException(5, 0, 0);
#else
if (m_bOpened)
throw CUDTException(5, 1, 0);
if (NULL != m_pCCFactory)
delete m_pCCFactory;
m_pCCFactory = ((CCCVirtualFactory *)optval)->clone();
#endif
break;
case UDT_FC:
if (m_bConnected)
throw CUDTException(5, 2, 0);
if (*(int*)optval <= 0)
throw CUDTException(5, 3);
m_iFlightFlagSize = *(int*)optval;
break;
case UDT_SNDBUF:
if (m_bOpened)
throw CUDTException(5, 1, 0);
if (*(int*)optval <= 0)
throw CUDTException(5, 3, 0);
m_iSndQueueLimit = *(int*)optval;
break;
case UDT_RCVBUF:
if (m_bOpened)
throw CUDTException(5, 1, 0);
if (*(int*)optval <= 0)
throw CUDTException(5, 3, 0);
if (*(int*)optval > (m_iMSS - 28) * 16)
m_iUDTBufSize = *(int*)optval;
else
m_iUDTBufSize = (m_iMSS - 28) * 16;
break;
case UDT_LINGER:
m_Linger = *(linger*)optval;
break;
case UDP_SNDBUF:
if (m_bOpened)
throw CUDTException(5, 1, 0);
m_iUDPSndBufSize = *(int*)optval;
break;
case UDP_RCVBUF:
if (m_bOpened)
throw CUDTException(5, 1, 0);
m_iUDPRcvBufSize = *(int*)optval;
break;
case UDT_MAXMSG:
if (m_b