mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
SRT: Upgrade libsrt from 1.4.1 to 1.5.1. v6.0.12 (#3362)
Co-authored-by: winlin <winlin@vip.126.com>
This commit is contained in:
parent
7a56208f2f
commit
fe086dfc31
143 changed files with 38185 additions and 15108 deletions
360
trunk/3rdparty/srt-1-fit/srtcore/ATTIC/ccc.cpp
vendored
360
trunk/3rdparty/srt-1-fit/srtcore/ATTIC/ccc.cpp
vendored
|
@ -1,360 +0,0 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.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 02/21/2013
|
||||
modified by
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "core.h"
|
||||
#include "ccc.h"
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
CCC::CCC():
|
||||
m_iSYNInterval(CUDT::m_iSYNInterval),
|
||||
m_dPktSndPeriod(1.0),
|
||||
m_dCWndSize(16.0),
|
||||
m_iBandwidth(),
|
||||
m_dMaxCWndSize(),
|
||||
m_iMSS(),
|
||||
m_iSndCurrSeqNo(),
|
||||
m_iRcvRate(),
|
||||
m_iRTT(),
|
||||
m_pcParam(NULL),
|
||||
m_iPSize(0),
|
||||
m_UDT(),
|
||||
m_iACKPeriod(0),
|
||||
m_iACKInterval(0),
|
||||
m_bUserDefinedRTO(false),
|
||||
m_iRTO(-1),
|
||||
m_PerfInfo()
|
||||
{
|
||||
}
|
||||
|
||||
CCC::~CCC()
|
||||
{
|
||||
delete [] m_pcParam;
|
||||
}
|
||||
|
||||
void CCC::setACKTimer(int msINT)
|
||||
{
|
||||
m_iACKPeriod = msINT > m_iSYNInterval ? m_iSYNInterval : msINT;
|
||||
}
|
||||
|
||||
void CCC::setACKInterval(int pktINT)
|
||||
{
|
||||
m_iACKInterval = pktINT;
|
||||
}
|
||||
|
||||
void CCC::setRTO(int usRTO)
|
||||
{
|
||||
m_bUserDefinedRTO = true;
|
||||
m_iRTO = usRTO;
|
||||
}
|
||||
|
||||
void CCC::sendCustomMsg(CPacket& pkt) const
|
||||
{
|
||||
CUDT* u = CUDT::getUDTHandle(m_UDT);
|
||||
|
||||
if (NULL != u)
|
||||
{
|
||||
pkt.m_iID = u->m_PeerID;
|
||||
#ifdef SRT_ENABLE_CTRLTSTAMP
|
||||
pkt.m_iTimeStamp = int(CTimer::getTime() - u->m_StartTime);
|
||||
#endif
|
||||
u->m_pSndQueue->sendto(u->m_pPeerAddr, pkt);
|
||||
}
|
||||
}
|
||||
|
||||
const CPerfMon* CCC::getPerfInfo()
|
||||
{
|
||||
try
|
||||
{
|
||||
CUDT* u = CUDT::getUDTHandle(m_UDT);
|
||||
if (NULL != u)
|
||||
u->sample(&m_PerfInfo, false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &m_PerfInfo;
|
||||
}
|
||||
|
||||
void CCC::setMSS(int mss)
|
||||
{
|
||||
m_iMSS = mss;
|
||||
}
|
||||
|
||||
void CCC::setBandwidth(int bw)
|
||||
{
|
||||
m_iBandwidth = bw;
|
||||
}
|
||||
|
||||
void CCC::setSndCurrSeqNo(int32_t seqno)
|
||||
{
|
||||
m_iSndCurrSeqNo = seqno;
|
||||
}
|
||||
|
||||
void CCC::setRcvRate(int rcvrate)
|
||||
{
|
||||
m_iRcvRate = rcvrate;
|
||||
}
|
||||
|
||||
void CCC::setMaxCWndSize(int cwnd)
|
||||
{
|
||||
m_dMaxCWndSize = cwnd;
|
||||
}
|
||||
|
||||
void CCC::setRTT(int rtt)
|
||||
{
|
||||
m_iRTT = rtt;
|
||||
}
|
||||
|
||||
void CCC::setUserParam(const char* param, int size)
|
||||
{
|
||||
delete [] m_pcParam;
|
||||
m_pcParam = new char[size];
|
||||
memcpy(m_pcParam, param, size);
|
||||
m_iPSize = size;
|
||||
}
|
||||
|
||||
//
|
||||
CUDTCC::CUDTCC():
|
||||
m_iRCInterval(),
|
||||
m_LastRCTime(),
|
||||
m_bSlowStart(),
|
||||
m_iLastAck(),
|
||||
m_bLoss(),
|
||||
m_iLastDecSeq(),
|
||||
m_dLastDecPeriod(),
|
||||
m_iNAKCount(),
|
||||
m_iDecRandom(),
|
||||
m_iAvgNAKNum(),
|
||||
m_iDecCount()
|
||||
{
|
||||
}
|
||||
|
||||
void CUDTCC::init()
|
||||
{
|
||||
m_iRCInterval = m_iSYNInterval;
|
||||
m_LastRCTime = CTimer::getTime();
|
||||
setACKTimer(m_iRCInterval);
|
||||
|
||||
m_bSlowStart = true;
|
||||
m_iLastAck = m_iSndCurrSeqNo;
|
||||
m_bLoss = false;
|
||||
m_iLastDecSeq = CSeqNo::decseq(m_iLastAck);
|
||||
m_dLastDecPeriod = 1;
|
||||
m_iAvgNAKNum = 0;
|
||||
m_iNAKCount = 0;
|
||||
m_iDecRandom = 1;
|
||||
|
||||
m_dCWndSize = 16;
|
||||
m_dPktSndPeriod = 1;
|
||||
}
|
||||
|
||||
void CUDTCC::onACK(int32_t ack)
|
||||
{
|
||||
int64_t B = 0;
|
||||
double inc = 0;
|
||||
// Note: 1/24/2012
|
||||
// The minimum increase parameter is increased from "1.0 / m_iMSS" to 0.01
|
||||
// because the original was too small and caused sending rate to stay at low level
|
||||
// for long time.
|
||||
const double min_inc = 0.01;
|
||||
|
||||
uint64_t currtime = CTimer::getTime();
|
||||
if (currtime - m_LastRCTime < (uint64_t)m_iRCInterval)
|
||||
return;
|
||||
|
||||
m_LastRCTime = currtime;
|
||||
|
||||
#ifdef SRT_ENABLE_BSTATS
|
||||
//m_iRcvRate is bytes/sec
|
||||
if (m_bSlowStart)
|
||||
{
|
||||
m_dCWndSize += CSeqNo::seqlen(m_iLastAck, ack);
|
||||
m_iLastAck = ack;
|
||||
|
||||
if (m_dCWndSize > m_dMaxCWndSize)
|
||||
{
|
||||
m_bSlowStart = false;
|
||||
if (m_iRcvRate > 0)
|
||||
m_dPktSndPeriod = 1000000.0 / ((m_iRcvRate + m_iMSS - 1) / m_iMSS);
|
||||
else
|
||||
m_dPktSndPeriod = (m_iRTT + m_iRCInterval) / m_dCWndSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_dCWndSize = ((m_iRcvRate + m_iMSS -1) / m_iMSS) / 1000000.0 * (m_iRTT + m_iRCInterval) + 16;
|
||||
#else
|
||||
if (m_bSlowStart)
|
||||
{
|
||||
m_dCWndSize += CSeqNo::seqlen(m_iLastAck, ack);
|
||||
m_iLastAck = ack;
|
||||
|
||||
if (m_dCWndSize > m_dMaxCWndSize)
|
||||
{
|
||||
m_bSlowStart = false;
|
||||
if (m_iRcvRate > 0)
|
||||
m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
|
||||
else
|
||||
m_dPktSndPeriod = (m_iRTT + m_iRCInterval) / m_dCWndSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_dCWndSize = m_iRcvRate / 1000000.0 * (m_iRTT + m_iRCInterval) + 16;
|
||||
#endif
|
||||
|
||||
// During Slow Start, no rate increase
|
||||
if (m_bSlowStart)
|
||||
return;
|
||||
|
||||
if (m_bLoss)
|
||||
{
|
||||
m_bLoss = false;
|
||||
return;
|
||||
}
|
||||
|
||||
//m_iBandwidth is pkts/sec
|
||||
B = (int64_t)(m_iBandwidth - 1000000.0 / m_dPktSndPeriod);
|
||||
if ((m_dPktSndPeriod > m_dLastDecPeriod) && ((m_iBandwidth / 9) < B))
|
||||
B = m_iBandwidth / 9;
|
||||
if (B <= 0)
|
||||
inc = min_inc;
|
||||
else
|
||||
{
|
||||
// inc = max(10 ^ ceil(log10( B * MSS * 8 ) * Beta / MSS, 1/MSS)
|
||||
// Beta = 1.5 * 10^(-6)
|
||||
|
||||
inc = pow(10.0, ceil(log10(B * m_iMSS * 8.0))) * 0.0000015 / m_iMSS;
|
||||
|
||||
if (inc < min_inc)
|
||||
inc = min_inc;
|
||||
}
|
||||
|
||||
m_dPktSndPeriod = (m_dPktSndPeriod * m_iRCInterval) / (m_dPktSndPeriod * inc + m_iRCInterval);
|
||||
}
|
||||
|
||||
void CUDTCC::onLoss(const int32_t* losslist, int)
|
||||
{
|
||||
//Slow Start stopped, if it hasn't yet
|
||||
if (m_bSlowStart)
|
||||
{
|
||||
m_bSlowStart = false;
|
||||
if (m_iRcvRate > 0)
|
||||
{
|
||||
// Set the sending rate to the receiving rate.
|
||||
#ifdef SRT_ENABLE_BSTATS
|
||||
//Need average packet size here for better send period
|
||||
m_dPktSndPeriod = 1000000.0 / ((m_iRcvRate + m_iMSS - 1) / m_iMSS);
|
||||
#else
|
||||
m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
// If no receiving rate is observed, we have to compute the sending
|
||||
// rate according to the current window size, and decrease it
|
||||
// using the method below.
|
||||
m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval);
|
||||
}
|
||||
|
||||
m_bLoss = true;
|
||||
|
||||
if (CSeqNo::seqcmp(losslist[0] & 0x7FFFFFFF, m_iLastDecSeq) > 0)
|
||||
{
|
||||
m_dLastDecPeriod = m_dPktSndPeriod;
|
||||
m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.125);
|
||||
|
||||
m_iAvgNAKNum = (int)ceil(m_iAvgNAKNum * 0.875 + m_iNAKCount * 0.125);
|
||||
m_iNAKCount = 1;
|
||||
m_iDecCount = 1;
|
||||
|
||||
m_iLastDecSeq = m_iSndCurrSeqNo;
|
||||
|
||||
// remove global synchronization using randomization
|
||||
srand(m_iLastDecSeq);
|
||||
m_iDecRandom = (int)ceil(m_iAvgNAKNum * (double(rand()) / RAND_MAX));
|
||||
if (m_iDecRandom < 1)
|
||||
m_iDecRandom = 1;
|
||||
}
|
||||
else if ((m_iDecCount ++ < 5) && (0 == (++ m_iNAKCount % m_iDecRandom)))
|
||||
{
|
||||
// 0.875^5 = 0.51, rate should not be decreased by more than half within a congestion period
|
||||
m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.125);
|
||||
m_iLastDecSeq = m_iSndCurrSeqNo;
|
||||
}
|
||||
}
|
||||
|
||||
void CUDTCC::onTimeout()
|
||||
{
|
||||
if (m_bSlowStart)
|
||||
{
|
||||
m_bSlowStart = false;
|
||||
if (m_iRcvRate > 0)
|
||||
#ifdef SRT_ENABLE_BSTATS
|
||||
// Need average packet size here
|
||||
m_dPktSndPeriod = 1000000.0 / ((m_iRcvRate + m_iMSS - 1) / m_iMSS);
|
||||
#else
|
||||
m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
|
||||
#endif
|
||||
else
|
||||
m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
m_dLastDecPeriod = m_dPktSndPeriod;
|
||||
m_dPktSndPeriod = ceil(m_dPktSndPeriod * 2);
|
||||
m_iLastDecSeq = m_iLastAck;
|
||||
*/
|
||||
}
|
||||
}
|
219
trunk/3rdparty/srt-1-fit/srtcore/ATTIC/ccc.h
vendored
219
trunk/3rdparty/srt-1-fit/srtcore/ATTIC/ccc.h
vendored
|
@ -1,219 +0,0 @@
|
|||
/*****************************************************************************
|
||||
Copyright (c) 2001 - 2009, 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 02/28/2012
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef __UDT_CCC_H__
|
||||
#define __UDT_CCC_H__
|
||||
|
||||
|
||||
#include "udt.h"
|
||||
#include "packet.h"
|
||||
|
||||
|
||||
class UDT_API CCC
|
||||
{
|
||||
friend class CUDT;
|
||||
|
||||
public:
|
||||
CCC();
|
||||
virtual ~CCC();
|
||||
|
||||
private:
|
||||
CCC(const CCC&);
|
||||
CCC& operator=(const CCC&) {return *this;}
|
||||
|
||||
public:
|
||||
|
||||
/// Callback function to be called (only) at the start of a UDT connection.
|
||||
/// note that this is different from CCC(), which is always called.
|
||||
|
||||
virtual void init() {}
|
||||
|
||||
/// Callback function to be called when a UDT connection is closed.
|
||||
|
||||
virtual void close() {}
|
||||
|
||||
/// Callback function to be called when an ACK packet is received.
|
||||
/// @param [in] ackno the data sequence number acknowledged by this ACK.
|
||||
|
||||
virtual void onACK(int32_t) {}
|
||||
|
||||
/// Callback function to be called when a loss report is received.
|
||||
/// @param [in] losslist list of sequence number of packets, in the format describled in packet.cpp.
|
||||
/// @param [in] size length of the loss list.
|
||||
|
||||
virtual void onLoss(const int32_t*, int) {}
|
||||
|
||||
/// Callback function to be called when a timeout event occurs.
|
||||
|
||||
virtual void onTimeout() {}
|
||||
|
||||
/// Callback function to be called when a data is sent.
|
||||
/// @param [in] seqno the data sequence number.
|
||||
/// @param [in] size the payload size.
|
||||
|
||||
virtual void onPktSent(const CPacket*) {}
|
||||
|
||||
/// Callback function to be called when a data is received.
|
||||
/// @param [in] seqno the data sequence number.
|
||||
/// @param [in] size the payload size.
|
||||
|
||||
virtual void onPktReceived(const CPacket*) {}
|
||||
|
||||
/// Callback function to Process a user defined packet.
|
||||
/// @param [in] pkt the user defined packet.
|
||||
|
||||
virtual void processCustomMsg(const CPacket*) {}
|
||||
|
||||
protected:
|
||||
|
||||
/// Set periodical acknowldging and the ACK period.
|
||||
/// @param [in] msINT the period to send an ACK.
|
||||
|
||||
void setACKTimer(int msINT);
|
||||
|
||||
/// Set packet-based acknowldging and the number of packets to send an ACK.
|
||||
/// @param [in] pktINT the number of packets to send an ACK.
|
||||
|
||||
void setACKInterval(int pktINT);
|
||||
|
||||
/// Set RTO value.
|
||||
/// @param [in] msRTO RTO in macroseconds.
|
||||
|
||||
void setRTO(int usRTO);
|
||||
|
||||
/// Send a user defined control packet.
|
||||
/// @param [in] pkt user defined packet.
|
||||
|
||||
void sendCustomMsg(CPacket& pkt) const;
|
||||
|
||||
/// retrieve performance information.
|
||||
/// @return Pointer to a performance info structure.
|
||||
|
||||
const CPerfMon* getPerfInfo();
|
||||
|
||||
/// Set user defined parameters.
|
||||
/// @param [in] param the paramters in one buffer.
|
||||
/// @param [in] size the size of the buffer.
|
||||
|
||||
void setUserParam(const char* param, int size);
|
||||
|
||||
private:
|
||||
void setMSS(int mss);
|
||||
void setMaxCWndSize(int cwnd);
|
||||
void setBandwidth(int bw);
|
||||
void setSndCurrSeqNo(int32_t seqno);
|
||||
void setRcvRate(int rcvrate);
|
||||
void setRTT(int rtt);
|
||||
|
||||
protected:
|
||||
const int32_t& m_iSYNInterval; // UDT constant parameter, SYN
|
||||
|
||||
double m_dPktSndPeriod; // Packet sending period, in microseconds
|
||||
double m_dCWndSize; // Congestion window size, in packets
|
||||
|
||||
int m_iBandwidth; // estimated bandwidth, packets per second
|
||||
double m_dMaxCWndSize; // maximum cwnd size, in packets
|
||||
|
||||
int m_iMSS; // Maximum Packet Size, including all packet headers
|
||||
int32_t m_iSndCurrSeqNo; // current maximum seq no sent out
|
||||
int m_iRcvRate; // packet arrive rate at receiver side, packets per second
|
||||
int m_iRTT; // current estimated RTT, microsecond
|
||||
|
||||
char* m_pcParam; // user defined parameter
|
||||
int m_iPSize; // size of m_pcParam
|
||||
|
||||
private:
|
||||
UDTSOCKET m_UDT; // The UDT entity that this congestion control algorithm is bound to
|
||||
|
||||
int m_iACKPeriod; // Periodical timer to send an ACK, in milliseconds
|
||||
int m_iACKInterval; // How many packets to send one ACK, in packets
|
||||
|
||||
bool m_bUserDefinedRTO; // if the RTO value is defined by users
|
||||
int m_iRTO; // RTO value, microseconds
|
||||
|
||||
CPerfMon m_PerfInfo; // protocol statistics information
|
||||
};
|
||||
|
||||
class CCCVirtualFactory
|
||||
{
|
||||
public:
|
||||
virtual ~CCCVirtualFactory() {}
|
||||
|
||||
virtual CCC* create() = 0;
|
||||
virtual CCCVirtualFactory* clone() = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class CCCFactory: public CCCVirtualFactory
|
||||
{
|
||||
public:
|
||||
virtual ~CCCFactory() {}
|
||||
|
||||
virtual CCC* create() {return new T;}
|
||||
virtual CCCVirtualFactory* clone() {return new CCCFactory<T>;}
|
||||
};
|
||||
|
||||
class CUDTCC: public CCC
|
||||
{
|
||||
public:
|
||||
CUDTCC();
|
||||
|
||||
public:
|
||||
virtual void init();
|
||||
virtual void onACK(int32_t);
|
||||
virtual void onLoss(const int32_t*, int);
|
||||
virtual void onTimeout();
|
||||
|
||||
private:
|
||||
int m_iRCInterval; // UDT Rate control interval
|
||||
uint64_t m_LastRCTime; // last rate increase time
|
||||
bool m_bSlowStart; // if in slow start phase
|
||||
int32_t m_iLastAck; // last ACKed seq no
|
||||
bool m_bLoss; // if loss happened since last rate increase
|
||||
int32_t m_iLastDecSeq; // max pkt seq no sent out when last decrease happened
|
||||
double m_dLastDecPeriod; // value of pktsndperiod when last decrease happened
|
||||
int m_iNAKCount; // NAK counter
|
||||
int m_iDecRandom; // random threshold on decrease by number of loss events
|
||||
int m_iAvgNAKNum; // average number of NAKs per congestion
|
||||
int m_iDecCount; // number of decreases in a congestion epoch
|
||||
};
|
||||
|
||||
#endif
|
79
trunk/3rdparty/srt-1-fit/srtcore/access_control.h
vendored
Normal file
79
trunk/3rdparty/srt-1-fit/srtcore/access_control.h
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2020 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
written by
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC_F_ACCESS_CONTROL_H
|
||||
#define INC_F_ACCESS_CONTROL_H
|
||||
|
||||
// A list of rejection codes that are SRT specific.
|
||||
|
||||
#define SRT_REJX_FALLBACK 1000 // A code used in case when the application wants to report some problem, but can't precisely specify it.
|
||||
#define SRT_REJX_KEY_NOTSUP 1001 // The key used in the StreamID keyed string is not supported by the service.
|
||||
#define SRT_REJX_FILEPATH 1002 // The resource type designates a file and the path is either wrong syntax or not found
|
||||
#define SRT_REJX_HOSTNOTFOUND 1003 // The `h` host specification was not recognized by the service
|
||||
|
||||
// The list of http codes adopted for SRT.
|
||||
// An example C++ header for HTTP codes can be found at:
|
||||
// https://github.com/j-ulrich/http-status-codes-cpp
|
||||
|
||||
// Some of the unused code can be revived in the future, if there
|
||||
// happens to be a good reason for it.
|
||||
|
||||
#define SRT_REJX_BAD_REQUEST 1400 // General syntax error in the SocketID specification (also a fallback code for undefined cases)
|
||||
#define SRT_REJX_UNAUTHORIZED 1401 // Authentication failed, provided that the user was correctly identified and access to the required resource would be granted
|
||||
#define SRT_REJX_OVERLOAD 1402 // The server is too heavily loaded, or you have exceeded credits for accessing the service and the resource.
|
||||
#define SRT_REJX_FORBIDDEN 1403 // Access denied to the resource by any kind of reason.
|
||||
#define SRT_REJX_NOTFOUND 1404 // Resource not found at this time.
|
||||
#define SRT_REJX_BAD_MODE 1405 // The mode specified in `m` key in StreamID is not supported for this request.
|
||||
#define SRT_REJX_UNACCEPTABLE 1406 // The requested parameters specified in SocketID cannot be satisfied for the requested resource. Also when m=publish and the data format is not acceptable.
|
||||
// CODE NOT IN USE 407: unused: proxy functionality not predicted
|
||||
// CODE NOT IN USE 408: unused: no timeout predicted for listener callback
|
||||
#define SRT_REJX_CONFLICT 1409 // The resource being accessed is already locked for modification. This is in case of m=publish and the specified resource is currently read-only.
|
||||
// CODE NOT IN USE 410: unused: treated as a specific case of 404
|
||||
// CODE NOT IN USE 411: unused: no reason to include lenght in the protocol
|
||||
// CODE NOT IN USE 412: unused: preconditions not predicted in AC
|
||||
// CODE NOT IN USE 413: unused: AC size is already defined as 512
|
||||
// CODE NOT IN USE 414: unused: AC size is already defined as 512
|
||||
#define SRT_REJX_NOTSUP_MEDIA 1415 // The media type is not supported by the application. This is the `t` key that specifies the media type as stream, file and auth, possibly extended by the application.
|
||||
// CODE NOT IN USE 416: unused: no detailed specification defined
|
||||
// CODE NOT IN USE 417: unused: expectations not supported
|
||||
// CODE NOT IN USE 418: unused: sharks do not drink tea
|
||||
// CODE NOT IN USE 419: not defined in HTTP
|
||||
// CODE NOT IN USE 420: not defined in HTTP
|
||||
// CODE NOT IN USE 421: unused: misdirection not supported
|
||||
// CODE NOT IN USE 422: unused: aligned to general 400
|
||||
#define SRT_REJX_LOCKED 1423 // The resource being accessed is locked for any access.
|
||||
#define SRT_REJX_FAILED_DEPEND 1424 // The request failed because it specified a dependent session ID that has been disconnected.
|
||||
// CODE NOT IN USE 425: unused: replaying not supported
|
||||
// CODE NOT IN USE 426: unused: tempting, but it requires resend in connected
|
||||
// CODE NOT IN USE 427: not defined in HTTP
|
||||
// CODE NOT IN USE 428: unused: renders to 409
|
||||
// CODE NOT IN USE 429: unused: renders to 402
|
||||
// CODE NOT IN USE 451: unused: renders to 403
|
||||
#define SRT_REJX_ISE 1500 // Unexpected internal server error
|
||||
#define SRT_REJX_UNIMPLEMENTED 1501 // The request was recognized, but the current version doesn't support it.
|
||||
#define SRT_REJX_GW 1502 // The server acts as a gateway and the target endpoint rejected the connection.
|
||||
#define SRT_REJX_DOWN 1503 // The service has been temporarily taken over by a stub reporting this error. The real service can be down for maintenance or crashed.
|
||||
// CODE NOT IN USE 504: unused: timeout not supported
|
||||
#define SRT_REJX_VERSION 1505 // SRT version not supported. This might be either unsupported backward compatibility, or an upper value of a version.
|
||||
// CODE NOT IN USE 506: unused: negotiation and references not supported
|
||||
#define SRT_REJX_NOROOM 1507 // The data stream cannot be archived due to lacking storage space. This is in case when the request type was to send a file or the live stream to be archived.
|
||||
// CODE NOT IN USE 508: unused: no redirection supported
|
||||
// CODE NOT IN USE 509: not defined in HTTP
|
||||
// CODE NOT IN USE 510: unused: extensions not supported
|
||||
// CODE NOT IN USE 511: unused: intercepting proxies not supported
|
||||
|
||||
|
||||
|
||||
#endif
|
6274
trunk/3rdparty/srt-1-fit/srtcore/api.cpp
vendored
6274
trunk/3rdparty/srt-1-fit/srtcore/api.cpp
vendored
File diff suppressed because it is too large
Load diff
603
trunk/3rdparty/srt-1-fit/srtcore/api.h
vendored
603
trunk/3rdparty/srt-1-fit/srtcore/api.h
vendored
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -45,14 +45,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
/*****************************************************************************
|
||||
written by
|
||||
Yunhong Gu, last updated 09/28/2010
|
||||
Yunhong Gu, last updated 09/28/2010
|
||||
modified by
|
||||
Haivision Systems Inc.
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_API_H__
|
||||
#define __UDT_API_H__
|
||||
|
||||
#ifndef INC_SRT_API_H
|
||||
#define INC_SRT_API_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
@ -64,237 +63,425 @@ modified by
|
|||
#include "cache.h"
|
||||
#include "epoll.h"
|
||||
#include "handshake.h"
|
||||
#include "core.h"
|
||||
#if ENABLE_BONDING
|
||||
#include "group.h"
|
||||
#endif
|
||||
|
||||
// Please refer to structure and locking information provided in the
|
||||
// docs/dev/low-level-info.md document.
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
class CUDT;
|
||||
|
||||
/// @brief Class CUDTSocket is a control layer on top of the CUDT core functionality layer.
|
||||
/// CUDTSocket owns CUDT.
|
||||
class CUDTSocket
|
||||
{
|
||||
public:
|
||||
CUDTSocket();
|
||||
~CUDTSocket();
|
||||
CUDTSocket()
|
||||
: m_Status(SRTS_INIT)
|
||||
, m_SocketID(0)
|
||||
, m_ListenSocket(0)
|
||||
, m_PeerID(0)
|
||||
#if ENABLE_BONDING
|
||||
, m_GroupMemberData()
|
||||
, m_GroupOf()
|
||||
#endif
|
||||
, m_iISN(0)
|
||||
, m_UDT(this)
|
||||
, m_AcceptCond()
|
||||
, m_AcceptLock()
|
||||
, m_uiBackLog(0)
|
||||
, m_iMuxID(-1)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
SRT_SOCKSTATUS m_Status; //< current socket state
|
||||
CUDTSocket(const CUDTSocket& ancestor)
|
||||
: m_Status(SRTS_INIT)
|
||||
, m_SocketID(0)
|
||||
, m_ListenSocket(0)
|
||||
, m_PeerID(0)
|
||||
#if ENABLE_BONDING
|
||||
, m_GroupMemberData()
|
||||
, m_GroupOf()
|
||||
#endif
|
||||
, m_iISN(0)
|
||||
, m_UDT(this, ancestor.m_UDT)
|
||||
, m_AcceptCond()
|
||||
, m_AcceptLock()
|
||||
, m_uiBackLog(0)
|
||||
, m_iMuxID(-1)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
/// Time when the socket is closed.
|
||||
/// When the socket is closed, it is not removed immediately from the list
|
||||
/// of sockets in order to prevent other methods from accessing invalid address.
|
||||
/// A timer is started and the socket will be removed after approximately
|
||||
/// 1 second (see CUDTUnited::checkBrokenSockets()).
|
||||
uint64_t m_ClosureTimeStamp;
|
||||
~CUDTSocket();
|
||||
|
||||
int m_iIPversion; //< IP version
|
||||
sockaddr* m_pSelfAddr; //< pointer to the local address of the socket
|
||||
sockaddr* m_pPeerAddr; //< pointer to the peer address of the socket
|
||||
void construct();
|
||||
|
||||
SRTSOCKET m_SocketID; //< socket ID
|
||||
SRTSOCKET m_ListenSocket; //< ID of the listener socket; 0 means this is an independent socket
|
||||
SRT_ATTR_GUARDED_BY(m_ControlLock)
|
||||
sync::atomic<SRT_SOCKSTATUS> m_Status; //< current socket state
|
||||
|
||||
SRTSOCKET m_PeerID; //< peer socket ID
|
||||
int32_t m_iISN; //< initial sequence number, used to tell different connection from same IP:port
|
||||
/// Time when the socket is closed.
|
||||
/// When the socket is closed, it is not removed immediately from the list
|
||||
/// of sockets in order to prevent other methods from accessing invalid address.
|
||||
/// A timer is started and the socket will be removed after approximately
|
||||
/// 1 second (see CUDTUnited::checkBrokenSockets()).
|
||||
sync::steady_clock::time_point m_tsClosureTimeStamp;
|
||||
|
||||
CUDT* m_pUDT; //< pointer to the UDT entity
|
||||
sockaddr_any m_SelfAddr; //< local address of the socket
|
||||
sockaddr_any m_PeerAddr; //< peer address of the socket
|
||||
|
||||
std::set<SRTSOCKET>* m_pQueuedSockets; //< set of connections waiting for accept()
|
||||
std::set<SRTSOCKET>* m_pAcceptSockets; //< set of accept()ed connections
|
||||
SRTSOCKET m_SocketID; //< socket ID
|
||||
SRTSOCKET m_ListenSocket; //< ID of the listener socket; 0 means this is an independent socket
|
||||
|
||||
pthread_cond_t m_AcceptCond; //< used to block "accept" call
|
||||
pthread_mutex_t m_AcceptLock; //< mutex associated to m_AcceptCond
|
||||
SRTSOCKET m_PeerID; //< peer socket ID
|
||||
#if ENABLE_BONDING
|
||||
groups::SocketData* m_GroupMemberData; //< Pointer to group member data, or NULL if not a group member
|
||||
CUDTGroup* m_GroupOf; //< Group this socket is a member of, or NULL if it isn't
|
||||
#endif
|
||||
|
||||
unsigned int m_uiBackLog; //< maximum number of connections in queue
|
||||
|
||||
int m_iMuxID; //< multiplexer ID
|
||||
|
||||
pthread_mutex_t m_ControlLock; //< lock this socket exclusively for control APIs: bind/listen/connect
|
||||
|
||||
static int64_t getPeerSpec(SRTSOCKET id, int32_t isn)
|
||||
{
|
||||
return (id << 30) + isn;
|
||||
}
|
||||
int64_t getPeerSpec()
|
||||
{
|
||||
return getPeerSpec(m_PeerID, m_iISN);
|
||||
}
|
||||
int32_t m_iISN; //< initial sequence number, used to tell different connection from same IP:port
|
||||
|
||||
private:
|
||||
CUDTSocket(const CUDTSocket&);
|
||||
CUDTSocket& operator=(const CUDTSocket&);
|
||||
CUDT m_UDT; //< internal SRT socket logic
|
||||
|
||||
public:
|
||||
std::set<SRTSOCKET> m_QueuedSockets; //< set of connections waiting for accept()
|
||||
|
||||
sync::Condition m_AcceptCond; //< used to block "accept" call
|
||||
sync::Mutex m_AcceptLock; //< mutex associated to m_AcceptCond
|
||||
|
||||
unsigned int m_uiBackLog; //< maximum number of connections in queue
|
||||
|
||||
// XXX A refactoring might be needed here.
|
||||
|
||||
// There are no reasons found why the socket can't contain a list iterator to a
|
||||
// multiplexer INSTEAD of m_iMuxID. There's no danger in this solution because
|
||||
// the multiplexer is never deleted until there's at least one socket using it.
|
||||
//
|
||||
// The multiplexer may even physically be contained in the CUDTUnited object,
|
||||
// just track the multiple users of it (the listener and the accepted sockets).
|
||||
// When deleting, you simply "unsubscribe" yourself from the multiplexer, which
|
||||
// will unref it and remove the list element by the iterator kept by the
|
||||
// socket.
|
||||
int m_iMuxID; //< multiplexer ID
|
||||
|
||||
sync::Mutex m_ControlLock; //< lock this socket exclusively for control APIs: bind/listen/connect
|
||||
|
||||
CUDT& core() { return m_UDT; }
|
||||
const CUDT& core() const { return m_UDT; }
|
||||
|
||||
static int64_t getPeerSpec(SRTSOCKET id, int32_t isn) { return (int64_t(id) << 30) + isn; }
|
||||
int64_t getPeerSpec() { return getPeerSpec(m_PeerID, m_iISN); }
|
||||
|
||||
SRT_SOCKSTATUS getStatus();
|
||||
|
||||
/// This function shall be called always wherever
|
||||
/// you'd like to call cudtsocket->m_pUDT->close(),
|
||||
/// from within the GC thread only (that is, only when
|
||||
/// the socket should be no longer visible in the
|
||||
/// connection, including for sending remaining data).
|
||||
void breakSocket_LOCKED();
|
||||
|
||||
/// This makes the socket no longer capable of performing any transmission
|
||||
/// operation, but continues to be responsive in the connection in order
|
||||
/// to finish sending the data that were scheduled for sending so far.
|
||||
void setClosed();
|
||||
|
||||
/// This does the same as setClosed, plus sets the m_bBroken to true.
|
||||
/// Such a socket can still be read from so that remaining data from
|
||||
/// the receiver buffer can be read, but no longer sends anything.
|
||||
void setBrokenClosed();
|
||||
void removeFromGroup(bool broken);
|
||||
|
||||
// Instrumentally used by select() and also required for non-blocking
|
||||
// mode check in groups
|
||||
bool readReady();
|
||||
bool writeReady() const;
|
||||
bool broken() const;
|
||||
|
||||
private:
|
||||
CUDTSocket& operator=(const CUDTSocket&);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CUDTUnited
|
||||
{
|
||||
friend class CUDT;
|
||||
friend class CRendezvousQueue;
|
||||
friend class CUDT;
|
||||
friend class CUDTGroup;
|
||||
friend class CRendezvousQueue;
|
||||
friend class CCryptoControl;
|
||||
|
||||
public:
|
||||
CUDTUnited();
|
||||
~CUDTUnited();
|
||||
CUDTUnited();
|
||||
~CUDTUnited();
|
||||
|
||||
// Public constants
|
||||
static const int32_t MAX_SOCKET_VAL = SRTGROUP_MASK - 1; // maximum value for a regular socket
|
||||
|
||||
public:
|
||||
|
||||
static std::string CONID(SRTSOCKET sock);
|
||||
|
||||
/// initialize the UDT library.
|
||||
/// @return 0 if success, otherwise -1 is returned.
|
||||
|
||||
int startup();
|
||||
|
||||
/// release the UDT library.
|
||||
/// @return 0 if success, otherwise -1 is returned.
|
||||
|
||||
int cleanup();
|
||||
|
||||
/// Create a new UDT socket.
|
||||
/// @param [in] af IP version, IPv4 (AF_INET) or IPv6 (AF_INET6).
|
||||
/// @param [in] type (ignored)
|
||||
/// @return The new UDT socket ID, or INVALID_SOCK.
|
||||
|
||||
SRTSOCKET newSocket(int af, int );
|
||||
|
||||
/// Create a new UDT connection.
|
||||
/// @param [in] listen the listening UDT socket;
|
||||
/// @param [in] peer peer address.
|
||||
/// @param [in,out] hs handshake information from peer side (in), negotiated value (out);
|
||||
/// @return If the new connection is successfully created: 1 success, 0 already exist, -1 error.
|
||||
|
||||
int newConnection(const SRTSOCKET listen, const sockaddr* peer, CHandShake* hs, const CPacket& hspkt,
|
||||
ref_t<SRT_REJECT_REASON> r_error);
|
||||
|
||||
int installAcceptHook(const SRTSOCKET lsn, srt_listen_callback_fn* hook, void* opaq);
|
||||
|
||||
/// look up the UDT entity according to its ID.
|
||||
/// @param [in] u the UDT socket ID.
|
||||
/// @return Pointer to the UDT entity.
|
||||
|
||||
CUDT* lookup(const SRTSOCKET u);
|
||||
|
||||
/// Check the status of the UDT socket.
|
||||
/// @param [in] u the UDT socket ID.
|
||||
/// @return UDT socket status, or NONEXIST if not found.
|
||||
|
||||
SRT_SOCKSTATUS getStatus(const SRTSOCKET u);
|
||||
|
||||
// socket APIs
|
||||
|
||||
int bind(const SRTSOCKET u, const sockaddr* name, int namelen);
|
||||
int bind(const SRTSOCKET u, UDPSOCKET udpsock);
|
||||
int listen(const SRTSOCKET u, int backlog);
|
||||
SRTSOCKET accept(const SRTSOCKET listen, sockaddr* addr, int* addrlen);
|
||||
int connect(const SRTSOCKET u, const sockaddr* name, int namelen, int32_t forced_isn);
|
||||
int close(const SRTSOCKET u);
|
||||
int getpeername(const SRTSOCKET u, sockaddr* name, int* namelen);
|
||||
int getsockname(const SRTSOCKET u, sockaddr* name, int* namelen);
|
||||
int select(ud_set* readfds, ud_set* writefds, ud_set* exceptfds, const timeval* timeout);
|
||||
int selectEx(const std::vector<SRTSOCKET>& fds, std::vector<SRTSOCKET>* readfds, std::vector<SRTSOCKET>* writefds, std::vector<SRTSOCKET>* exceptfds, int64_t msTimeOut);
|
||||
int epoll_create();
|
||||
int epoll_add_usock(const int eid, const SRTSOCKET u, const int* events = NULL);
|
||||
int epoll_add_ssock(const int eid, const SYSSOCKET s, const int* events = NULL);
|
||||
int epoll_remove_usock(const int eid, const SRTSOCKET u);
|
||||
int epoll_remove_ssock(const int eid, const SYSSOCKET s);
|
||||
int epoll_update_usock(const int eid, const SRTSOCKET u, const int* events = NULL);
|
||||
int epoll_update_ssock(const int eid, const SYSSOCKET s, const int* events = NULL);
|
||||
int epoll_wait(const int eid, std::set<SRTSOCKET>* readfds, std::set<SRTSOCKET>* writefds, int64_t msTimeOut, std::set<SYSSOCKET>* lrfds = NULL, std::set<SYSSOCKET>* lwfds = NULL);
|
||||
int epoll_uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut);
|
||||
int32_t epoll_set(const int eid, int32_t flags);
|
||||
int epoll_release(const int eid);
|
||||
|
||||
/// record the UDT exception.
|
||||
/// @param [in] e pointer to a UDT exception instance.
|
||||
|
||||
void setError(CUDTException* e);
|
||||
|
||||
/// look up the most recent UDT exception.
|
||||
/// @return pointer to a UDT exception instance.
|
||||
|
||||
CUDTException* getError();
|
||||
|
||||
private:
|
||||
// void init();
|
||||
|
||||
private:
|
||||
std::map<SRTSOCKET, CUDTSocket*> m_Sockets; // stores all the socket structures
|
||||
|
||||
pthread_mutex_t m_ControlLock; // used to synchronize UDT API
|
||||
|
||||
pthread_mutex_t m_IDLock; // used to synchronize ID generation
|
||||
SRTSOCKET m_SocketIDGenerator; // seed to generate a new unique socket ID
|
||||
|
||||
std::map<int64_t, std::set<SRTSOCKET> > m_PeerRec;// record sockets from peers to avoid repeated connection request, int64_t = (socker_id << 30) + isn
|
||||
|
||||
private:
|
||||
pthread_key_t m_TLSError; // thread local error record (last error)
|
||||
static void TLSDestroy(void* e) {if (NULL != e) delete (CUDTException*)e;}
|
||||
|
||||
private:
|
||||
CUDTSocket* locate(const SRTSOCKET u);
|
||||
CUDTSocket* locate(const sockaddr* peer, const SRTSOCKET id, int32_t isn);
|
||||
void updateMux(CUDTSocket* s, const sockaddr* addr = NULL, const UDPSOCKET* = NULL);
|
||||
void updateListenerMux(CUDTSocket* s, const CUDTSocket* ls);
|
||||
|
||||
private:
|
||||
std::map<int, CMultiplexer> m_mMultiplexer; // UDP multiplexer
|
||||
pthread_mutex_t m_MultiplexerLock;
|
||||
|
||||
private:
|
||||
CCache<CInfoBlock>* m_pCache; // UDT network information cache
|
||||
|
||||
private:
|
||||
volatile bool m_bClosing;
|
||||
pthread_mutex_t m_GCStopLock;
|
||||
pthread_cond_t m_GCStopCond;
|
||||
|
||||
pthread_mutex_t m_InitLock;
|
||||
int m_iInstanceCount; // number of startup() called by application
|
||||
bool m_bGCStatus; // if the GC thread is working (true)
|
||||
|
||||
pthread_t m_GCThread;
|
||||
static void* garbageCollect(void*);
|
||||
|
||||
std::map<SRTSOCKET, CUDTSocket*> m_ClosedSockets; // temporarily store closed sockets
|
||||
|
||||
void checkBrokenSockets();
|
||||
void removeSocket(const SRTSOCKET u);
|
||||
|
||||
CEPoll m_EPoll; // handling epoll data structures and events
|
||||
|
||||
private:
|
||||
CUDTUnited(const CUDTUnited&);
|
||||
CUDTUnited& operator=(const CUDTUnited&);
|
||||
};
|
||||
|
||||
// Debug support
|
||||
inline std::string SockaddrToString(const sockaddr* sadr)
|
||||
{
|
||||
void* addr =
|
||||
sadr->sa_family == AF_INET ?
|
||||
(void*)&((sockaddr_in*)sadr)->sin_addr
|
||||
: sadr->sa_family == AF_INET6 ?
|
||||
(void*)&((sockaddr_in6*)sadr)->sin6_addr
|
||||
: 0;
|
||||
// (cast to (void*) is required because otherwise the 2-3 arguments
|
||||
// of ?: operator would have different types, which isn't allowed in C++.
|
||||
if ( !addr )
|
||||
return "unknown:0";
|
||||
|
||||
std::ostringstream output;
|
||||
char hostbuf[1024];
|
||||
int flags;
|
||||
|
||||
#if ENABLE_GETNAMEINFO
|
||||
flags = NI_NAMEREQD;
|
||||
#else
|
||||
flags = NI_NUMERICHOST | NI_NUMERICSERV;
|
||||
#endif
|
||||
|
||||
if (!getnameinfo(sadr, sizeof(*sadr), hostbuf, 1024, NULL, 0, flags))
|
||||
enum ErrorHandling
|
||||
{
|
||||
output << hostbuf;
|
||||
ERH_RETURN,
|
||||
ERH_THROW,
|
||||
ERH_ABORT
|
||||
};
|
||||
static std::string CONID(SRTSOCKET sock);
|
||||
|
||||
/// initialize the UDT library.
|
||||
/// @return 0 if success, otherwise -1 is returned.
|
||||
int startup();
|
||||
|
||||
/// release the UDT library.
|
||||
/// @return 0 if success, otherwise -1 is returned.
|
||||
int cleanup();
|
||||
|
||||
/// Create a new UDT socket.
|
||||
/// @param [out] pps Variable (optional) to which the new socket will be written, if succeeded
|
||||
/// @return The new UDT socket ID, or INVALID_SOCK.
|
||||
SRTSOCKET newSocket(CUDTSocket** pps = NULL);
|
||||
|
||||
/// Create (listener-side) a new socket associated with the incoming connection request.
|
||||
/// @param [in] listen the listening socket ID.
|
||||
/// @param [in] peer peer address.
|
||||
/// @param [in,out] hs handshake information from peer side (in), negotiated value (out);
|
||||
/// @param [out] w_error error code in case of failure.
|
||||
/// @param [out] w_acpu reference to the existing associated socket if already exists.
|
||||
/// @return 1: if the new connection was successfully created (accepted), @a w_acpu is NULL;
|
||||
/// 0: the connection already exists (reference to the corresponding socket is returned in @a w_acpu).
|
||||
/// -1: The connection processing failed due to memory alloation error, exceeding listener's backlog,
|
||||
/// any error propagated from CUDT::open and CUDT::acceptAndRespond.
|
||||
int newConnection(const SRTSOCKET listen,
|
||||
const sockaddr_any& peer,
|
||||
const CPacket& hspkt,
|
||||
CHandShake& w_hs,
|
||||
int& w_error,
|
||||
CUDT*& w_acpu);
|
||||
|
||||
int installAcceptHook(const SRTSOCKET lsn, srt_listen_callback_fn* hook, void* opaq);
|
||||
int installConnectHook(const SRTSOCKET lsn, srt_connect_callback_fn* hook, void* opaq);
|
||||
|
||||
/// Check the status of the UDT socket.
|
||||
/// @param [in] u the UDT socket ID.
|
||||
/// @return UDT socket status, or NONEXIST if not found.
|
||||
SRT_SOCKSTATUS getStatus(const SRTSOCKET u);
|
||||
|
||||
// socket APIs
|
||||
|
||||
int bind(CUDTSocket* u, const sockaddr_any& name);
|
||||
int bind(CUDTSocket* u, UDPSOCKET udpsock);
|
||||
int listen(const SRTSOCKET u, int backlog);
|
||||
SRTSOCKET accept(const SRTSOCKET listen, sockaddr* addr, int* addrlen);
|
||||
SRTSOCKET accept_bond(const SRTSOCKET listeners[], int lsize, int64_t msTimeOut);
|
||||
int connect(SRTSOCKET u, const sockaddr* srcname, const sockaddr* tarname, int tarlen);
|
||||
int connect(const SRTSOCKET u, const sockaddr* name, int namelen, int32_t forced_isn);
|
||||
int connectIn(CUDTSocket* s, const sockaddr_any& target, int32_t forced_isn);
|
||||
#if ENABLE_BONDING
|
||||
int groupConnect(CUDTGroup* g, SRT_SOCKGROUPCONFIG targets[], int arraysize);
|
||||
int singleMemberConnect(CUDTGroup* g, SRT_SOCKGROUPCONFIG* target);
|
||||
#endif
|
||||
int close(const SRTSOCKET u);
|
||||
int close(CUDTSocket* s);
|
||||
void getpeername(const SRTSOCKET u, sockaddr* name, int* namelen);
|
||||
void getsockname(const SRTSOCKET u, sockaddr* name, int* namelen);
|
||||
int select(UDT::UDSET* readfds, UDT::UDSET* writefds, UDT::UDSET* exceptfds, const timeval* timeout);
|
||||
int selectEx(const std::vector<SRTSOCKET>& fds,
|
||||
std::vector<SRTSOCKET>* readfds,
|
||||
std::vector<SRTSOCKET>* writefds,
|
||||
std::vector<SRTSOCKET>* exceptfds,
|
||||
int64_t msTimeOut);
|
||||
int epoll_create();
|
||||
int epoll_clear_usocks(int eid);
|
||||
int epoll_add_usock(const int eid, const SRTSOCKET u, const int* events = NULL);
|
||||
int epoll_add_usock_INTERNAL(const int eid, CUDTSocket* s, const int* events);
|
||||
int epoll_add_ssock(const int eid, const SYSSOCKET s, const int* events = NULL);
|
||||
int epoll_remove_usock(const int eid, const SRTSOCKET u);
|
||||
template <class EntityType>
|
||||
int epoll_remove_entity(const int eid, EntityType* ent);
|
||||
int epoll_remove_socket_INTERNAL(const int eid, CUDTSocket* ent);
|
||||
#if ENABLE_BONDING
|
||||
int epoll_remove_group_INTERNAL(const int eid, CUDTGroup* ent);
|
||||
#endif
|
||||
int epoll_remove_ssock(const int eid, const SYSSOCKET s);
|
||||
int epoll_update_ssock(const int eid, const SYSSOCKET s, const int* events = NULL);
|
||||
int epoll_uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut);
|
||||
int32_t epoll_set(const int eid, int32_t flags);
|
||||
int epoll_release(const int eid);
|
||||
|
||||
#if ENABLE_BONDING
|
||||
// [[using locked(m_GlobControlLock)]]
|
||||
CUDTGroup& addGroup(SRTSOCKET id, SRT_GROUP_TYPE type)
|
||||
{
|
||||
// This only ensures that the element exists.
|
||||
// If the element was newly added, it will be NULL.
|
||||
CUDTGroup*& g = m_Groups[id];
|
||||
if (!g)
|
||||
{
|
||||
// This is a reference to the cell, so it will
|
||||
// rewrite it into the map.
|
||||
g = new CUDTGroup(type);
|
||||
}
|
||||
|
||||
// Now we are sure that g is not NULL,
|
||||
// and persistence of this object is in the map.
|
||||
// The reference to the object can be safely returned here.
|
||||
return *g;
|
||||
}
|
||||
|
||||
output << ":" << ntohs(((sockaddr_in*)sadr)->sin_port); // TRICK: sin_port and sin6_port have the same offset and size
|
||||
return output.str();
|
||||
}
|
||||
void deleteGroup(CUDTGroup* g);
|
||||
void deleteGroup_LOCKED(CUDTGroup* g);
|
||||
|
||||
// [[using locked(m_GlobControlLock)]]
|
||||
CUDTGroup* findPeerGroup_LOCKED(SRTSOCKET peergroup)
|
||||
{
|
||||
for (groups_t::iterator i = m_Groups.begin(); i != m_Groups.end(); ++i)
|
||||
{
|
||||
if (i->second->peerid() == peergroup)
|
||||
return i->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
CEPoll& epoll_ref() { return m_EPoll; }
|
||||
|
||||
private:
|
||||
/// Generates a new socket ID. This function starts from a randomly
|
||||
/// generated value (at initialization time) and goes backward with
|
||||
/// with next calls. The possible values come from the range without
|
||||
/// the SRTGROUP_MASK bit, and the group bit is set when the ID is
|
||||
/// generated for groups. It is also internally checked if the
|
||||
/// newly generated ID isn't already used by an existing socket or group.
|
||||
///
|
||||
/// Socket ID value range.
|
||||
/// - [0]: reserved for handshake procedure. If the destination Socket ID is 0
|
||||
/// (destination Socket ID unknown) the packet will be sent to the listening socket
|
||||
/// or to a socket that is in the rendezvous connection phase.
|
||||
/// - [1; 2 ^ 30): single socket ID range.
|
||||
/// - (2 ^ 30; 2 ^ 31): group socket ID range. Effectively any positive number
|
||||
/// from [1; 2 ^ 30) with bit 30 set to 1. Bit 31 is zero.
|
||||
/// The most significant bit 31 (sign bit) is left unused so that checking for a value <= 0 identifies an invalid
|
||||
/// socket ID.
|
||||
///
|
||||
/// @param group The socket id should be for socket group.
|
||||
/// @return The new socket ID.
|
||||
/// @throw CUDTException if after rolling over all possible ID values nothing can be returned
|
||||
SRTSOCKET generateSocketID(bool group = false);
|
||||
|
||||
private:
|
||||
typedef std::map<SRTSOCKET, CUDTSocket*> sockets_t; // stores all the socket structures
|
||||
sockets_t m_Sockets;
|
||||
|
||||
#if ENABLE_BONDING
|
||||
typedef std::map<SRTSOCKET, CUDTGroup*> groups_t;
|
||||
groups_t m_Groups;
|
||||
#endif
|
||||
|
||||
sync::Mutex m_GlobControlLock; // used to synchronize UDT API
|
||||
|
||||
sync::Mutex m_IDLock; // used to synchronize ID generation
|
||||
|
||||
SRTSOCKET m_SocketIDGenerator; // seed to generate a new unique socket ID
|
||||
SRTSOCKET m_SocketIDGenerator_init; // Keeps track of the very first one
|
||||
|
||||
std::map<int64_t, std::set<SRTSOCKET> >
|
||||
m_PeerRec; // record sockets from peers to avoid repeated connection request, int64_t = (socker_id << 30) + isn
|
||||
|
||||
private:
|
||||
friend struct FLookupSocketWithEvent_LOCKED;
|
||||
|
||||
CUDTSocket* locateSocket(SRTSOCKET u, ErrorHandling erh = ERH_RETURN);
|
||||
// This function does the same as locateSocket, except that:
|
||||
// - lock on m_GlobControlLock is expected (so that you don't unlock between finding and using)
|
||||
// - only return NULL if not found
|
||||
CUDTSocket* locateSocket_LOCKED(SRTSOCKET u);
|
||||
CUDTSocket* locatePeer(const sockaddr_any& peer, const SRTSOCKET id, int32_t isn);
|
||||
|
||||
#if ENABLE_BONDING
|
||||
CUDTGroup* locateAcquireGroup(SRTSOCKET u, ErrorHandling erh = ERH_RETURN);
|
||||
CUDTGroup* acquireSocketsGroup(CUDTSocket* s);
|
||||
|
||||
struct GroupKeeper
|
||||
{
|
||||
CUDTGroup* group;
|
||||
|
||||
// This is intended for API functions to lock the group's existence
|
||||
// for the lifetime of their call.
|
||||
GroupKeeper(CUDTUnited& glob, SRTSOCKET id, ErrorHandling erh) { group = glob.locateAcquireGroup(id, erh); }
|
||||
|
||||
// This is intended for TSBPD thread that should lock the group's
|
||||
// existence until it exits.
|
||||
GroupKeeper(CUDTUnited& glob, CUDTSocket* s) { group = glob.acquireSocketsGroup(s); }
|
||||
|
||||
~GroupKeeper()
|
||||
{
|
||||
if (group)
|
||||
{
|
||||
// We have a guarantee that if `group` was set
|
||||
// as non-NULL here, it is also acquired and will not
|
||||
// be deleted until this busy flag is set back to false.
|
||||
sync::ScopedLock cgroup(*group->exp_groupLock());
|
||||
group->apiRelease();
|
||||
// Only now that the group lock is lifted, can the
|
||||
// group be now deleted and this pointer potentially dangling
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
void updateMux(CUDTSocket* s, const sockaddr_any& addr, const UDPSOCKET* = NULL);
|
||||
bool updateListenerMux(CUDTSocket* s, const CUDTSocket* ls);
|
||||
|
||||
// Utility functions for updateMux
|
||||
void configureMuxer(CMultiplexer& w_m, const CUDTSocket* s, int af);
|
||||
uint16_t installMuxer(CUDTSocket* w_s, CMultiplexer& sm);
|
||||
|
||||
/// @brief Checks if channel configuration matches the socket configuration.
|
||||
/// @param cfgMuxer multiplexer configuration.
|
||||
/// @param cfgSocket socket configuration.
|
||||
/// @return tru if configurations match, false otherwise.
|
||||
static bool channelSettingsMatch(const CSrtMuxerConfig& cfgMuxer, const CSrtConfig& cfgSocket);
|
||||
|
||||
private:
|
||||
std::map<int, CMultiplexer> m_mMultiplexer; // UDP multiplexer
|
||||
sync::Mutex m_MultiplexerLock;
|
||||
|
||||
private:
|
||||
CCache<CInfoBlock>* m_pCache; // UDT network information cache
|
||||
|
||||
private:
|
||||
srt::sync::atomic<bool> m_bClosing;
|
||||
sync::Mutex m_GCStopLock;
|
||||
sync::Condition m_GCStopCond;
|
||||
|
||||
sync::Mutex m_InitLock;
|
||||
int m_iInstanceCount; // number of startup() called by application
|
||||
bool m_bGCStatus; // if the GC thread is working (true)
|
||||
|
||||
sync::CThread m_GCThread;
|
||||
static void* garbageCollect(void*);
|
||||
|
||||
sockets_t m_ClosedSockets; // temporarily store closed sockets
|
||||
#if ENABLE_BONDING
|
||||
groups_t m_ClosedGroups;
|
||||
#endif
|
||||
|
||||
void checkBrokenSockets();
|
||||
void removeSocket(const SRTSOCKET u);
|
||||
|
||||
CEPoll m_EPoll; // handling epoll data structures and events
|
||||
|
||||
private:
|
||||
CUDTUnited(const CUDTUnited&);
|
||||
CUDTUnited& operator=(const CUDTUnited&);
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
311
trunk/3rdparty/srt-1-fit/srtcore/atomic.h
vendored
Normal file
311
trunk/3rdparty/srt-1-fit/srtcore/atomic.h
vendored
Normal file
|
@ -0,0 +1,311 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute
|
||||
// this software, either in source code form or as a compiled binary, for any
|
||||
// purpose, commercial or non-commercial, and by any means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors of
|
||||
// this software dedicate any and all copyright interest in the software to the
|
||||
// public domain. We make this dedication for the benefit of the public at
|
||||
// large and to the detriment of our heirs and successors. We intend this
|
||||
// dedication to be an overt act of relinquishment in perpetuity of all present
|
||||
// and future rights to this software under copyright law.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// For more information, please refer to <http://unlicense.org/>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// SRT Project information:
|
||||
// This file was adopted from a Public Domain project from
|
||||
// https://github.com/mbitsnbites/atomic
|
||||
// Only namespaces were changed to adopt it for SRT project.
|
||||
|
||||
#ifndef SRT_SYNC_ATOMIC_H_
|
||||
#define SRT_SYNC_ATOMIC_H_
|
||||
|
||||
// Macro for disallowing copying of an object.
|
||||
#if __cplusplus >= 201103L
|
||||
#define ATOMIC_DISALLOW_COPY(T) \
|
||||
T(const T&) = delete; \
|
||||
T& operator=(const T&) = delete;
|
||||
#else
|
||||
#define ATOMIC_DISALLOW_COPY(T) \
|
||||
T(const T&); \
|
||||
T& operator=(const T&);
|
||||
#endif
|
||||
|
||||
// A portable static assert.
|
||||
#if __cplusplus >= 201103L
|
||||
#define ATOMIC_STATIC_ASSERT(condition, message) \
|
||||
static_assert((condition), message)
|
||||
#else
|
||||
// Based on: http://stackoverflow.com/a/809465/5778708
|
||||
#define ATOMIC_STATIC_ASSERT(condition, message) \
|
||||
_impl_STATIC_ASSERT_LINE(condition, __LINE__)
|
||||
#define _impl_PASTE(a, b) a##b
|
||||
#ifdef __GNUC__
|
||||
#define _impl_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define _impl_UNUSED
|
||||
#endif
|
||||
#define _impl_STATIC_ASSERT_LINE(condition, line) \
|
||||
typedef char _impl_PASTE( \
|
||||
STATIC_ASSERT_failed_, \
|
||||
line)[(2 * static_cast<int>(!!(condition))) - 1] _impl_UNUSED
|
||||
#endif
|
||||
|
||||
#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1)
|
||||
// NOTE: Defined at the top level.
|
||||
#elif __cplusplus >= 201103L
|
||||
// NOTE: Prefer to use the c++11 std::atomic.
|
||||
#define ATOMIC_USE_CPP11_ATOMIC
|
||||
#elif (defined(__clang__) && defined(__clang_major__) && (__clang_major__ > 5)) \
|
||||
|| defined(__xlc__)
|
||||
// NOTE: Clang <6 does not support GCC __atomic_* intrinsics. I am unsure
|
||||
// about Clang6. Since Clang sets __GNUC__ and __GNUC_MINOR__ of this era
|
||||
// to <4.5, older Clang will catch the setting below to use the
|
||||
// POSIX Mutex Implementation.
|
||||
#define ATOMIC_USE_GCC_INTRINSICS
|
||||
#elif defined(__GNUC__) \
|
||||
&& ( (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) )
|
||||
// NOTE: The __atomic_* family of intrisics were introduced in GCC-4.7.0.
|
||||
// NOTE: This follows #if defined(__clang__), because most if, not all,
|
||||
// versions of Clang define __GNUC__ and __GNUC_MINOR__ but often define
|
||||
// them to 4.4 or an even earlier version. Most of the newish versions
|
||||
// of Clang also support GCC Atomic Intrisics even if they set GCC version
|
||||
// macros to <4.7.
|
||||
#define ATOMIC_USE_GCC_INTRINSICS
|
||||
#elif defined(__GNUC__) && !defined(ATOMIC_USE_SRT_SYNC_MUTEX)
|
||||
// NOTE: GCC compiler built-ins for atomic operations are pure
|
||||
// compiler extensions prior to GCC-4.7 and were grouped into the
|
||||
// the __sync_* family of functions. GCC-4.7, both the c++11 and C11
|
||||
// standards had been finalized, and GCC updated their built-ins to
|
||||
// better reflect the new memory model and the new functions grouped
|
||||
// into the __atomic_* family. Also the memory models were defined
|
||||
// differently, than in pre 4.7.
|
||||
// TODO: PORT to the pre GCC-4.7 __sync_* intrinsics. In the meantime use
|
||||
// the POSIX Mutex Implementation.
|
||||
#define ATOMIC_USE_SRT_SYNC_MUTEX 1
|
||||
#elif defined(_MSC_VER)
|
||||
#define ATOMIC_USE_MSVC_INTRINSICS
|
||||
#include "atomic_msvc.h"
|
||||
#else
|
||||
#error Unsupported compiler / system.
|
||||
#endif
|
||||
// Include any necessary headers for the selected Atomic Implementation.
|
||||
#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1)
|
||||
#include "sync.h"
|
||||
#endif
|
||||
#if defined(ATOMIC_USE_CPP11_ATOMIC)
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
namespace srt {
|
||||
namespace sync {
|
||||
template <typename T>
|
||||
class atomic {
|
||||
public:
|
||||
ATOMIC_STATIC_ASSERT(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 ||
|
||||
sizeof(T) == 8,
|
||||
"Only types of size 1, 2, 4 or 8 are supported");
|
||||
|
||||
atomic()
|
||||
: value_(static_cast<T>(0))
|
||||
#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1)
|
||||
, mutex_()
|
||||
#endif
|
||||
{
|
||||
// No-Op
|
||||
}
|
||||
|
||||
explicit atomic(const T value)
|
||||
: value_(value)
|
||||
#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1)
|
||||
, mutex_()
|
||||
#endif
|
||||
{
|
||||
// No-Op
|
||||
}
|
||||
|
||||
~atomic()
|
||||
{
|
||||
// No-Op
|
||||
}
|
||||
|
||||
/// @brief Performs an atomic increment operation (value + 1).
|
||||
/// @returns The new value of the atomic object.
|
||||
T operator++() {
|
||||
#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1)
|
||||
ScopedLock lg_(mutex_);
|
||||
const T t = ++value_;
|
||||
return t;
|
||||
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
|
||||
return __atomic_add_fetch(&value_, 1, __ATOMIC_SEQ_CST);
|
||||
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
return msvc::interlocked<T>::increment(&value_);
|
||||
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
|
||||
return ++value_;
|
||||
#else
|
||||
#error "Implement Me."
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Performs an atomic decrement operation (value - 1).
|
||||
/// @returns The new value of the atomic object.
|
||||
T operator--() {
|
||||
#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1)
|
||||
ScopedLock lg_(mutex_);
|
||||
const T t = --value_;
|
||||
return t;
|
||||
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
|
||||
return __atomic_sub_fetch(&value_, 1, __ATOMIC_SEQ_CST);
|
||||
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
return msvc::interlocked<T>::decrement(&value_);
|
||||
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
|
||||
return --value_;
|
||||
#else
|
||||
#error "Implement Me."
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Performs an atomic compare-and-swap (CAS) operation.
|
||||
///
|
||||
/// The value of the atomic object is only updated to the new value if the
|
||||
/// old value of the atomic object matches @c expected_val.
|
||||
///
|
||||
/// @param expected_val The expected value of the atomic object.
|
||||
/// @param new_val The new value to write to the atomic object.
|
||||
/// @returns True if new_value was written to the atomic object.
|
||||
bool compare_exchange(const T expected_val, const T new_val) {
|
||||
#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1)
|
||||
ScopedLock lg_(mutex_);
|
||||
bool result = false;
|
||||
if (expected_val == value_)
|
||||
{
|
||||
value_ = new_val;
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
|
||||
T e = expected_val;
|
||||
return __atomic_compare_exchange_n(
|
||||
&value_, &e, new_val, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
const T old_val =
|
||||
msvc::interlocked<T>::compare_exchange(&value_, new_val, expected_val);
|
||||
return (old_val == expected_val);
|
||||
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
|
||||
T e = expected_val;
|
||||
return value_.compare_exchange_weak(e, new_val);
|
||||
#else
|
||||
#error "Implement Me."
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Performs an atomic set operation.
|
||||
///
|
||||
/// The value of the atomic object is unconditionally updated to the new
|
||||
/// value.
|
||||
///
|
||||
/// @param new_val The new value to write to the atomic object.
|
||||
void store(const T new_val) {
|
||||
#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1)
|
||||
ScopedLock lg_(mutex_);
|
||||
value_ = new_val;
|
||||
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
|
||||
__atomic_store_n(&value_, new_val, __ATOMIC_SEQ_CST);
|
||||
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
(void)msvc::interlocked<T>::exchange(&value_, new_val);
|
||||
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
|
||||
value_.store(new_val);
|
||||
#else
|
||||
#error "Implement Me."
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @returns the current value of the atomic object.
|
||||
/// @note Be careful about how this is used, since any operations on the
|
||||
/// returned value are inherently non-atomic.
|
||||
T load() const {
|
||||
#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1)
|
||||
ScopedLock lg_(mutex_);
|
||||
const T t = value_;
|
||||
return t;
|
||||
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
|
||||
return __atomic_load_n(&value_, __ATOMIC_SEQ_CST);
|
||||
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
// TODO(m): Is there a better solution for MSVC?
|
||||
return value_;
|
||||
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
|
||||
return value_;
|
||||
#else
|
||||
#error "Implement Me."
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Performs an atomic exchange operation.
|
||||
///
|
||||
/// The value of the atomic object is unconditionally updated to the new
|
||||
/// value, and the old value is returned.
|
||||
///
|
||||
/// @param new_val The new value to write to the atomic object.
|
||||
/// @returns the old value.
|
||||
T exchange(const T new_val) {
|
||||
#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1)
|
||||
ScopedLock lg_(mutex_);
|
||||
const T t = value_;
|
||||
value_ = new_val;
|
||||
return t;
|
||||
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
|
||||
return __atomic_exchange_n(&value_, new_val, __ATOMIC_SEQ_CST);
|
||||
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
return msvc::interlocked<T>::exchange(&value_, new_val);
|
||||
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
|
||||
return value_.exchange(new_val);
|
||||
#else
|
||||
#error "Implement Me."
|
||||
#endif
|
||||
}
|
||||
|
||||
T operator=(const T new_value) {
|
||||
store(new_value);
|
||||
return new_value;
|
||||
}
|
||||
|
||||
operator T() const {
|
||||
return load();
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1)
|
||||
T value_;
|
||||
mutable Mutex mutex_;
|
||||
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
|
||||
volatile T value_;
|
||||
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
volatile T value_;
|
||||
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
|
||||
std::atomic<T> value_;
|
||||
#else
|
||||
#error "Implement Me. (value_ type)"
|
||||
#endif
|
||||
|
||||
ATOMIC_DISALLOW_COPY(atomic)
|
||||
};
|
||||
|
||||
} // namespace sync
|
||||
} // namespace srt
|
||||
|
||||
// Undef temporary defines.
|
||||
#undef ATOMIC_USE_GCC_INTRINSICS
|
||||
#undef ATOMIC_USE_MSVC_INTRINSICS
|
||||
#undef ATOMIC_USE_CPP11_ATOMIC
|
||||
|
||||
#endif // ATOMIC_ATOMIC_H_
|
91
trunk/3rdparty/srt-1-fit/srtcore/atomic_clock.h
vendored
Normal file
91
trunk/3rdparty/srt-1-fit/srtcore/atomic_clock.h
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2021 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INC_SRT_SYNC_ATOMIC_CLOCK_H
|
||||
#define INC_SRT_SYNC_ATOMIC_CLOCK_H
|
||||
|
||||
#include "sync.h"
|
||||
#include "atomic.h"
|
||||
|
||||
namespace srt
|
||||
{
|
||||
namespace sync
|
||||
{
|
||||
|
||||
template <class Clock>
|
||||
class AtomicDuration
|
||||
{
|
||||
atomic<int64_t> dur;
|
||||
typedef typename Clock::duration duration_type;
|
||||
typedef typename Clock::time_point time_point_type;
|
||||
public:
|
||||
|
||||
AtomicDuration() ATR_NOEXCEPT : dur(0) {}
|
||||
|
||||
duration_type load()
|
||||
{
|
||||
int64_t val = dur.load();
|
||||
return duration_type(val);
|
||||
}
|
||||
|
||||
void store(const duration_type& d)
|
||||
{
|
||||
dur.store(d.count());
|
||||
}
|
||||
|
||||
AtomicDuration<Clock>& operator=(const duration_type& s)
|
||||
{
|
||||
dur = s.count();
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator duration_type() const
|
||||
{
|
||||
return duration_type(dur);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Clock>
|
||||
class AtomicClock
|
||||
{
|
||||
atomic<uint64_t> dur;
|
||||
typedef typename Clock::duration duration_type;
|
||||
typedef typename Clock::time_point time_point_type;
|
||||
public:
|
||||
|
||||
AtomicClock() ATR_NOEXCEPT : dur(0) {}
|
||||
|
||||
time_point_type load() const
|
||||
{
|
||||
int64_t val = dur.load();
|
||||
return time_point_type(duration_type(val));
|
||||
}
|
||||
|
||||
void store(const time_point_type& d)
|
||||
{
|
||||
dur.store(uint64_t(d.time_since_epoch().count()));
|
||||
}
|
||||
|
||||
AtomicClock& operator=(const time_point_type& s)
|
||||
{
|
||||
dur = s.time_since_epoch().count();
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator time_point_type() const
|
||||
{
|
||||
return time_point_type(duration_type(dur.load()));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sync
|
||||
} // namespace srt
|
||||
|
||||
#endif // INC_SRT_SYNC_ATOMIC_CLOCK_H
|
245
trunk/3rdparty/srt-1-fit/srtcore/atomic_msvc.h
vendored
Normal file
245
trunk/3rdparty/srt-1-fit/srtcore/atomic_msvc.h
vendored
Normal file
|
@ -0,0 +1,245 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute
|
||||
// this software, either in source code form or as a compiled binary, for any
|
||||
// purpose, commercial or non-commercial, and by any means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors of
|
||||
// this software dedicate any and all copyright interest in the software to the
|
||||
// public domain. We make this dedication for the benefit of the public at
|
||||
// large and to the detriment of our heirs and successors. We intend this
|
||||
// dedication to be an overt act of relinquishment in perpetuity of all present
|
||||
// and future rights to this software under copyright law.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// For more information, please refer to <http://unlicense.org/>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// SRT Project information:
|
||||
// This file was adopted from a Public Domain project from
|
||||
// https://github.com/mbitsnbites/atomic
|
||||
// Only namespaces were changed to adopt it for SRT project.
|
||||
|
||||
#ifndef SRT_SYNC_ATOMIC_MSVC_H_
|
||||
#define SRT_SYNC_ATOMIC_MSVC_H_
|
||||
|
||||
// Define which functions we need (don't include <intrin.h>).
|
||||
extern "C" {
|
||||
short _InterlockedIncrement16(short volatile*);
|
||||
long _InterlockedIncrement(long volatile*);
|
||||
__int64 _InterlockedIncrement64(__int64 volatile*);
|
||||
|
||||
short _InterlockedDecrement16(short volatile*);
|
||||
long _InterlockedDecrement(long volatile*);
|
||||
__int64 _InterlockedDecrement64(__int64 volatile*);
|
||||
|
||||
char _InterlockedExchange8(char volatile*, char);
|
||||
short _InterlockedExchange16(short volatile*, short);
|
||||
long __cdecl _InterlockedExchange(long volatile*, long);
|
||||
__int64 _InterlockedExchange64(__int64 volatile*, __int64);
|
||||
|
||||
char _InterlockedCompareExchange8(char volatile*, char, char);
|
||||
short _InterlockedCompareExchange16(short volatile*, short, short);
|
||||
long __cdecl _InterlockedCompareExchange(long volatile*, long, long);
|
||||
__int64 _InterlockedCompareExchange64(__int64 volatile*, __int64, __int64);
|
||||
};
|
||||
|
||||
// Define which functions we want to use as inline intriniscs.
|
||||
#pragma intrinsic(_InterlockedIncrement)
|
||||
#pragma intrinsic(_InterlockedIncrement16)
|
||||
|
||||
#pragma intrinsic(_InterlockedDecrement)
|
||||
#pragma intrinsic(_InterlockedDecrement16)
|
||||
|
||||
#pragma intrinsic(_InterlockedCompareExchange)
|
||||
#pragma intrinsic(_InterlockedCompareExchange8)
|
||||
#pragma intrinsic(_InterlockedCompareExchange16)
|
||||
|
||||
#pragma intrinsic(_InterlockedExchange)
|
||||
#pragma intrinsic(_InterlockedExchange8)
|
||||
#pragma intrinsic(_InterlockedExchange16)
|
||||
|
||||
#if defined(_M_X64)
|
||||
#pragma intrinsic(_InterlockedIncrement64)
|
||||
#pragma intrinsic(_InterlockedDecrement64)
|
||||
#pragma intrinsic(_InterlockedCompareExchange64)
|
||||
#pragma intrinsic(_InterlockedExchange64)
|
||||
#endif // _M_X64
|
||||
|
||||
namespace srt {
|
||||
namespace sync {
|
||||
namespace msvc {
|
||||
template <typename T, size_t N = sizeof(T)>
|
||||
struct interlocked {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct interlocked<T, 1> {
|
||||
static inline T increment(T volatile* x) {
|
||||
// There's no _InterlockedIncrement8().
|
||||
char old_val, new_val;
|
||||
do {
|
||||
old_val = static_cast<char>(*x);
|
||||
new_val = old_val + static_cast<char>(1);
|
||||
} while (_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(x),
|
||||
new_val,
|
||||
old_val) != old_val);
|
||||
return static_cast<T>(new_val);
|
||||
}
|
||||
|
||||
static inline T decrement(T volatile* x) {
|
||||
// There's no _InterlockedDecrement8().
|
||||
char old_val, new_val;
|
||||
do {
|
||||
old_val = static_cast<char>(*x);
|
||||
new_val = old_val - static_cast<char>(1);
|
||||
} while (_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(x),
|
||||
new_val,
|
||||
old_val) != old_val);
|
||||
return static_cast<T>(new_val);
|
||||
}
|
||||
|
||||
static inline T compare_exchange(T volatile* x,
|
||||
const T new_val,
|
||||
const T expected_val) {
|
||||
return static_cast<T>(
|
||||
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(x),
|
||||
static_cast<const char>(new_val),
|
||||
static_cast<const char>(expected_val)));
|
||||
}
|
||||
|
||||
static inline T exchange(T volatile* x, const T new_val) {
|
||||
return static_cast<T>(_InterlockedExchange8(
|
||||
reinterpret_cast<volatile char*>(x), static_cast<const char>(new_val)));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct interlocked<T, 2> {
|
||||
static inline T increment(T volatile* x) {
|
||||
return static_cast<T>(
|
||||
_InterlockedIncrement16(reinterpret_cast<volatile short*>(x)));
|
||||
}
|
||||
|
||||
static inline T decrement(T volatile* x) {
|
||||
return static_cast<T>(
|
||||
_InterlockedDecrement16(reinterpret_cast<volatile short*>(x)));
|
||||
}
|
||||
|
||||
static inline T compare_exchange(T volatile* x,
|
||||
const T new_val,
|
||||
const T expected_val) {
|
||||
return static_cast<T>(
|
||||
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(x),
|
||||
static_cast<const short>(new_val),
|
||||
static_cast<const short>(expected_val)));
|
||||
}
|
||||
|
||||
static inline T exchange(T volatile* x, const T new_val) {
|
||||
return static_cast<T>(
|
||||
_InterlockedExchange16(reinterpret_cast<volatile short*>(x),
|
||||
static_cast<const short>(new_val)));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct interlocked<T, 4> {
|
||||
static inline T increment(T volatile* x) {
|
||||
return static_cast<T>(
|
||||
_InterlockedIncrement(reinterpret_cast<volatile long*>(x)));
|
||||
}
|
||||
|
||||
static inline T decrement(T volatile* x) {
|
||||
return static_cast<T>(
|
||||
_InterlockedDecrement(reinterpret_cast<volatile long*>(x)));
|
||||
}
|
||||
|
||||
static inline T compare_exchange(T volatile* x,
|
||||
const T new_val,
|
||||
const T expected_val) {
|
||||
return static_cast<T>(
|
||||
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(x),
|
||||
static_cast<const long>(new_val),
|
||||
static_cast<const long>(expected_val)));
|
||||
}
|
||||
|
||||
static inline T exchange(T volatile* x, const T new_val) {
|
||||
return static_cast<T>(_InterlockedExchange(
|
||||
reinterpret_cast<volatile long*>(x), static_cast<const long>(new_val)));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct interlocked<T, 8> {
|
||||
static inline T increment(T volatile* x) {
|
||||
#if defined(_M_X64)
|
||||
return static_cast<T>(
|
||||
_InterlockedIncrement64(reinterpret_cast<volatile __int64*>(x)));
|
||||
#else
|
||||
// There's no _InterlockedIncrement64() for 32-bit x86.
|
||||
__int64 old_val, new_val;
|
||||
do {
|
||||
old_val = static_cast<__int64>(*x);
|
||||
new_val = old_val + static_cast<__int64>(1);
|
||||
} while (_InterlockedCompareExchange64(
|
||||
reinterpret_cast<volatile __int64*>(x), new_val, old_val) !=
|
||||
old_val);
|
||||
return static_cast<T>(new_val);
|
||||
#endif // _M_X64
|
||||
}
|
||||
|
||||
static inline T decrement(T volatile* x) {
|
||||
#if defined(_M_X64)
|
||||
return static_cast<T>(
|
||||
_InterlockedDecrement64(reinterpret_cast<volatile __int64*>(x)));
|
||||
#else
|
||||
// There's no _InterlockedDecrement64() for 32-bit x86.
|
||||
__int64 old_val, new_val;
|
||||
do {
|
||||
old_val = static_cast<__int64>(*x);
|
||||
new_val = old_val - static_cast<__int64>(1);
|
||||
} while (_InterlockedCompareExchange64(
|
||||
reinterpret_cast<volatile __int64*>(x), new_val, old_val) !=
|
||||
old_val);
|
||||
return static_cast<T>(new_val);
|
||||
#endif // _M_X64
|
||||
}
|
||||
|
||||
static inline T compare_exchange(T volatile* x,
|
||||
const T new_val,
|
||||
const T expected_val) {
|
||||
return static_cast<T>(_InterlockedCompareExchange64(
|
||||
reinterpret_cast<volatile __int64*>(x),
|
||||
static_cast<const __int64>(new_val),
|
||||
static_cast<const __int64>(expected_val)));
|
||||
}
|
||||
|
||||
static inline T exchange(T volatile* x, const T new_val) {
|
||||
#if defined(_M_X64)
|
||||
return static_cast<T>(
|
||||
_InterlockedExchange64(reinterpret_cast<volatile __int64*>(x),
|
||||
static_cast<const __int64>(new_val)));
|
||||
#else
|
||||
// There's no _InterlockedExchange64 for 32-bit x86.
|
||||
__int64 old_val;
|
||||
do {
|
||||
old_val = static_cast<__int64>(*x);
|
||||
} while (_InterlockedCompareExchange64(
|
||||
reinterpret_cast<volatile __int64*>(x), new_val, old_val) !=
|
||||
old_val);
|
||||
return static_cast<T>(old_val);
|
||||
#endif // _M_X64
|
||||
}
|
||||
};
|
||||
} // namespace msvc
|
||||
} // namespace sync
|
||||
} // namespace srt
|
||||
|
||||
#endif // ATOMIC_ATOMIC_MSVC_H_
|
2743
trunk/3rdparty/srt-1-fit/srtcore/buffer.cpp
vendored
2743
trunk/3rdparty/srt-1-fit/srtcore/buffer.cpp
vendored
File diff suppressed because it is too large
Load diff
867
trunk/3rdparty/srt-1-fit/srtcore/buffer.h
vendored
867
trunk/3rdparty/srt-1-fit/srtcore/buffer.h
vendored
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -50,461 +50,562 @@ modified by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_BUFFER_H__
|
||||
#define __UDT_BUFFER_H__
|
||||
|
||||
#ifndef INC_SRT_BUFFER_H
|
||||
#define INC_SRT_BUFFER_H
|
||||
|
||||
#include "udt.h"
|
||||
#include "list.h"
|
||||
#include "queue.h"
|
||||
#include "tsbpd_time.h"
|
||||
#include "utilities.h"
|
||||
#include <fstream>
|
||||
|
||||
class CSndBuffer
|
||||
// The notation used for "circular numbers" in comments:
|
||||
// The "cicrular numbers" are numbers that when increased up to the
|
||||
// maximum become zero, and similarly, when the zero value is decreased,
|
||||
// it turns into the maximum value minus one. This wrapping works the
|
||||
// same for adding and subtracting. Circular numbers cannot be multiplied.
|
||||
|
||||
// Operations done on these numbers are marked with additional % character:
|
||||
// a %> b : a is later than b
|
||||
// a ++% (++%a) : shift a by 1 forward
|
||||
// a +% b : shift a by b
|
||||
// a == b : equality is same as for just numbers
|
||||
|
||||
namespace srt {
|
||||
|
||||
/// The AvgBufSize class is used to calculate moving average of the buffer (RCV or SND)
|
||||
class AvgBufSize
|
||||
{
|
||||
public:
|
||||
|
||||
// XXX There's currently no way to access the socket ID set for
|
||||
// whatever the buffer is currently working for. Required to find
|
||||
// some way to do this, possibly by having a "reverse pointer".
|
||||
// Currently just "unimplemented".
|
||||
std::string CONID() const { return ""; }
|
||||
|
||||
CSndBuffer(int size = 32, int mss = 1500);
|
||||
~CSndBuffer();
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
|
||||
public:
|
||||
AvgBufSize()
|
||||
: m_dBytesCountMAvg(0.0)
|
||||
, m_dCountMAvg(0.0)
|
||||
, m_dTimespanMAvg(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
/// Insert a user buffer into the sending list.
|
||||
/// @param [in] data pointer to the user data block.
|
||||
/// @param [in] len size of the block.
|
||||
/// @param [in] ttl time to live in milliseconds
|
||||
/// @param [in] order if the block should be delivered in order, for DGRAM only
|
||||
|
||||
void addBuffer(const char* data, int len, int ttl, bool order, uint64_t srctime, ref_t<int32_t> r_msgno);
|
||||
|
||||
/// Read a block of data from file and insert it into the sending list.
|
||||
/// @param [in] ifs input file stream.
|
||||
/// @param [in] len size of the block.
|
||||
/// @return actual size of data added from the file.
|
||||
|
||||
int addBufferFromFile(std::fstream& ifs, int len);
|
||||
|
||||
/// Find data position to pack a DATA packet from the furthest reading point.
|
||||
/// @param [out] data the pointer to the data position.
|
||||
/// @param [out] msgno message number of the packet.
|
||||
/// @param [out] origintime origin time stamp of the message
|
||||
/// @param [in] kflags Odd|Even crypto key flag
|
||||
/// @return Actual length of data read.
|
||||
|
||||
int readData(char** data, int32_t& msgno, uint64_t& origintime, int kflgs);
|
||||
|
||||
|
||||
/// Find data position to pack a DATA packet for a retransmission.
|
||||
/// @param [out] data the pointer to the data position.
|
||||
/// @param [in] offset offset from the last ACK point.
|
||||
/// @param [out] msgno message number of the packet.
|
||||
/// @param [out] origintime origin time stamp of the message
|
||||
/// @param [out] msglen length of the message
|
||||
/// @return Actual length of data read.
|
||||
|
||||
int readData(char** data, const int offset, int32_t& msgno, uint64_t& origintime, int& msglen);
|
||||
|
||||
/// Update the ACK point and may release/unmap/return the user data according to the flag.
|
||||
/// @param [in] offset number of packets acknowledged.
|
||||
|
||||
void ackData(int offset);
|
||||
|
||||
/// Read size of data still in the sending list.
|
||||
/// @return Current size of the data in the sending list.
|
||||
|
||||
int getCurrBufSize() const;
|
||||
|
||||
int dropLateData(int &bytes, uint64_t latetime);
|
||||
|
||||
#ifdef SRT_ENABLE_SNDBUFSZ_MAVG
|
||||
void updAvgBufSize(uint64_t time);
|
||||
int getAvgBufSize(ref_t<int> bytes, ref_t<int> timespan);
|
||||
#endif /* SRT_ENABLE_SNDBUFSZ_MAVG */
|
||||
int getCurrBufSize(ref_t<int> bytes, ref_t<int> timespan);
|
||||
|
||||
uint64_t getInRatePeriod() const { return m_InRatePeriod; }
|
||||
|
||||
/// Retrieve input bitrate in bytes per second
|
||||
int getInputRate() const { return m_iInRateBps; }
|
||||
|
||||
/// Update input rate calculation.
|
||||
/// @param [in] time current time in microseconds
|
||||
/// @param [in] pkts number of packets newly added to the buffer
|
||||
/// @param [in] bytes number of payload bytes in those newly added packets
|
||||
///
|
||||
/// @return Current size of the data in the sending list.
|
||||
void updateInputRate(uint64_t time, int pkts = 0, int bytes = 0);
|
||||
|
||||
|
||||
void resetInputRateSmpPeriod(bool disable = false)
|
||||
{
|
||||
setInputRateSmpPeriod(disable ? 0 : INPUTRATE_FAST_START_US);
|
||||
}
|
||||
public:
|
||||
bool isTimeToUpdate(const time_point& now) const;
|
||||
void update(const time_point& now, int pkts, int bytes, int timespan_ms);
|
||||
|
||||
public:
|
||||
inline double pkts() const { return m_dCountMAvg; }
|
||||
inline double timespan_ms() const { return m_dTimespanMAvg; }
|
||||
inline double bytes() const { return m_dBytesCountMAvg; }
|
||||
|
||||
private:
|
||||
time_point m_tsLastSamplingTime;
|
||||
double m_dBytesCountMAvg;
|
||||
double m_dCountMAvg;
|
||||
double m_dTimespanMAvg;
|
||||
};
|
||||
|
||||
void increase();
|
||||
void setInputRateSmpPeriod(int period);
|
||||
/// The class to estimate source bitrate based on samples submitted to the buffer.
|
||||
/// Is currently only used by the CSndBuffer.
|
||||
class CRateEstimator
|
||||
{
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
typedef sync::steady_clock::duration duration;
|
||||
public:
|
||||
CRateEstimator();
|
||||
|
||||
private: // Constants
|
||||
public:
|
||||
uint64_t getInRatePeriod() const { return m_InRatePeriod; }
|
||||
|
||||
static const uint64_t INPUTRATE_FAST_START_US = 500000; // 500 ms
|
||||
static const uint64_t INPUTRATE_RUNNING_US = 1000000; // 1000 ms
|
||||
static const int64_t INPUTRATE_MAX_PACKETS = 2000; // ~ 21 Mbps of 1316 bytes payload
|
||||
/// Retrieve input bitrate in bytes per second
|
||||
int getInputRate() const { return m_iInRateBps; }
|
||||
|
||||
void setInputRateSmpPeriod(int period);
|
||||
|
||||
/// Update input rate calculation.
|
||||
/// @param [in] time current time in microseconds
|
||||
/// @param [in] pkts number of packets newly added to the buffer
|
||||
/// @param [in] bytes number of payload bytes in those newly added packets
|
||||
///
|
||||
/// @return Current size of the data in the sending list.
|
||||
void updateInputRate(const time_point& time, int pkts = 0, int bytes = 0);
|
||||
|
||||
void resetInputRateSmpPeriod(bool disable = false) { setInputRateSmpPeriod(disable ? 0 : INPUTRATE_FAST_START_US); }
|
||||
|
||||
private: // Constants
|
||||
static const uint64_t INPUTRATE_FAST_START_US = 500000; // 500 ms
|
||||
static const uint64_t INPUTRATE_RUNNING_US = 1000000; // 1000 ms
|
||||
static const int64_t INPUTRATE_MAX_PACKETS = 2000; // ~ 21 Mbps of 1316 bytes payload
|
||||
static const int INPUTRATE_INITIAL_BYTESPS = BW_INFINITE;
|
||||
|
||||
private:
|
||||
pthread_mutex_t m_BufLock; // used to synchronize buffer operation
|
||||
int m_iInRatePktsCount; // number of payload bytes added since InRateStartTime
|
||||
int m_iInRateBytesCount; // number of payload bytes added since InRateStartTime
|
||||
time_point m_tsInRateStartTime;
|
||||
uint64_t m_InRatePeriod; // usec
|
||||
int m_iInRateBps; // Input Rate in Bytes/sec
|
||||
};
|
||||
|
||||
struct Block
|
||||
{
|
||||
char* m_pcData; // pointer to the data block
|
||||
int m_iLength; // length of the block
|
||||
class CSndBuffer
|
||||
{
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
typedef sync::steady_clock::duration duration;
|
||||
|
||||
int32_t m_iMsgNoBitset; // message number
|
||||
uint64_t m_ullOriginTime_us; // original request time
|
||||
uint64_t m_ullSourceTime_us;
|
||||
int m_iTTL; // time to live (milliseconds)
|
||||
public:
|
||||
// XXX There's currently no way to access the socket ID set for
|
||||
// whatever the buffer is currently working for. Required to find
|
||||
// some way to do this, possibly by having a "reverse pointer".
|
||||
// Currently just "unimplemented".
|
||||
std::string CONID() const { return ""; }
|
||||
|
||||
Block* m_pNext; // next block
|
||||
/// @brief CSndBuffer constructor.
|
||||
/// @param size initial number of blocks (each block to store one packet payload).
|
||||
/// @param maxpld maximum packet payload.
|
||||
CSndBuffer(int size = 32, int maxpld = 1500);
|
||||
~CSndBuffer();
|
||||
|
||||
int32_t getMsgSeq()
|
||||
{
|
||||
// NOTE: this extracts message ID with regard to REXMIT flag.
|
||||
// This is valid only for message ID that IS GENERATED in this instance,
|
||||
// not provided by the peer. This can be otherwise sent to the peer - it doesn't matter
|
||||
// for the peer that it uses LESS bits to represent the message.
|
||||
return m_iMsgNoBitset & MSGNO_SEQ::mask;
|
||||
}
|
||||
public:
|
||||
/// Insert a user buffer into the sending list.
|
||||
/// For @a w_mctrl the following fields are used:
|
||||
/// INPUT:
|
||||
/// - msgttl: timeout for retransmitting the message, if lost
|
||||
/// - inorder: request to deliver the message in order of sending
|
||||
/// - srctime: local time as a base for packet's timestamp (0 if unused)
|
||||
/// - pktseq: sequence number to be stamped on the packet (-1 if unused)
|
||||
/// - msgno: message number to be stamped on the packet (-1 if unused)
|
||||
/// OUTPUT:
|
||||
/// - srctime: local time stamped on the packet (same as input, if input wasn't 0)
|
||||
/// - pktseq: sequence number to be stamped on the next packet
|
||||
/// - msgno: message number stamped on the packet
|
||||
/// @param [in] data pointer to the user data block.
|
||||
/// @param [in] len size of the block.
|
||||
/// @param [inout] w_mctrl Message control data
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
void addBuffer(const char* data, int len, SRT_MSGCTRL& w_mctrl);
|
||||
|
||||
} *m_pBlock, *m_pFirstBlock, *m_pCurrBlock, *m_pLastBlock;
|
||||
/// Read a block of data from file and insert it into the sending list.
|
||||
/// @param [in] ifs input file stream.
|
||||
/// @param [in] len size of the block.
|
||||
/// @return actual size of data added from the file.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
int addBufferFromFile(std::fstream& ifs, int len);
|
||||
|
||||
// m_pBlock: The head pointer
|
||||
// m_pFirstBlock: The first block
|
||||
// m_pCurrBlock: The current block
|
||||
// m_pLastBlock: The last block (if first == last, buffer is empty)
|
||||
/// Find data position to pack a DATA packet from the furthest reading point.
|
||||
/// @param [out] packet the packet to read.
|
||||
/// @param [out] origintime origin time stamp of the message
|
||||
/// @param [in] kflags Odd|Even crypto key flag
|
||||
/// @param [out] seqnoinc the number of packets skipped due to TTL, so that seqno should be incremented.
|
||||
/// @return Actual length of data read.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
int readData(CPacket& w_packet, time_point& w_origintime, int kflgs, int& w_seqnoinc);
|
||||
|
||||
struct Buffer
|
||||
{
|
||||
char* m_pcData; // buffer
|
||||
int m_iSize; // size
|
||||
Buffer* m_pNext; // next buffer
|
||||
} *m_pBuffer; // physical buffer
|
||||
/// Peek an information on the next original data packet to send.
|
||||
/// @return origin time stamp of the next packet; epoch start time otherwise.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
time_point peekNextOriginal() const;
|
||||
|
||||
int32_t m_iNextMsgNo; // next message number
|
||||
/// Find data position to pack a DATA packet for a retransmission.
|
||||
/// @param [in] offset offset from the last ACK point (backward sequence number difference)
|
||||
/// @param [out] packet the packet to read.
|
||||
/// @param [out] origintime origin time stamp of the message
|
||||
/// @param [out] msglen length of the message
|
||||
/// @return Actual length of data read (return 0 if offset too large, -1 if TTL exceeded).
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
int readData(const int offset, CPacket& w_packet, time_point& w_origintime, int& w_msglen);
|
||||
|
||||
int m_iSize; // buffer size (number of packets)
|
||||
int m_iMSS; // maximum seqment/packet size
|
||||
/// Get the time of the last retransmission (if any) of the DATA packet.
|
||||
/// @param [in] offset offset from the last ACK point (backward sequence number difference)
|
||||
///
|
||||
/// @return Last time of the last retransmission event for the corresponding DATA packet.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
time_point getPacketRexmitTime(const int offset);
|
||||
|
||||
int m_iCount; // number of used blocks
|
||||
/// Update the ACK point and may release/unmap/return the user data according to the flag.
|
||||
/// @param [in] offset number of packets acknowledged.
|
||||
int32_t getMsgNoAt(const int offset);
|
||||
|
||||
int m_iBytesCount; // number of payload bytes in queue
|
||||
uint64_t m_ullLastOriginTime_us;
|
||||
void ackData(int offset);
|
||||
|
||||
#ifdef SRT_ENABLE_SNDBUFSZ_MAVG
|
||||
uint64_t m_LastSamplingTime;
|
||||
int m_iCountMAvg;
|
||||
int m_iBytesCountMAvg;
|
||||
int m_TimespanMAvg;
|
||||
#endif /* SRT_ENABLE_SNDBUFSZ_MAVG */
|
||||
/// Read size of data still in the sending list.
|
||||
/// @return Current size of the data in the sending list.
|
||||
int getCurrBufSize() const;
|
||||
|
||||
int m_iInRatePktsCount; // number of payload bytes added since InRateStartTime
|
||||
int m_iInRateBytesCount; // number of payload bytes added since InRateStartTime
|
||||
uint64_t m_InRateStartTime;
|
||||
uint64_t m_InRatePeriod; // usec
|
||||
int m_iInRateBps; // Input Rate in Bytes/sec
|
||||
int m_iAvgPayloadSz; // Average packet payload size
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
int dropLateData(int& bytes, int32_t& w_first_msgno, const time_point& too_late_time);
|
||||
|
||||
void updAvgBufSize(const time_point& time);
|
||||
int getAvgBufSize(int& bytes, int& timespan);
|
||||
int getCurrBufSize(int& bytes, int& timespan);
|
||||
|
||||
/// @brief Get the buffering delay of the oldest message in the buffer.
|
||||
/// @return the delay value.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
duration getBufferingDelay(const time_point& tnow) const;
|
||||
|
||||
uint64_t getInRatePeriod() const { return m_rateEstimator.getInRatePeriod(); }
|
||||
|
||||
/// Retrieve input bitrate in bytes per second
|
||||
int getInputRate() const { return m_rateEstimator.getInputRate(); }
|
||||
|
||||
void resetInputRateSmpPeriod(bool disable = false) { m_rateEstimator.resetInputRateSmpPeriod(disable); }
|
||||
|
||||
const CRateEstimator& getRateEstimator() const { return m_rateEstimator; }
|
||||
|
||||
void setRateEstimator(const CRateEstimator& other) { m_rateEstimator = other; }
|
||||
|
||||
private:
|
||||
CSndBuffer(const CSndBuffer&);
|
||||
CSndBuffer& operator=(const CSndBuffer&);
|
||||
void increase();
|
||||
|
||||
private:
|
||||
mutable sync::Mutex m_BufLock; // used to synchronize buffer operation
|
||||
|
||||
struct Block
|
||||
{
|
||||
char* m_pcData; // pointer to the data block
|
||||
int m_iLength; // payload length of the block.
|
||||
|
||||
int32_t m_iMsgNoBitset; // message number
|
||||
int32_t m_iSeqNo; // sequence number for scheduling
|
||||
time_point m_tsOriginTime; // block origin time (either provided from above or equals the time a message was submitted for sending.
|
||||
time_point m_tsRexmitTime; // packet retransmission time
|
||||
int m_iTTL; // time to live (milliseconds)
|
||||
|
||||
Block* m_pNext; // next block
|
||||
|
||||
int32_t getMsgSeq()
|
||||
{
|
||||
// NOTE: this extracts message ID with regard to REXMIT flag.
|
||||
// This is valid only for message ID that IS GENERATED in this instance,
|
||||
// not provided by the peer. This can be otherwise sent to the peer - it doesn't matter
|
||||
// for the peer that it uses LESS bits to represent the message.
|
||||
return m_iMsgNoBitset & MSGNO_SEQ::mask;
|
||||
}
|
||||
|
||||
} * m_pBlock, *m_pFirstBlock, *m_pCurrBlock, *m_pLastBlock;
|
||||
|
||||
// m_pBlock: The head pointer
|
||||
// m_pFirstBlock: The first block
|
||||
// m_pCurrBlock: The current block
|
||||
// m_pLastBlock: The last block (if first == last, buffer is empty)
|
||||
|
||||
struct Buffer
|
||||
{
|
||||
char* m_pcData; // buffer
|
||||
int m_iSize; // size
|
||||
Buffer* m_pNext; // next buffer
|
||||
} * m_pBuffer; // physical buffer
|
||||
|
||||
int32_t m_iNextMsgNo; // next message number
|
||||
|
||||
int m_iSize; // buffer size (number of packets)
|
||||
const int m_iBlockLen; // maximum length of a block holding packet payload (excluding packet header).
|
||||
int m_iCount; // number of used blocks
|
||||
|
||||
int m_iBytesCount; // number of payload bytes in queue
|
||||
time_point m_tsLastOriginTime;
|
||||
|
||||
AvgBufSize m_mavg;
|
||||
CRateEstimator m_rateEstimator;
|
||||
|
||||
private:
|
||||
CSndBuffer(const CSndBuffer&);
|
||||
CSndBuffer& operator=(const CSndBuffer&);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if (!ENABLE_NEW_RCVBUFFER)
|
||||
|
||||
class CRcvBuffer
|
||||
{
|
||||
public:
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
typedef sync::steady_clock::duration duration;
|
||||
|
||||
public:
|
||||
// XXX There's currently no way to access the socket ID set for
|
||||
// whatever the queue is currently working for. Required to find
|
||||
// some way to do this, possibly by having a "reverse pointer".
|
||||
// Currently just "unimplemented".
|
||||
std::string CONID() const { return ""; }
|
||||
|
||||
|
||||
/// Construct the buffer.
|
||||
/// @param [in] queue CUnitQueue that actually holds the units (packets)
|
||||
/// @param [in] bufsize_pkts in units (packets)
|
||||
CRcvBuffer(CUnitQueue* queue, int bufsize_pkts = 65536);
|
||||
~CRcvBuffer();
|
||||
|
||||
static const int DEFAULT_SIZE = 65536;
|
||||
/// Construct the buffer.
|
||||
/// @param [in] queue CUnitQueue that actually holds the units (packets)
|
||||
/// @param [in] bufsize_pkts in units (packets)
|
||||
CRcvBuffer(CUnitQueue* queue, int bufsize_pkts = DEFAULT_SIZE);
|
||||
~CRcvBuffer();
|
||||
|
||||
public:
|
||||
/// Write data into the buffer.
|
||||
/// @param [in] unit pointer to a data unit containing new packet
|
||||
/// @param [in] offset offset from last ACK point.
|
||||
/// @return 0 is success, -1 if data is repeated.
|
||||
int addData(CUnit* unit, int offset);
|
||||
|
||||
/// Write data into the buffer.
|
||||
/// @param [in] unit pointer to a data unit containing new packet
|
||||
/// @param [in] offset offset from last ACK point.
|
||||
/// @return 0 is success, -1 if data is repeated.
|
||||
/// Read data into a user buffer.
|
||||
/// @param [in] data pointer to user buffer.
|
||||
/// @param [in] len length of user buffer.
|
||||
/// @return size of data read.
|
||||
int readBuffer(char* data, int len);
|
||||
|
||||
int addData(CUnit* unit, int offset);
|
||||
/// Read data directly into file.
|
||||
/// @param [in] file C++ file stream.
|
||||
/// @param [in] len expected length of data to write into the file.
|
||||
/// @return size of data read.
|
||||
int readBufferToFile(std::fstream& ofs, int len);
|
||||
|
||||
/// Read data into a user buffer.
|
||||
/// @param [in] data pointer to user buffer.
|
||||
/// @param [in] len length of user buffer.
|
||||
/// @return size of data read.
|
||||
/// Update the ACK point of the buffer.
|
||||
/// @param [in] len number of units to be acknowledged.
|
||||
/// @return 1 if a user buffer is fulfilled, otherwise 0.
|
||||
int ackData(int len);
|
||||
|
||||
int readBuffer(char* data, int len);
|
||||
/// Query how many buffer space left for data receiving.
|
||||
/// Actually only acknowledged packets, that are still in the buffer,
|
||||
/// are considered to take buffer space.
|
||||
///
|
||||
/// @return size of available buffer space (including user buffer) for data receiving.
|
||||
/// Not counting unacknowledged packets.
|
||||
int getAvailBufSize() const;
|
||||
|
||||
/// Read data directly into file.
|
||||
/// @param [in] file C++ file stream.
|
||||
/// @param [in] len expected length of data to write into the file.
|
||||
/// @return size of data read.
|
||||
/// Query how many data has been continuously received (for reading) and ready to play (tsbpdtime < now).
|
||||
/// @return size of valid (continous) data for reading.
|
||||
int getRcvDataSize() const;
|
||||
|
||||
int readBufferToFile(std::fstream& ofs, int len);
|
||||
/// Query how many data was received and acknowledged.
|
||||
/// @param [out] bytes bytes
|
||||
/// @param [out] spantime spantime
|
||||
/// @return size in pkts of acked data.
|
||||
int getRcvDataSize(int& bytes, int& spantime);
|
||||
|
||||
/// Update the ACK point of the buffer.
|
||||
/// @param [in] len number of units to be acknowledged.
|
||||
/// @return 1 if a user buffer is fulfilled, otherwise 0.
|
||||
/// Query a 1 sec moving average of how many data was received and acknowledged.
|
||||
/// @param [out] bytes bytes
|
||||
/// @param [out] spantime spantime
|
||||
/// @return size in pkts of acked data.
|
||||
int getRcvAvgDataSize(int& bytes, int& spantime);
|
||||
|
||||
void ackData(int len);
|
||||
/// Query how many data of the receive buffer is acknowledged.
|
||||
/// @param [in] now current time in us.
|
||||
/// @return none.
|
||||
void updRcvAvgDataSize(const time_point& now);
|
||||
|
||||
/// Query how many buffer space left for data receiving.
|
||||
/// Actually only acknowledged packets, that are still in the buffer,
|
||||
/// are considered to take buffer space.
|
||||
///
|
||||
/// @return size of available buffer space (including user buffer) for data receiving.
|
||||
/// Not counting unacknowledged packets.
|
||||
/// Query the received average payload size.
|
||||
/// @return size (bytes) of payload size
|
||||
unsigned getRcvAvgPayloadSize() const;
|
||||
|
||||
int getAvailBufSize() const;
|
||||
struct ReadingState
|
||||
{
|
||||
time_point tsStart;
|
||||
time_point tsLastAck;
|
||||
time_point tsEnd;
|
||||
int iNumAcknowledged;
|
||||
int iNumUnacknowledged;
|
||||
};
|
||||
|
||||
/// Query how many data has been continuously received (for reading) and ready to play (tsbpdtime < now).
|
||||
/// @return size of valid (continous) data for reading.
|
||||
ReadingState debugGetReadingState() const;
|
||||
|
||||
int getRcvDataSize() const;
|
||||
/// Form a string of the current buffer fullness state.
|
||||
/// number of packets acknowledged, TSBPD readiness, etc.
|
||||
std::string strFullnessState(const time_point& tsNow) const;
|
||||
|
||||
/// Query how many data was received and acknowledged.
|
||||
/// @param [out] bytes bytes
|
||||
/// @param [out] spantime spantime
|
||||
/// @return size in pkts of acked data.
|
||||
/// Mark the message to be dropped from the message list.
|
||||
/// @param [in] msgno message number.
|
||||
/// @param [in] using_rexmit_flag whether the MSGNO field uses rexmit flag (if not, one more bit is part of the
|
||||
/// msgno value)
|
||||
void dropMsg(int32_t msgno, bool using_rexmit_flag);
|
||||
|
||||
int getRcvDataSize(int &bytes, int &spantime);
|
||||
#if SRT_ENABLE_RCVBUFSZ_MAVG
|
||||
|
||||
/// Query a 1 sec moving average of how many data was received and acknowledged.
|
||||
/// @param [out] bytes bytes
|
||||
/// @param [out] spantime spantime
|
||||
/// @return size in pkts of acked data.
|
||||
|
||||
int getRcvAvgDataSize(int &bytes, int &spantime);
|
||||
|
||||
/// Query how many data of the receive buffer is acknowledged.
|
||||
/// @param [in] now current time in us.
|
||||
/// @return none.
|
||||
|
||||
void updRcvAvgDataSize(uint64_t now);
|
||||
#endif /* SRT_ENABLE_RCVBUFSZ_MAVG */
|
||||
|
||||
/// Query the received average payload size.
|
||||
/// @return size (bytes) of payload size
|
||||
|
||||
int getRcvAvgPayloadSize() const;
|
||||
|
||||
|
||||
/// Mark the message to be dropped from the message list.
|
||||
/// @param [in] msgno message number.
|
||||
/// @param [in] using_rexmit_flag whether the MSGNO field uses rexmit flag (if not, one more bit is part of the msgno value)
|
||||
|
||||
void dropMsg(int32_t msgno, bool using_rexmit_flag);
|
||||
|
||||
/// read a message.
|
||||
/// @param [out] data buffer to write the message into.
|
||||
/// @param [in] len size of the buffer.
|
||||
/// @return actuall size of data read.
|
||||
|
||||
int readMsg(char* data, int len);
|
||||
|
||||
/// read a message.
|
||||
/// @param [out] data buffer to write the message into.
|
||||
/// @param [in] len size of the buffer.
|
||||
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay
|
||||
/// @return actuall size of data read.
|
||||
|
||||
int readMsg(char* data, int len, ref_t<SRT_MSGCTRL> mctrl);
|
||||
|
||||
/// Query if data is ready to read (tsbpdtime <= now if TsbPD is active).
|
||||
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay
|
||||
/// of next packet in recv buffer, ready or not.
|
||||
/// @param [out] curpktseq Sequence number of the packet if there is one ready to play
|
||||
/// @return true if ready to play, false otherwise (tsbpdtime may be !0 in
|
||||
/// both cases).
|
||||
|
||||
bool isRcvDataReady(ref_t<uint64_t> tsbpdtime, ref_t<int32_t> curpktseq);
|
||||
bool isRcvDataReady();
|
||||
bool isRcvDataAvailable()
|
||||
{
|
||||
return m_iLastAckPos != m_iStartPos;
|
||||
}
|
||||
CPacket* getRcvReadyPacket();
|
||||
|
||||
/// Set TimeStamp-Based Packet Delivery Rx Mode
|
||||
/// @param [in] timebase localtime base (uSec) of packet time stamps including buffering delay
|
||||
/// @param [in] delay aggreed TsbPD delay
|
||||
/// @return 0
|
||||
|
||||
int setRcvTsbPdMode(uint64_t timebase, uint32_t delay);
|
||||
|
||||
/// Add packet timestamp for drift caclculation and compensation
|
||||
/// @param [in] timestamp packet time stamp
|
||||
/// @param [ref] lock Mutex that should be locked for the operation
|
||||
|
||||
void addRcvTsbPdDriftSample(uint32_t timestamp, pthread_mutex_t& lock);
|
||||
|
||||
#ifdef SRT_DEBUG_TSBPD_DRIFT
|
||||
void printDriftHistogram(int64_t iDrift);
|
||||
void printDriftOffset(int tsbPdOffset, int tsbPdDriftAvg);
|
||||
#endif
|
||||
|
||||
/// Get information on the 1st message in queue.
|
||||
// Parameters (of the 1st packet queue, ready to play or not):
|
||||
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay of 1st packet or 0 if none
|
||||
/// @param [out] passack true if 1st ready packet is not yet acknowleged (allowed to be delivered to the app)
|
||||
/// @param [out] skipseqno -1 or seq number of 1st unacknowledged pkt ready to play preceeded by missing packets.
|
||||
/// @retval true 1st packet ready to play (tsbpdtime <= now). Not yet acknowledged if passack == true
|
||||
/// @retval false IF tsbpdtime = 0: rcv buffer empty; ELSE:
|
||||
/// IF skipseqno != -1, packet ready to play preceeded by missing packets.;
|
||||
/// IF skipseqno == -1, no missing packet but 1st not ready to play.
|
||||
|
||||
|
||||
bool getRcvFirstMsg(ref_t<uint64_t> tsbpdtime, ref_t<bool> passack, ref_t<int32_t> skipseqno, ref_t<int32_t> curpktseq);
|
||||
|
||||
/// Update the ACK point of the buffer.
|
||||
/// @param [in] len size of data to be skip & acknowledged.
|
||||
|
||||
void skipData(int len);
|
||||
/// read a message.
|
||||
/// @param [out] data buffer to write the message into.
|
||||
/// @param [in] len size of the buffer.
|
||||
/// @return actuall size of data read.
|
||||
int readMsg(char* data, int len);
|
||||
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
void reportBufferStats(); // Heavy logging Debug only
|
||||
void readMsgHeavyLogging(int p);
|
||||
#endif
|
||||
|
||||
private:
|
||||
/// Adjust receive queue to 1st ready to play message (tsbpdtime < now).
|
||||
// Parameters (of the 1st packet queue, ready to play or not):
|
||||
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay of 1st packet or 0 if none
|
||||
/// @retval true 1st packet ready to play without discontinuity (no hole)
|
||||
/// @retval false tsbpdtime = 0: no packet ready to play
|
||||
/// read a message.
|
||||
/// @param [out] data buffer to write the message into.
|
||||
/// @param [in] len size of the buffer.
|
||||
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay
|
||||
/// @return actuall size of data read.
|
||||
int readMsg(char* data, int len, SRT_MSGCTRL& w_mctrl, int upto);
|
||||
|
||||
|
||||
bool getRcvReadyMsg(ref_t<uint64_t> tsbpdtime, ref_t<int32_t> curpktseq);
|
||||
|
||||
public:
|
||||
|
||||
// (This is exposed as used publicly in logs)
|
||||
/// Get packet delivery local time base (adjusted for wrap around)
|
||||
/// @param [in] timestamp packet timestamp (relative to peer StartTime), wrapping around every ~72 min
|
||||
/// @return local delivery time (usec)
|
||||
uint64_t getTsbPdTimeBase(uint32_t timestamp_us);
|
||||
|
||||
/// Get packet local delivery time
|
||||
/// @param [in] timestamp packet timestamp (relative to peer StartTime), wrapping around every ~72 min
|
||||
/// @return local delivery time (usec)
|
||||
|
||||
public:
|
||||
uint64_t getPktTsbPdTime(uint32_t timestamp);
|
||||
int debugGetSize() const;
|
||||
bool empty() const;
|
||||
|
||||
// Required by PacketFilter facility to use as a storage
|
||||
// for provided packets
|
||||
CUnitQueue* getUnitQueue()
|
||||
{
|
||||
return m_pUnitQueue;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// thread safe bytes counter of the Recv & Ack buffer
|
||||
/// @param [in] pkts acked or removed pkts from rcv buffer (used with acked = true)
|
||||
/// @param [in] bytes number of bytes added/delete (if negative) to/from rcv buffer.
|
||||
/// @param [in] acked true when adding new pkt in RcvBuffer; false when acking/removing pkts to/from buffer
|
||||
|
||||
void countBytes(int pkts, int bytes, bool acked = false);
|
||||
|
||||
private:
|
||||
bool scanMsg(ref_t<int> start, ref_t<int> end, ref_t<bool> passack);
|
||||
|
||||
private:
|
||||
CUnit** m_pUnit; // pointer to the protocol buffer (array of CUnit* items)
|
||||
const int m_iSize; // size of the array of CUnit* items
|
||||
CUnitQueue* m_pUnitQueue; // the shared unit queue
|
||||
|
||||
int m_iStartPos; // the head position for I/O (inclusive)
|
||||
int m_iLastAckPos; // the last ACKed position (exclusive)
|
||||
// EMPTY: m_iStartPos = m_iLastAckPos FULL: m_iStartPos = m_iLastAckPos + 1
|
||||
int m_iMaxPos; // the furthest data position
|
||||
|
||||
int m_iNotch; // the starting read point of the first unit
|
||||
|
||||
pthread_mutex_t m_BytesCountLock; // used to protect counters operations
|
||||
int m_iBytesCount; // Number of payload bytes in the buffer
|
||||
int m_iAckedPktsCount; // Number of acknowledged pkts in the buffer
|
||||
int m_iAckedBytesCount; // Number of acknowledged payload bytes in the buffer
|
||||
int m_iAvgPayloadSz; // Average payload size for dropped bytes estimation
|
||||
|
||||
bool m_bTsbPdMode; // true: apply TimeStamp-Based Rx Mode
|
||||
uint32_t m_uTsbPdDelay; // aggreed delay
|
||||
uint64_t m_ullTsbPdTimeBase; // localtime base for TsbPd mode
|
||||
// Note: m_ullTsbPdTimeBase cumulates values from:
|
||||
// 1. Initial SRT_CMD_HSREQ packet returned value diff to current time:
|
||||
// == (NOW - PACKET_TIMESTAMP), at the time of HSREQ reception
|
||||
// 2. Timestamp overflow (@c CRcvBuffer::getTsbPdTimeBase), when overflow on packet detected
|
||||
// += CPacket::MAX_TIMESTAMP+1 (it's a hex round value, usually 0x1*e8).
|
||||
// 3. Time drift (CRcvBuffer::addRcvTsbPdDriftSample, executed exclusively
|
||||
// from UMSG_ACKACK handler). This is updated with (positive or negative) TSBPD_DRIFT_MAX_VALUE
|
||||
// once the value of average drift exceeds this value in whatever direction.
|
||||
// += (+/-)CRcvBuffer::TSBPD_DRIFT_MAX_VALUE
|
||||
//
|
||||
// XXX Application-supplied timestamps won't work therefore. This requires separate
|
||||
// calculation of all these things above.
|
||||
|
||||
bool m_bTsbPdWrapCheck; // true: check packet time stamp wrap around
|
||||
static const uint32_t TSBPD_WRAP_PERIOD = (30*1000000); //30 seconds (in usec)
|
||||
|
||||
static const int TSBPD_DRIFT_MAX_VALUE = 5000; // Max drift (usec) above which TsbPD Time Offset is adjusted
|
||||
static const int TSBPD_DRIFT_MAX_SAMPLES = 1000; // Number of samples (UMSG_ACKACK packets) to perform drift caclulation and compensation
|
||||
//int m_iTsbPdDrift; // recent drift in the packet time stamp
|
||||
//int64_t m_TsbPdDriftSum; // Sum of sampled drift
|
||||
//int m_iTsbPdDriftNbSamples; // Number of samples in sum and histogram
|
||||
DriftTracer<TSBPD_DRIFT_MAX_SAMPLES, TSBPD_DRIFT_MAX_VALUE> m_DriftTracer;
|
||||
#ifdef SRT_ENABLE_RCVBUFSZ_MAVG
|
||||
uint64_t m_LastSamplingTime;
|
||||
int m_TimespanMAvg;
|
||||
int m_iCountMAvg;
|
||||
int m_iBytesCountMAvg;
|
||||
#endif /* SRT_ENABLE_RCVBUFSZ_MAVG */
|
||||
#ifdef SRT_DEBUG_TSBPD_DRIFT
|
||||
int m_TsbPdDriftHisto100us[22]; // Histogram of 100us TsbPD drift (-1.0 .. +1.0 ms in 0.1ms increment)
|
||||
int m_TsbPdDriftHisto1ms[22]; // Histogram of TsbPD drift (-10.0 .. +10.0 ms, in 1.0 ms increment)
|
||||
static const int TSBPD_DRIFT_PRT_SAMPLES = 200; // Number of samples (UMSG_ACKACK packets) to print hostogram
|
||||
#endif /* SRT_DEBUG_TSBPD_DRIFT */
|
||||
/// Query if data is ready to read (tsbpdtime <= now if TsbPD is active).
|
||||
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay
|
||||
/// of next packet in recv buffer, ready or not.
|
||||
/// @param [out] curpktseq Sequence number of the packet if there is one ready to play
|
||||
/// @return true if ready to play, false otherwise (tsbpdtime may be !0 in
|
||||
/// both cases).
|
||||
bool isRcvDataReady(time_point& w_tsbpdtime, int32_t& w_curpktseq, int32_t seqdistance);
|
||||
|
||||
#ifdef SRT_DEBUG_TSBPD_OUTJITTER
|
||||
unsigned long m_ulPdHisto[4][10];
|
||||
#endif /* SRT_DEBUG_TSBPD_OUTJITTER */
|
||||
void debugTraceJitter(time_point t);
|
||||
#else
|
||||
void debugTraceJitter(time_point) {}
|
||||
#endif /* SRT_DEBUG_TSBPD_OUTJITTER */
|
||||
|
||||
bool isRcvDataReady();
|
||||
bool isRcvDataAvailable() { return m_iLastAckPos != m_iStartPos; }
|
||||
CPacket* getRcvReadyPacket(int32_t seqdistance);
|
||||
|
||||
/// Set TimeStamp-Based Packet Delivery Rx Mode
|
||||
/// @param [in] timebase localtime base (uSec) of packet time stamps including buffering delay
|
||||
/// @param [in] delay aggreed TsbPD delay
|
||||
void setRcvTsbPdMode(const time_point& timebase, const duration& delay);
|
||||
|
||||
/// Add packet timestamp for drift caclculation and compensation
|
||||
/// @param [in] timestamp packet time stamp
|
||||
/// @param [in] tsPktArrival arrival time of the packet used to extract the drift sample.
|
||||
/// @param [in] rtt RTT sample
|
||||
bool addRcvTsbPdDriftSample(uint32_t timestamp, const time_point& tsPktArrival, int rtt);
|
||||
|
||||
#ifdef SRT_DEBUG_TSBPD_DRIFT
|
||||
void printDriftHistogram(int64_t iDrift);
|
||||
void printDriftOffset(int tsbPdOffset, int tsbPdDriftAvg);
|
||||
#endif
|
||||
|
||||
/// Get information on the 1st message in queue.
|
||||
// Parameters (of the 1st packet queue, ready to play or not):
|
||||
/// @param [out] w_tsbpdtime localtime-based (uSec) packet time stamp including buffering delay of 1st packet or 0
|
||||
/// if none
|
||||
/// @param [out] w_passack true if 1st ready packet is not yet acknowleged (allowed to be delivered to the app)
|
||||
/// @param [out] w_skipseqno SRT_SEQNO_NONE or seq number of 1st unacknowledged pkt ready to play preceeded by
|
||||
/// missing packets.
|
||||
/// @param base_seq SRT_SEQNO_NONE or desired, ignore seq smaller than base if exist packet ready-to-play
|
||||
/// and larger than base
|
||||
/// @retval true 1st packet ready to play (tsbpdtime <= now). Not yet acknowledged if passack == true
|
||||
/// @retval false IF tsbpdtime = 0: rcv buffer empty; ELSE:
|
||||
/// IF skipseqno != SRT_SEQNO_NONE, packet ready to play preceeded by missing packets.;
|
||||
/// IF skipseqno == SRT_SEQNO_NONE, no missing packet but 1st not ready to play.
|
||||
bool getRcvFirstMsg(time_point& w_tsbpdtime,
|
||||
bool& w_passack,
|
||||
int32_t& w_skipseqno,
|
||||
int32_t& w_curpktseq,
|
||||
int32_t base_seq = SRT_SEQNO_NONE);
|
||||
|
||||
/// Update the ACK point of the buffer.
|
||||
/// @param [in] len size of data to be skip & acknowledged.
|
||||
void skipData(int len);
|
||||
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
void reportBufferStats() const; // Heavy logging Debug only
|
||||
#endif
|
||||
bool empty() const
|
||||
{
|
||||
// This will not always return the intended value,
|
||||
// that is, it may return false when the buffer really is
|
||||
// empty - but it will return true then in one of next calls.
|
||||
// This function will be always called again at some point
|
||||
// if it returned false, and on true the connection
|
||||
// is going to be broken - so this behavior is acceptable.
|
||||
return m_iStartPos == m_iLastAckPos;
|
||||
}
|
||||
bool full() const { return m_iStartPos == (m_iLastAckPos + 1) % m_iSize; }
|
||||
int capacity() const { return m_iSize; }
|
||||
|
||||
private:
|
||||
CRcvBuffer();
|
||||
CRcvBuffer(const CRcvBuffer&);
|
||||
CRcvBuffer& operator=(const CRcvBuffer&);
|
||||
/// This gives up unit at index p. The unit is given back to the
|
||||
/// free unit storage for further assignment for the new incoming
|
||||
/// data.
|
||||
size_t freeUnitAt(size_t p)
|
||||
{
|
||||
CUnit* u = m_pUnit[p];
|
||||
m_pUnit[p] = NULL;
|
||||
size_t rmbytes = u->m_Packet.getLength();
|
||||
m_pUnitQueue->makeUnitFree(u);
|
||||
return rmbytes;
|
||||
}
|
||||
|
||||
/// Adjust receive queue to 1st ready to play message (tsbpdtime < now).
|
||||
/// Parameters (of the 1st packet queue, ready to play or not):
|
||||
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay of 1st packet or 0 if
|
||||
/// none
|
||||
/// @param base_seq SRT_SEQNO_NONE or desired, ignore seq smaller than base
|
||||
/// @retval true 1st packet ready to play without discontinuity (no hole)
|
||||
/// @retval false tsbpdtime = 0: no packet ready to play
|
||||
bool getRcvReadyMsg(time_point& w_tsbpdtime, int32_t& w_curpktseq, int upto, int base_seq = SRT_SEQNO_NONE);
|
||||
|
||||
public:
|
||||
/// @brief Get clock drift in microseconds.
|
||||
int64_t getDrift() const { return m_tsbpd.drift(); }
|
||||
|
||||
public:
|
||||
int32_t getTopMsgno() const;
|
||||
|
||||
void getInternalTimeBase(time_point& w_tb, bool& w_wrp, duration& w_udrift);
|
||||
|
||||
void applyGroupTime(const time_point& timebase, bool wrapcheck, uint32_t delay, const duration& udrift);
|
||||
void applyGroupDrift(const time_point& timebase, bool wrapcheck, const duration& udrift);
|
||||
time_point getPktTsbPdTime(uint32_t timestamp);
|
||||
int debugGetSize() const;
|
||||
time_point debugGetDeliveryTime(int offset);
|
||||
|
||||
size_t dropData(int len);
|
||||
|
||||
private:
|
||||
int extractData(char* data, int len, int p, int q, bool passack);
|
||||
bool accessMsg(int& w_p, int& w_q, bool& w_passack, int64_t& w_playtime, int upto);
|
||||
|
||||
/// Describes the state of the first N packets
|
||||
std::string debugTimeState(size_t first_n_pkts) const;
|
||||
|
||||
/// thread safe bytes counter of the Recv & Ack buffer
|
||||
/// @param [in] pkts acked or removed pkts from rcv buffer (used with acked = true)
|
||||
/// @param [in] bytes number of bytes added/delete (if negative) to/from rcv buffer.
|
||||
/// @param [in] acked true when adding new pkt in RcvBuffer; false when acking/removing pkts to/from buffer
|
||||
void countBytes(int pkts, int bytes, bool acked = false);
|
||||
|
||||
private:
|
||||
bool scanMsg(int& w_start, int& w_end, bool& w_passack);
|
||||
|
||||
int shift(int basepos, int shift) const { return (basepos + shift) % m_iSize; }
|
||||
|
||||
/// Simplified versions with ++ and --; avoid using division instruction
|
||||
int shiftFwd(int basepos) const
|
||||
{
|
||||
if (++basepos == m_iSize)
|
||||
return 0;
|
||||
return basepos;
|
||||
}
|
||||
|
||||
int shiftBack(int basepos) const
|
||||
{
|
||||
if (basepos == 0)
|
||||
return m_iSize - 1;
|
||||
return --basepos;
|
||||
}
|
||||
|
||||
private:
|
||||
CUnit** m_pUnit; // Array of pointed units collected in the buffer
|
||||
const int m_iSize; // Size of the internal array of CUnit* items
|
||||
CUnitQueue* m_pUnitQueue; // the shared unit queue
|
||||
|
||||
int m_iStartPos; // HEAD: first packet available for reading
|
||||
int m_iLastAckPos; // the last ACKed position (exclusive), follows the last readable
|
||||
// EMPTY: m_iStartPos = m_iLastAckPos FULL: m_iStartPos = m_iLastAckPos + 1
|
||||
int m_iMaxPos; // delta between acked-TAIL and reception-TAIL
|
||||
|
||||
int m_iNotch; // the starting read point of the first unit
|
||||
// (this is required for stream reading mode; it's
|
||||
// the position in the first unit in the list
|
||||
// up to which data are already retrieved;
|
||||
// in message reading mode it's unused and always 0)
|
||||
|
||||
sync::Mutex m_BytesCountLock; // used to protect counters operations
|
||||
int m_iBytesCount; // Number of payload bytes in the buffer
|
||||
int m_iAckedPktsCount; // Number of acknowledged pkts in the buffer
|
||||
int m_iAckedBytesCount; // Number of acknowledged payload bytes in the buffer
|
||||
unsigned m_uAvgPayloadSz; // Average payload size for dropped bytes estimation
|
||||
|
||||
CTsbpdTime m_tsbpd;
|
||||
|
||||
AvgBufSize m_mavg;
|
||||
|
||||
private:
|
||||
CRcvBuffer();
|
||||
CRcvBuffer(const CRcvBuffer&);
|
||||
CRcvBuffer& operator=(const CRcvBuffer&);
|
||||
};
|
||||
|
||||
#endif // !ENABLE_NEW_RCVBUFFER
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
1072
trunk/3rdparty/srt-1-fit/srtcore/buffer_rcv.cpp
vendored
Normal file
1072
trunk/3rdparty/srt-1-fit/srtcore/buffer_rcv.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
367
trunk/3rdparty/srt-1-fit/srtcore/buffer_rcv.h
vendored
Normal file
367
trunk/3rdparty/srt-1-fit/srtcore/buffer_rcv.h
vendored
Normal file
|
@ -0,0 +1,367 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2020 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INC_SRT_BUFFER_RCV_H
|
||||
#define INC_SRT_BUFFER_RCV_H
|
||||
|
||||
#if ENABLE_NEW_RCVBUFFER
|
||||
|
||||
#include "buffer.h" // AvgBufSize
|
||||
#include "common.h"
|
||||
#include "queue.h"
|
||||
#include "sync.h"
|
||||
#include "tsbpd_time.h"
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
/*
|
||||
* Circular receiver buffer.
|
||||
*
|
||||
* |<------------------- m_szSize ---------------------------->|
|
||||
* | |<------------ m_iMaxPosInc ----------->| |
|
||||
* | | | |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+ +---+
|
||||
* | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |...| 0 | m_pUnit[]
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+ +---+
|
||||
* | |
|
||||
* | \__last pkt received
|
||||
* |
|
||||
* \___ m_iStartPos: first message to read
|
||||
*
|
||||
* m_pUnit[i]->status_: 0: free, 1: good, 2: read, 3: dropped (can be combined with read?)
|
||||
*
|
||||
* thread safety:
|
||||
* start_pos_: CUDT::m_RecvLock
|
||||
* first_unack_pos_: CUDT::m_AckLock
|
||||
* max_pos_inc_: none? (modified on add and ack
|
||||
* first_nonread_pos_:
|
||||
*/
|
||||
|
||||
class CRcvBufferNew
|
||||
{
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
typedef sync::steady_clock::duration duration;
|
||||
|
||||
public:
|
||||
CRcvBufferNew(int initSeqNo, size_t size, CUnitQueue* unitqueue, bool bMessageAPI);
|
||||
|
||||
~CRcvBufferNew();
|
||||
|
||||
public:
|
||||
/// Insert a unit into the buffer.
|
||||
/// Similar to CRcvBuffer::addData(CUnit* unit, int offset)
|
||||
///
|
||||
/// @param [in] unit pointer to a data unit containing new packet
|
||||
/// @param [in] offset offset from last ACK point.
|
||||
///
|
||||
/// @return 0 on success, -1 if packet is already in buffer, -2 if packet is before m_iStartSeqNo.
|
||||
/// -3 if a packet is offset is ahead the buffer capacity.
|
||||
// TODO: Previously '-2' also meant 'already acknowledged'. Check usage of this value.
|
||||
int insert(CUnit* unit);
|
||||
|
||||
/// Drop packets in the receiver buffer from the current position up to the seqno (excluding seqno).
|
||||
/// @param [in] seqno drop units up to this sequence number
|
||||
/// @return number of dropped packets.
|
||||
int dropUpTo(int32_t seqno);
|
||||
|
||||
/// @brief Drop all the packets in the receiver buffer.
|
||||
/// The starting position and seqno are shifted right after the last packet in the buffer.
|
||||
/// @return the number of dropped packets.
|
||||
int dropAll();
|
||||
|
||||
/// @brief Drop the whole message from the buffer.
|
||||
/// If message number is 0, then use sequence numbers to locate sequence range to drop [seqnolo, seqnohi].
|
||||
/// When one packet of the message is in the range of dropping, the whole message is to be dropped.
|
||||
/// @param seqnolo sequence number of the first packet in the dropping range.
|
||||
/// @param seqnohi sequence number of the last packet in the dropping range.
|
||||
/// @param msgno message number to drop (0 if unknown)
|
||||
/// @return the number of packets actually dropped.
|
||||
int dropMessage(int32_t seqnolo, int32_t seqnohi, int32_t msgno);
|
||||
|
||||
/// Read the whole message from one or several packets.
|
||||
///
|
||||
/// @param [in,out] data buffer to write the message into.
|
||||
/// @param [in] len size of the buffer.
|
||||
/// @param [in,out] message control data
|
||||
///
|
||||
/// @return actual number of bytes extracted from the buffer.
|
||||
/// 0 if nothing to read.
|
||||
/// -1 on failure.
|
||||
int readMessage(char* data, size_t len, SRT_MSGCTRL* msgctrl = NULL);
|
||||
|
||||
/// Read acknowledged data into a user buffer.
|
||||
/// @param [in, out] dst pointer to the target user buffer.
|
||||
/// @param [in] len length of user buffer.
|
||||
/// @return size of data read. -1 on error.
|
||||
int readBuffer(char* dst, int len);
|
||||
|
||||
/// Read acknowledged data directly into file.
|
||||
/// @param [in] ofs C++ file stream.
|
||||
/// @param [in] len expected length of data to write into the file.
|
||||
/// @return size of data read. -1 on error.
|
||||
int readBufferToFile(std::fstream& ofs, int len);
|
||||
|
||||
public:
|
||||
/// Get the starting position of the buffer as a packet sequence number.
|
||||
int getStartSeqNo() const { return m_iStartSeqNo; }
|
||||
|
||||
/// Sets the start seqno of the buffer.
|
||||
/// Must be used with caution and only when the buffer is empty.
|
||||
void setStartSeqNo(int seqno) { m_iStartSeqNo = seqno; }
|
||||
|
||||
/// Given the sequence number of the first unacknowledged packet
|
||||
/// tells the size of the buffer available for packets.
|
||||
/// Effective returns capacity of the buffer minus acknowledged packet still kept in it.
|
||||
// TODO: Maybe does not need to return minus one slot now to distinguish full and empty buffer.
|
||||
size_t getAvailSize(int iFirstUnackSeqNo) const
|
||||
{
|
||||
// Receiver buffer allows reading unacknowledged packets.
|
||||
// Therefore if the first packet in the buffer is ahead of the iFirstUnackSeqNo
|
||||
// then it does not have acknowledged packets and its full capacity is available.
|
||||
// Otherwise subtract the number of acknowledged but not yet read packets from its capacity.
|
||||
const int iRBufSeqNo = getStartSeqNo();
|
||||
if (CSeqNo::seqcmp(iRBufSeqNo, iFirstUnackSeqNo) >= 0) // iRBufSeqNo >= iFirstUnackSeqNo
|
||||
{
|
||||
// Full capacity is available, still don't want to encourage extra packets to come.
|
||||
// Note: CSeqNo::seqlen(n, n) returns 1.
|
||||
return capacity() - CSeqNo::seqlen(iFirstUnackSeqNo, iRBufSeqNo) + 1;
|
||||
}
|
||||
|
||||
// Note: CSeqNo::seqlen(n, n) returns 1.
|
||||
return capacity() - CSeqNo::seqlen(iRBufSeqNo, iFirstUnackSeqNo) + 1;
|
||||
}
|
||||
|
||||
/// @brief Checks if the buffer has packets available for reading regardless of the TSBPD.
|
||||
/// @return true if there are packets available for reading, false otherwise.
|
||||
bool hasAvailablePackets() const;
|
||||
|
||||
/// Query how many data has been continuously received (for reading) and available for reading out
|
||||
/// regardless of the TSBPD.
|
||||
/// TODO: Rename to countAvailablePackets().
|
||||
/// @return size of valid (continous) data for reading.
|
||||
int getRcvDataSize() const;
|
||||
|
||||
/// Get the number of packets, bytes and buffer timespan.
|
||||
/// Differs from getRcvDataSize() that it counts all packets in the buffer, not only continious.
|
||||
int getRcvDataSize(int& bytes, int& timespan) const;
|
||||
|
||||
struct PacketInfo
|
||||
{
|
||||
int seqno;
|
||||
bool seq_gap; //< true if there are missing packets in the buffer, preceding current packet
|
||||
time_point tsbpd_time;
|
||||
};
|
||||
|
||||
/// Get information on the 1st message in queue.
|
||||
/// Similar to CRcvBuffer::getRcvFirstMsg
|
||||
/// Parameters (of the 1st packet queue, ready to play or not):
|
||||
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay of 1st packet or 0 if
|
||||
/// none
|
||||
/// @param [out] passack true if 1st ready packet is not yet acknowleged (allowed to be delivered to the app)
|
||||
/// @param [out] skipseqno -1 or seq number of 1st unacknowledged pkt ready to play preceeded by missing packets.
|
||||
/// @retval true 1st packet ready to play (tsbpdtime <= now). Not yet acknowledged if passack == true
|
||||
/// @retval false IF tsbpdtime = 0: rcv buffer empty; ELSE:
|
||||
/// IF skipseqno != -1, packet ready to play preceeded by missing packets.;
|
||||
/// IF skipseqno == -1, no missing packet but 1st not ready to play.
|
||||
PacketInfo getFirstValidPacketInfo() const;
|
||||
|
||||
PacketInfo getFirstReadablePacketInfo(time_point time_now) const;
|
||||
|
||||
/// Get information on packets available to be read.
|
||||
/// @returns a pair of sequence numbers (first available; first unavailable).
|
||||
///
|
||||
/// @note CSeqNo::seqoff(first, second) is 0 if nothing to read.
|
||||
std::pair<int, int> getAvailablePacketsRange() const;
|
||||
|
||||
size_t countReadable() const;
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return (m_iMaxPosInc == 0);
|
||||
}
|
||||
|
||||
/// Return buffer capacity.
|
||||
/// One slot had to be empty in order to tell the difference between "empty buffer" and "full buffer".
|
||||
/// E.g. m_iFirstNonreadPos would again point to m_iStartPos if m_szSize entries are added continiously.
|
||||
/// TODO: Old receiver buffer capacity returns the actual size. Check for conflicts.
|
||||
size_t capacity() const
|
||||
{
|
||||
return m_szSize - 1;
|
||||
}
|
||||
|
||||
int64_t getDrift() const { return m_tsbpd.drift(); }
|
||||
|
||||
// TODO: make thread safe?
|
||||
int debugGetSize() const
|
||||
{
|
||||
return getRcvDataSize();
|
||||
}
|
||||
|
||||
/// Zero time to include all available packets.
|
||||
/// TODO: Rename to 'canRead`.
|
||||
bool isRcvDataReady(time_point time_now = time_point()) const;
|
||||
|
||||
int getRcvAvgDataSize(int& bytes, int& timespan);
|
||||
void updRcvAvgDataSize(const time_point& now);
|
||||
|
||||
unsigned getRcvAvgPayloadSize() const { return m_uAvgPayloadSz; }
|
||||
|
||||
void getInternalTimeBase(time_point& w_timebase, bool& w_wrp, duration& w_udrift)
|
||||
{
|
||||
return m_tsbpd.getInternalTimeBase(w_timebase, w_wrp, w_udrift);
|
||||
}
|
||||
|
||||
public: // Used for testing
|
||||
/// Peek unit in position of seqno
|
||||
const CUnit* peek(int32_t seqno);
|
||||
|
||||
private:
|
||||
inline int incPos(int pos, int inc = 1) const { return (pos + inc) % m_szSize; }
|
||||
inline int decPos(int pos) const { return (pos - 1) >= 0 ? (pos - 1) : int(m_szSize - 1); }
|
||||
inline int offPos(int pos1, int pos2) const { return (pos2 >= pos1) ? (pos2 - pos1) : int(m_szSize + pos2 - pos1); }
|
||||
|
||||
private:
|
||||
void countBytes(int pkts, int bytes);
|
||||
void updateNonreadPos();
|
||||
void releaseUnitInPos(int pos);
|
||||
|
||||
/// @brief Drop a unit from the buffer.
|
||||
/// @param pos position in the m_entries of the unit to drop.
|
||||
/// @return false if nothing to drop, true if the unit was dropped successfully.
|
||||
bool dropUnitInPos(int pos);
|
||||
|
||||
/// Release entries following the current buffer position if they were already
|
||||
/// read out of order (EntryState_Read) or dropped (EntryState_Drop).
|
||||
void releaseNextFillerEntries();
|
||||
|
||||
bool hasReadableInorderPkts() const { return (m_iFirstNonreadPos != m_iStartPos); }
|
||||
|
||||
/// Find position of the last packet of the message.
|
||||
int findLastMessagePkt();
|
||||
|
||||
/// Scan for availability of out of order packets.
|
||||
void onInsertNotInOrderPacket(int insertpos);
|
||||
// Check if m_iFirstReadableOutOfOrder is still readable.
|
||||
bool checkFirstReadableOutOfOrder();
|
||||
void updateFirstReadableOutOfOrder();
|
||||
int scanNotInOrderMessageRight(int startPos, int msgNo) const;
|
||||
int scanNotInOrderMessageLeft(int startPos, int msgNo) const;
|
||||
|
||||
typedef bool copy_to_dst_f(char* data, int len, int dst_offset, void* arg);
|
||||
|
||||
/// Read acknowledged data directly into file.
|
||||
/// @param [in] ofs C++ file stream.
|
||||
/// @param [in] len expected length of data to write into the file.
|
||||
/// @return size of data read.
|
||||
int readBufferTo(int len, copy_to_dst_f funcCopyToDst, void* arg);
|
||||
|
||||
/// @brief Estimate timespan of the stored packets (acknowledged and unacknowledged).
|
||||
/// @return timespan in milliseconds
|
||||
int getTimespan_ms() const;
|
||||
|
||||
private:
|
||||
// TODO: Call makeUnitGood upon assignment, and makeUnitFree upon clearing.
|
||||
// TODO: CUnitPtr is not in use at the moment, but may be a smart pointer.
|
||||
// class CUnitPtr
|
||||
// {
|
||||
// public:
|
||||
// void operator=(CUnit* pUnit)
|
||||
// {
|
||||
// if (m_pUnit != NULL)
|
||||
// {
|
||||
// // m_pUnitQueue->makeUnitFree(m_entries[i].pUnit);
|
||||
// }
|
||||
// m_pUnit = pUnit;
|
||||
// }
|
||||
// private:
|
||||
// CUnit* m_pUnit;
|
||||
// };
|
||||
|
||||
enum EntryStatus
|
||||
{
|
||||
EntryState_Empty, //< No CUnit record.
|
||||
EntryState_Avail, //< Entry is available for reading.
|
||||
EntryState_Read, //< Entry has already been read (out of order).
|
||||
EntryState_Drop //< Entry has been dropped.
|
||||
};
|
||||
struct Entry
|
||||
{
|
||||
Entry()
|
||||
: pUnit(NULL)
|
||||
, status(EntryState_Empty)
|
||||
{}
|
||||
|
||||
CUnit* pUnit;
|
||||
EntryStatus status;
|
||||
};
|
||||
|
||||
//static Entry emptyEntry() { return Entry { NULL, EntryState_Empty }; }
|
||||
|
||||
FixedArray<Entry> m_entries;
|
||||
|
||||
const size_t m_szSize; // size of the array of units (buffer)
|
||||
CUnitQueue* m_pUnitQueue; // the shared unit queue
|
||||
|
||||
int m_iStartSeqNo;
|
||||
int m_iStartPos; // the head position for I/O (inclusive)
|
||||
int m_iFirstNonreadPos; // First position that can't be read (<= m_iLastAckPos)
|
||||
int m_iMaxPosInc; // the furthest data position
|
||||
int m_iNotch; // the starting read point of the first unit
|
||||
|
||||
size_t m_numOutOfOrderPackets; // The number of stored packets with "inorder" flag set to false
|
||||
int m_iFirstReadableOutOfOrder; // In case of out ouf order packet, points to a position of the first such packet to
|
||||
// read
|
||||
bool m_bPeerRexmitFlag; // Needed to read message number correctly
|
||||
const bool m_bMessageAPI; // Operation mode flag: message or stream.
|
||||
|
||||
public: // TSBPD public functions
|
||||
/// Set TimeStamp-Based Packet Delivery Rx Mode
|
||||
/// @param [in] timebase localtime base (uSec) of packet time stamps including buffering delay
|
||||
/// @param [in] wrap Is in wrapping period
|
||||
/// @param [in] delay aggreed TsbPD delay
|
||||
///
|
||||
/// @return 0
|
||||
void setTsbPdMode(const time_point& timebase, bool wrap, duration delay);
|
||||
|
||||
void setPeerRexmitFlag(bool flag) { m_bPeerRexmitFlag = flag; }
|
||||
|
||||
void applyGroupTime(const time_point& timebase, bool wrp, uint32_t delay, const duration& udrift);
|
||||
|
||||
void applyGroupDrift(const time_point& timebase, bool wrp, const duration& udrift);
|
||||
|
||||
bool addRcvTsbPdDriftSample(uint32_t usTimestamp, const time_point& tsPktArrival, int usRTTSample);
|
||||
|
||||
time_point getPktTsbPdTime(uint32_t usPktTimestamp) const;
|
||||
|
||||
time_point getTsbPdTimeBase(uint32_t usPktTimestamp) const;
|
||||
void updateTsbPdTimeBase(uint32_t usPktTimestamp);
|
||||
|
||||
/// Form a string of the current buffer fullness state.
|
||||
/// number of packets acknowledged, TSBPD readiness, etc.
|
||||
std::string strFullnessState(int iFirstUnackSeqNo, const time_point& tsNow) const;
|
||||
|
||||
private:
|
||||
CTsbpdTime m_tsbpd;
|
||||
|
||||
private: // Statistics
|
||||
AvgBufSize m_mavg;
|
||||
|
||||
// TODO: m_BytesCountLock is probably not needed as the buffer has to be protected from simultaneous access.
|
||||
mutable sync::Mutex m_BytesCountLock; // used to protect counters operations
|
||||
int m_iBytesCount; // Number of payload bytes in the buffer
|
||||
int m_iPktsCount; // Number of payload bytes in the buffer
|
||||
unsigned m_uAvgPayloadSz; // Average payload size for dropped bytes estimation
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif // ENABLE_NEW_RCVBUFFER
|
||||
#endif // INC_SRT_BUFFER_RCV_H
|
52
trunk/3rdparty/srt-1-fit/srtcore/cache.cpp
vendored
52
trunk/3rdparty/srt-1-fit/srtcore/cache.cpp
vendored
|
@ -38,10 +38,8 @@ written by
|
|||
Yunhong Gu, last updated 05/05/2009
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <cstring>
|
||||
#include "cache.h"
|
||||
|
@ -49,22 +47,22 @@ written by
|
|||
|
||||
using namespace std;
|
||||
|
||||
CInfoBlock& CInfoBlock::operator=(const CInfoBlock& obj)
|
||||
srt::CInfoBlock& srt::CInfoBlock::copyFrom(const CInfoBlock& obj)
|
||||
{
|
||||
std::copy(obj.m_piIP, obj.m_piIP + 4, m_piIP);
|
||||
m_iIPversion = obj.m_iIPversion;
|
||||
m_ullTimeStamp = obj.m_ullTimeStamp;
|
||||
m_iRTT = obj.m_iRTT;
|
||||
m_iBandwidth = obj.m_iBandwidth;
|
||||
m_iLossRate = obj.m_iLossRate;
|
||||
m_iIPversion = obj.m_iIPversion;
|
||||
m_ullTimeStamp = obj.m_ullTimeStamp;
|
||||
m_iSRTT = obj.m_iSRTT;
|
||||
m_iBandwidth = obj.m_iBandwidth;
|
||||
m_iLossRate = obj.m_iLossRate;
|
||||
m_iReorderDistance = obj.m_iReorderDistance;
|
||||
m_dInterval = obj.m_dInterval;
|
||||
m_dCWnd = obj.m_dCWnd;
|
||||
m_dInterval = obj.m_dInterval;
|
||||
m_dCWnd = obj.m_dCWnd;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CInfoBlock::operator==(const CInfoBlock& obj)
|
||||
bool srt::CInfoBlock::operator==(const CInfoBlock& obj)
|
||||
{
|
||||
if (m_iIPversion != obj.m_iIPversion)
|
||||
return false;
|
||||
|
@ -81,24 +79,24 @@ bool CInfoBlock::operator==(const CInfoBlock& obj)
|
|||
return true;
|
||||
}
|
||||
|
||||
CInfoBlock* CInfoBlock::clone()
|
||||
srt::CInfoBlock* srt::CInfoBlock::clone()
|
||||
{
|
||||
CInfoBlock* obj = new CInfoBlock;
|
||||
|
||||
std::copy(m_piIP, m_piIP + 4, obj->m_piIP);
|
||||
obj->m_iIPversion = m_iIPversion;
|
||||
obj->m_ullTimeStamp = m_ullTimeStamp;
|
||||
obj->m_iRTT = m_iRTT;
|
||||
obj->m_iBandwidth = m_iBandwidth;
|
||||
obj->m_iLossRate = m_iLossRate;
|
||||
obj->m_iIPversion = m_iIPversion;
|
||||
obj->m_ullTimeStamp = m_ullTimeStamp;
|
||||
obj->m_iSRTT = m_iSRTT;
|
||||
obj->m_iBandwidth = m_iBandwidth;
|
||||
obj->m_iLossRate = m_iLossRate;
|
||||
obj->m_iReorderDistance = m_iReorderDistance;
|
||||
obj->m_dInterval = m_dInterval;
|
||||
obj->m_dCWnd = m_dCWnd;
|
||||
obj->m_dInterval = m_dInterval;
|
||||
obj->m_dCWnd = m_dCWnd;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
int CInfoBlock::getKey()
|
||||
int srt::CInfoBlock::getKey()
|
||||
{
|
||||
if (m_iIPversion == AF_INET)
|
||||
return m_piIP[0];
|
||||
|
@ -106,15 +104,15 @@ int CInfoBlock::getKey()
|
|||
return m_piIP[0] + m_piIP[1] + m_piIP[2] + m_piIP[3];
|
||||
}
|
||||
|
||||
void CInfoBlock::convert(const sockaddr* addr, int ver, uint32_t ip[])
|
||||
void srt::CInfoBlock::convert(const sockaddr_any& addr, uint32_t aw_ip[4])
|
||||
{
|
||||
if (ver == AF_INET)
|
||||
if (addr.family() == AF_INET)
|
||||
{
|
||||
ip[0] = ((sockaddr_in*)addr)->sin_addr.s_addr;
|
||||
ip[1] = ip[2] = ip[3] = 0;
|
||||
aw_ip[0] = addr.sin.sin_addr.s_addr;
|
||||
aw_ip[1] = aw_ip[2] = aw_ip[3] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy((char*)ip, (char*)((sockaddr_in6*)addr)->sin6_addr.s6_addr, 16);
|
||||
memcpy((aw_ip), addr.sin6.sin6_addr.s6_addr, sizeof addr.sin6.sin6_addr.s6_addr);
|
||||
}
|
||||
}
|
||||
|
|
55
trunk/3rdparty/srt-1-fit/srtcore/cache.h
vendored
55
trunk/3rdparty/srt-1-fit/srtcore/cache.h
vendored
|
@ -38,15 +38,19 @@ written by
|
|||
Yunhong Gu, last updated 01/27/2011
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_CACHE_H__
|
||||
#define __UDT_CACHE_H__
|
||||
#ifndef INC_SRT_CACHE_H
|
||||
#define INC_SRT_CACHE_H
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "common.h"
|
||||
#include "sync.h"
|
||||
#include "netinet_any.h"
|
||||
#include "udt.h"
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
class CCacheItem
|
||||
{
|
||||
public:
|
||||
|
@ -82,13 +86,13 @@ public:
|
|||
m_iCurrSize(0)
|
||||
{
|
||||
m_vHashPtr.resize(m_iHashSize);
|
||||
CGuard::createMutex(m_Lock);
|
||||
// Exception: -> CUDTUnited ctor
|
||||
srt::sync::setupMutex(m_Lock, "Cache");
|
||||
}
|
||||
|
||||
~CCache()
|
||||
{
|
||||
clear();
|
||||
CGuard::releaseMutex(m_Lock);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -98,7 +102,7 @@ public:
|
|||
|
||||
int lookup(T* data)
|
||||
{
|
||||
CGuard cacheguard(m_Lock);
|
||||
srt::sync::ScopedLock cacheguard(m_Lock);
|
||||
|
||||
int key = data->getKey();
|
||||
if (key < 0)
|
||||
|
@ -126,7 +130,7 @@ public:
|
|||
|
||||
int update(T* data)
|
||||
{
|
||||
CGuard cacheguard(m_Lock);
|
||||
srt::sync::ScopedLock cacheguard(m_Lock);
|
||||
|
||||
int key = data->getKey();
|
||||
if (key < 0)
|
||||
|
@ -223,7 +227,7 @@ private:
|
|||
int m_iHashSize;
|
||||
int m_iCurrSize;
|
||||
|
||||
pthread_mutex_t m_Lock;
|
||||
srt::sync::Mutex m_Lock;
|
||||
|
||||
private:
|
||||
CCache(const CCache&);
|
||||
|
@ -234,23 +238,25 @@ private:
|
|||
class CInfoBlock
|
||||
{
|
||||
public:
|
||||
uint32_t m_piIP[4]; // IP address, machine read only, not human readable format
|
||||
int m_iIPversion; // IP version
|
||||
uint64_t m_ullTimeStamp; // last update time
|
||||
int m_iRTT; // RTT
|
||||
int m_iBandwidth; // estimated bandwidth
|
||||
int m_iLossRate; // average loss rate
|
||||
int m_iReorderDistance; // packet reordering distance
|
||||
double m_dInterval; // inter-packet time, congestion control
|
||||
double m_dCWnd; // congestion window size, congestion control
|
||||
uint32_t m_piIP[4]; // IP address, machine read only, not human readable format.
|
||||
int m_iIPversion; // Address family: AF_INET or AF_INET6.
|
||||
uint64_t m_ullTimeStamp; // Last update time.
|
||||
int m_iSRTT; // Smoothed RTT.
|
||||
int m_iBandwidth; // Estimated link bandwidth.
|
||||
int m_iLossRate; // Average loss rate.
|
||||
int m_iReorderDistance; // Packet reordering distance.
|
||||
double m_dInterval; // Inter-packet time (Congestion Control).
|
||||
double m_dCWnd; // Congestion window size (Congestion Control).
|
||||
|
||||
public:
|
||||
virtual ~CInfoBlock() {}
|
||||
virtual CInfoBlock& operator=(const CInfoBlock& obj);
|
||||
virtual bool operator==(const CInfoBlock& obj);
|
||||
virtual CInfoBlock* clone();
|
||||
virtual int getKey();
|
||||
virtual void release() {}
|
||||
CInfoBlock() {} // NOTE: leaves uninitialized
|
||||
CInfoBlock& copyFrom(const CInfoBlock& obj);
|
||||
CInfoBlock(const CInfoBlock& src) { copyFrom(src); }
|
||||
CInfoBlock& operator=(const CInfoBlock& src) { return copyFrom(src); }
|
||||
bool operator==(const CInfoBlock& obj);
|
||||
CInfoBlock* clone();
|
||||
int getKey();
|
||||
void release() {}
|
||||
|
||||
public:
|
||||
|
||||
|
@ -259,8 +265,9 @@ public:
|
|||
/// @param [in] ver IP version
|
||||
/// @param [out] ip the result machine readable IP address in integer array
|
||||
|
||||
static void convert(const sockaddr* addr, int ver, uint32_t ip[]);
|
||||
static void convert(const sockaddr_any& addr, uint32_t ip[4]);
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
993
trunk/3rdparty/srt-1-fit/srtcore/channel.cpp
vendored
993
trunk/3rdparty/srt-1-fit/srtcore/channel.cpp
vendored
File diff suppressed because it is too large
Load diff
162
trunk/3rdparty/srt-1-fit/srtcore/channel.h
vendored
162
trunk/3rdparty/srt-1-fit/srtcore/channel.h
vendored
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -50,138 +50,118 @@ modified by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_CHANNEL_H__
|
||||
#define __UDT_CHANNEL_H__
|
||||
|
||||
#ifndef INC_SRT_CHANNEL_H
|
||||
#define INC_SRT_CHANNEL_H
|
||||
|
||||
#include "platform_sys.h"
|
||||
#include "udt.h"
|
||||
#include "packet.h"
|
||||
#include "socketconfig.h"
|
||||
#include "netinet_any.h"
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
class CChannel
|
||||
{
|
||||
void createSocket(int family);
|
||||
|
||||
public:
|
||||
// XXX There's currently no way to access the socket ID set for
|
||||
// whatever the channel is currently working for. Required to find
|
||||
// some way to do this, possibly by having a "reverse pointer".
|
||||
// Currently just "unimplemented".
|
||||
std::string CONID() const { return ""; }
|
||||
|
||||
// XXX There's currently no way to access the socket ID set for
|
||||
// whatever the channel is currently working for. Required to find
|
||||
// some way to do this, possibly by having a "reverse pointer".
|
||||
// Currently just "unimplemented".
|
||||
std::string CONID() const { return ""; }
|
||||
CChannel();
|
||||
~CChannel();
|
||||
|
||||
CChannel();
|
||||
CChannel(int version);
|
||||
~CChannel();
|
||||
/// Open a UDP channel.
|
||||
/// @param [in] addr The local address that UDP will use.
|
||||
|
||||
/// Open a UDP channel.
|
||||
/// @param [in] addr The local address that UDP will use.
|
||||
void open(const sockaddr_any& addr);
|
||||
|
||||
void open(const sockaddr* addr = NULL);
|
||||
void open(int family);
|
||||
|
||||
/// Open a UDP channel based on an existing UDP socket.
|
||||
/// @param [in] udpsock UDP socket descriptor.
|
||||
/// Open a UDP channel based on an existing UDP socket.
|
||||
/// @param [in] udpsock UDP socket descriptor.
|
||||
|
||||
void attach(UDPSOCKET udpsock);
|
||||
void attach(UDPSOCKET udpsock, const sockaddr_any& adr);
|
||||
|
||||
/// Disconnect and close the UDP entity.
|
||||
/// Disconnect and close the UDP entity.
|
||||
|
||||
void close() const;
|
||||
void close() const;
|
||||
|
||||
/// Get the UDP sending buffer size.
|
||||
/// @return Current UDP sending buffer size.
|
||||
/// Get the UDP sending buffer size.
|
||||
/// @return Current UDP sending buffer size.
|
||||
|
||||
int getSndBufSize();
|
||||
int getSndBufSize();
|
||||
|
||||
/// Get the UDP receiving buffer size.
|
||||
/// @return Current UDP receiving buffer size.
|
||||
/// Get the UDP receiving buffer size.
|
||||
/// @return Current UDP receiving buffer size.
|
||||
|
||||
int getRcvBufSize();
|
||||
int getRcvBufSize();
|
||||
|
||||
/// Set the UDP sending buffer size.
|
||||
/// @param [in] size expected UDP sending buffer size.
|
||||
/// Query the socket address that the channel is using.
|
||||
/// @param [out] addr pointer to store the returned socket address.
|
||||
|
||||
void setSndBufSize(int size);
|
||||
void getSockAddr(sockaddr_any& addr) const;
|
||||
|
||||
/// Set the UDP receiving buffer size.
|
||||
/// @param [in] size expected UDP receiving buffer size.
|
||||
/// Query the peer side socket address that the channel is connect to.
|
||||
/// @param [out] addr pointer to store the returned socket address.
|
||||
|
||||
void setRcvBufSize(int size);
|
||||
void getPeerAddr(sockaddr_any& addr) const;
|
||||
|
||||
/// Set the IPV6ONLY option.
|
||||
/// @param [in] IPV6ONLY value.
|
||||
/// Send a packet to the given address.
|
||||
/// @param [in] addr pointer to the destination address.
|
||||
/// @param [in] packet reference to a CPacket entity.
|
||||
/// @return Actual size of data sent.
|
||||
|
||||
void setIpV6Only(int ipV6Only);
|
||||
int sendto(const sockaddr_any& addr, srt::CPacket& packet) const;
|
||||
|
||||
/// Query the socket address that the channel is using.
|
||||
/// @param [out] addr pointer to store the returned socket address.
|
||||
/// Receive a packet from the channel and record the source address.
|
||||
/// @param [in] addr pointer to the source address.
|
||||
/// @param [in] packet reference to a CPacket entity.
|
||||
/// @return Actual size of data received.
|
||||
|
||||
void getSockAddr(sockaddr* addr) const;
|
||||
EReadStatus recvfrom(sockaddr_any& addr, srt::CPacket& packet) const;
|
||||
|
||||
/// Query the peer side socket address that the channel is connect to.
|
||||
/// @param [out] addr pointer to store the returned socket address.
|
||||
void setConfig(const CSrtMuxerConfig& config);
|
||||
|
||||
void getPeerAddr(sockaddr* addr) const;
|
||||
/// Get the IP TTL.
|
||||
/// @param [in] ttl IP Time To Live.
|
||||
/// @return TTL.
|
||||
|
||||
/// Send a packet to the given address.
|
||||
/// @param [in] addr pointer to the destination address.
|
||||
/// @param [in] packet reference to a CPacket entity.
|
||||
/// @return Actual size of data sent.
|
||||
int getIpTTL() const;
|
||||
|
||||
int sendto(const sockaddr* addr, CPacket& packet) const;
|
||||
/// Get the IP Type of Service.
|
||||
/// @return ToS.
|
||||
|
||||
/// Receive a packet from the channel and record the source address.
|
||||
/// @param [in] addr pointer to the source address.
|
||||
/// @param [in] packet reference to a CPacket entity.
|
||||
/// @return Actual size of data received.
|
||||
int getIpToS() const;
|
||||
|
||||
EReadStatus recvfrom(sockaddr* addr, CPacket& packet) const;
|
||||
|
||||
#ifdef SRT_ENABLE_IPOPTS
|
||||
/// Set the IP TTL.
|
||||
/// @param [in] ttl IP Time To Live.
|
||||
/// @return none.
|
||||
|
||||
void setIpTTL(int ttl);
|
||||
|
||||
/// Set the IP Type of Service.
|
||||
/// @param [in] tos IP Type of Service.
|
||||
|
||||
void setIpToS(int tos);
|
||||
|
||||
/// Get the IP TTL.
|
||||
/// @param [in] ttl IP Time To Live.
|
||||
/// @return TTL.
|
||||
|
||||
int getIpTTL() const;
|
||||
|
||||
/// Get the IP Type of Service.
|
||||
/// @return ToS.
|
||||
|
||||
int getIpToS() const;
|
||||
#ifdef SRT_ENABLE_BINDTODEVICE
|
||||
bool getBind(char* dst, size_t len);
|
||||
#endif
|
||||
|
||||
int ioctlQuery(int type) const;
|
||||
int sockoptQuery(int level, int option) const;
|
||||
int ioctlQuery(int type) const;
|
||||
int sockoptQuery(int level, int option) const;
|
||||
|
||||
const sockaddr* bindAddress() { return &m_BindAddr; }
|
||||
const sockaddr_any& bindAddressAny() { return m_BindAddr; }
|
||||
const sockaddr* bindAddress() { return m_BindAddr.get(); }
|
||||
const sockaddr_any& bindAddressAny() { return m_BindAddr; }
|
||||
|
||||
private:
|
||||
void setUDPSockOpt();
|
||||
void setUDPSockOpt();
|
||||
|
||||
private:
|
||||
const int m_iIPversion; // IP version
|
||||
int m_iSockAddrSize; // socket address structure size (pre-defined to avoid run-time test)
|
||||
UDPSOCKET m_iSocket; // socket descriptor
|
||||
|
||||
UDPSOCKET m_iSocket; // socket descriptor
|
||||
#ifdef SRT_ENABLE_IPOPTS
|
||||
int m_iIpTTL;
|
||||
int m_iIpToS;
|
||||
#endif
|
||||
int m_iSndBufSize; // UDP sending buffer size
|
||||
int m_iRcvBufSize; // UDP receiving buffer size
|
||||
int m_iIpV6Only; // IPV6_V6ONLY option (-1 if not set)
|
||||
sockaddr_any m_BindAddr;
|
||||
// Mutable because when querying original settings
|
||||
// this comprises the cache for extracted values,
|
||||
// although the object itself isn't considered modified.
|
||||
mutable CSrtMuxerConfig m_mcfg; // Note: ReuseAddr is unused and ineffective.
|
||||
sockaddr_any m_BindAddr;
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
911
trunk/3rdparty/srt-1-fit/srtcore/common.cpp
vendored
911
trunk/3rdparty/srt-1-fit/srtcore/common.cpp
vendored
File diff suppressed because it is too large
Load diff
967
trunk/3rdparty/srt-1-fit/srtcore/common.h
vendored
967
trunk/3rdparty/srt-1-fit/srtcore/common.h
vendored
File diff suppressed because it is too large
Load diff
129
trunk/3rdparty/srt-1-fit/srtcore/congctl.cpp
vendored
129
trunk/3rdparty/srt-1-fit/srtcore/congctl.cpp
vendored
|
@ -12,7 +12,7 @@
|
|||
// This is a controversial thing, so temporarily blocking
|
||||
//#define SRT_ENABLE_SYSTEMBUFFER_TRACE
|
||||
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
||||
|
||||
#ifdef SRT_ENABLE_SYSTEMBUFFER_TRACE
|
||||
|
@ -34,8 +34,11 @@
|
|||
#include "logging.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace srt::sync;
|
||||
using namespace srt_logging;
|
||||
|
||||
namespace srt {
|
||||
|
||||
SrtCongestionControlBase::SrtCongestionControlBase(CUDT* parent)
|
||||
{
|
||||
m_parent = parent;
|
||||
|
@ -58,7 +61,7 @@ void SrtCongestion::Check()
|
|||
class LiveCC: public SrtCongestionControlBase
|
||||
{
|
||||
int64_t m_llSndMaxBW; //Max bandwidth (bytes/sec)
|
||||
size_t m_zSndAvgPayloadSize; //Average Payload Size of packets to xmit
|
||||
srt::sync::atomic<size_t> m_zSndAvgPayloadSize; //Average Payload Size of packets to xmit
|
||||
size_t m_zMaxPayloadSize;
|
||||
|
||||
// NAKREPORT stuff.
|
||||
|
@ -74,12 +77,12 @@ public:
|
|||
{
|
||||
m_llSndMaxBW = BW_INFINITE; // 1 Gbbps in Bytes/sec BW_INFINITE
|
||||
m_zMaxPayloadSize = parent->OPT_PayloadSize();
|
||||
if ( m_zMaxPayloadSize == 0 )
|
||||
if (m_zMaxPayloadSize == 0)
|
||||
m_zMaxPayloadSize = parent->maxPayloadSize();
|
||||
m_zSndAvgPayloadSize = m_zMaxPayloadSize;
|
||||
|
||||
m_iMinNakInterval_us = 20000; //Minimum NAK Report Period (usec)
|
||||
m_iNakReportAccel = 2; //Default NAK Report Period (RTT) accelerator
|
||||
m_iNakReportAccel = 2; //Default NAK Report Period (RTT) accelerator (send periodic NAK every RTT/2)
|
||||
|
||||
HLOGC(cclog.Debug, log << "Creating LiveCC: bw=" << m_llSndMaxBW << " avgplsize=" << m_zSndAvgPayloadSize);
|
||||
|
||||
|
@ -90,11 +93,11 @@ public:
|
|||
// from receiving thread.
|
||||
parent->ConnectSignal(TEV_SEND, SSLOT(updatePayloadSize));
|
||||
|
||||
/*
|
||||
* Readjust the max SndPeriod onACK (and onTimeout)
|
||||
*/
|
||||
parent->ConnectSignal(TEV_CHECKTIMER, SSLOT(updatePktSndPeriod_onTimer));
|
||||
parent->ConnectSignal(TEV_ACK, SSLOT(updatePktSndPeriod_onAck));
|
||||
//
|
||||
// Adjust the max SndPeriod onACK and onTimeout.
|
||||
//
|
||||
parent->ConnectSignal(TEV_CHECKTIMER, SSLOT(onRTO));
|
||||
parent->ConnectSignal(TEV_ACK, SSLOT(onAck));
|
||||
}
|
||||
|
||||
bool checkTransArgs(SrtCongestion::TransAPI api, SrtCongestion::TransDir dir, const char* , size_t size, int , bool ) ATR_OVERRIDE
|
||||
|
@ -151,24 +154,30 @@ private:
|
|||
HLOGC(cclog.Debug, log << "LiveCC: avg payload size updated: " << m_zSndAvgPayloadSize);
|
||||
}
|
||||
|
||||
void updatePktSndPeriod_onTimer(ETransmissionEvent , EventVariant var)
|
||||
/// @brief On RTO event update an inter-packet send interval.
|
||||
/// @param arg EventVariant::STAGE to distinguish between INIT and actual RTO.
|
||||
void onRTO(ETransmissionEvent , EventVariant var)
|
||||
{
|
||||
if ( var.get<EventVariant::STAGE>() != TEV_CHT_INIT )
|
||||
if (var.get<EventVariant::STAGE>() != TEV_CHT_INIT )
|
||||
updatePktSndPeriod();
|
||||
}
|
||||
|
||||
void updatePktSndPeriod_onAck(ETransmissionEvent , EventVariant )
|
||||
/// @brief Handle an incoming ACK event.
|
||||
/// Mainly updates a send interval between packets relying on the maximum BW limit.
|
||||
void onAck(ETransmissionEvent, EventVariant )
|
||||
{
|
||||
updatePktSndPeriod();
|
||||
}
|
||||
|
||||
/// @brief Updates a send interval between packets relying on the maximum BW limit.
|
||||
void updatePktSndPeriod()
|
||||
{
|
||||
// packet = payload + header
|
||||
const double pktsize = (double) m_zSndAvgPayloadSize + CPacket::SRT_DATA_HDR_SIZE;
|
||||
const double pktsize = (double) m_zSndAvgPayloadSize.load() + CPacket::SRT_DATA_HDR_SIZE;
|
||||
m_dPktSndPeriod = 1000 * 1000.0 * (pktsize / m_llSndMaxBW);
|
||||
HLOGC(cclog.Debug, log << "LiveCC: sending period updated: " << m_dPktSndPeriod
|
||||
<< " (pktsize=" << pktsize << ", bw=" << m_llSndMaxBW);
|
||||
<< " by avg pktsize=" << m_zSndAvgPayloadSize
|
||||
<< ", bw=" << m_llSndMaxBW);
|
||||
}
|
||||
|
||||
void setMaxBW(int64_t maxbw)
|
||||
|
@ -176,7 +185,6 @@ private:
|
|||
m_llSndMaxBW = maxbw > 0 ? maxbw : BW_INFINITE;
|
||||
updatePktSndPeriod();
|
||||
|
||||
#ifdef SRT_ENABLE_NOCWND
|
||||
/*
|
||||
* UDT default flow control should not trigger under normal SRT operation
|
||||
* UDT stops sending if the number of packets in transit (not acknowledged)
|
||||
|
@ -186,9 +194,6 @@ private:
|
|||
*/
|
||||
// XXX Consider making this a socket option.
|
||||
m_dCWndSize = m_dMaxCWndSize;
|
||||
#else
|
||||
m_dCWndSize = 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
void updateBandwidth(int64_t maxbw, int64_t bw) ATR_OVERRIDE
|
||||
|
@ -215,7 +220,7 @@ private:
|
|||
return SrtCongestion::SRM_FASTREXMIT;
|
||||
}
|
||||
|
||||
uint64_t updateNAKInterval(uint64_t nakint_tk, int /*rcv_speed*/, size_t /*loss_length*/) ATR_OVERRIDE
|
||||
int64_t updateNAKInterval(int64_t nakint_us, int /*rcv_speed*/, size_t /*loss_length*/) ATR_OVERRIDE
|
||||
{
|
||||
/*
|
||||
* duB:
|
||||
|
@ -233,12 +238,12 @@ private:
|
|||
|
||||
// Note: this value will still be reshaped to defined minimum,
|
||||
// as per minNAKInterval.
|
||||
return nakint_tk / m_iNakReportAccel;
|
||||
return nakint_us / m_iNakReportAccel;
|
||||
}
|
||||
|
||||
uint64_t minNAKInterval() ATR_OVERRIDE
|
||||
int64_t minNAKInterval() ATR_OVERRIDE
|
||||
{
|
||||
return m_iMinNakInterval_us * CTimer::getCPUFrequency();
|
||||
return m_iMinNakInterval_us;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -250,7 +255,7 @@ class FileCC : public SrtCongestionControlBase
|
|||
|
||||
// Fields from CUDTCC
|
||||
int m_iRCInterval; // UDT Rate control interval
|
||||
uint64_t m_LastRCTime; // last rate increase time
|
||||
steady_clock::time_point m_LastRCTime; // last rate increase time
|
||||
bool m_bSlowStart; // if in slow start phase
|
||||
int32_t m_iLastAck; // last ACKed seq no
|
||||
bool m_bLoss; // if loss happened since last rate increase
|
||||
|
@ -268,7 +273,7 @@ public:
|
|||
FileCC(CUDT* parent)
|
||||
: SrtCongestionControlBase(parent)
|
||||
, m_iRCInterval(CUDT::COMM_SYN_INTERVAL_US)
|
||||
, m_LastRCTime(CTimer::getTime())
|
||||
, m_LastRCTime(steady_clock::now())
|
||||
, m_bSlowStart(true)
|
||||
, m_iLastAck(parent->sndSeqNo())
|
||||
, m_bLoss(false)
|
||||
|
@ -290,9 +295,9 @@ public:
|
|||
m_dCWndSize = 16;
|
||||
m_dPktSndPeriod = 1;
|
||||
|
||||
parent->ConnectSignal(TEV_ACK, SSLOT(updateSndPeriod));
|
||||
parent->ConnectSignal(TEV_LOSSREPORT, SSLOT(slowdownSndPeriod));
|
||||
parent->ConnectSignal(TEV_CHECKTIMER, SSLOT(speedupToWindowSize));
|
||||
parent->ConnectSignal(TEV_ACK, SSLOT(onACK));
|
||||
parent->ConnectSignal(TEV_LOSSREPORT, SSLOT(onLossReport));
|
||||
parent->ConnectSignal(TEV_CHECKTIMER, SSLOT(onRTO));
|
||||
|
||||
HLOGC(cclog.Debug, log << "Creating FileCC");
|
||||
}
|
||||
|
@ -306,10 +311,11 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Tells if an early ACK is needed (before the next Full ACK happening every 10ms).
|
||||
/// In FileCC, treat non-full-payload as an end-of-message (stream)
|
||||
/// and request ACK to be sent immediately.
|
||||
bool needsQuickACK(const CPacket& pkt) ATR_OVERRIDE
|
||||
{
|
||||
// For FileCC, treat non-full-buffer situation as an end-of-message situation;
|
||||
// request ACK to be sent immediately.
|
||||
if (pkt.getLength() < m_parent->maxPayloadSize())
|
||||
{
|
||||
// This is not a regular fixed size packet...
|
||||
|
@ -330,14 +336,15 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
// SLOTS
|
||||
void updateSndPeriod(ETransmissionEvent, EventVariant arg)
|
||||
/// Handle icoming ACK event.
|
||||
/// In slow start stage increase CWND. Leave slow start once maximum CWND is reached.
|
||||
/// In congestion avoidance stage adjust inter packet send interval value to achieve maximum rate.
|
||||
void onACK(ETransmissionEvent, EventVariant arg)
|
||||
{
|
||||
const int ack = arg.get<EventVariant::ACK>();
|
||||
|
||||
const uint64_t currtime = CTimer::getTime();
|
||||
if (currtime - m_LastRCTime < (uint64_t)m_iRCInterval)
|
||||
const steady_clock::time_point currtime = steady_clock::now();
|
||||
if (count_microseconds(currtime - m_LastRCTime) < m_iRCInterval)
|
||||
return;
|
||||
|
||||
m_LastRCTime = currtime;
|
||||
|
@ -360,11 +367,11 @@ private:
|
|||
}
|
||||
else
|
||||
{
|
||||
m_dPktSndPeriod = m_dCWndSize / (m_parent->RTT() + m_iRCInterval);
|
||||
m_dPktSndPeriod = m_dCWndSize / (m_parent->SRTT() + m_iRCInterval);
|
||||
HLOGC(cclog.Debug, log << "FileCC: UPD (slowstart:ENDED) wndsize="
|
||||
<< m_dCWndSize << "/" << m_dMaxCWndSize
|
||||
<< " sndperiod=" << m_dPktSndPeriod << "us = wndsize/(RTT+RCIV) RTT="
|
||||
<< m_parent->RTT() << " RCIV=" << m_iRCInterval);
|
||||
<< m_parent->SRTT() << " RCIV=" << m_iRCInterval);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -376,9 +383,9 @@ private:
|
|||
}
|
||||
else
|
||||
{
|
||||
m_dCWndSize = m_parent->deliveryRate() / 1000000.0 * (m_parent->RTT() + m_iRCInterval) + 16;
|
||||
m_dCWndSize = m_parent->deliveryRate() / 1000000.0 * (m_parent->SRTT() + m_iRCInterval) + 16;
|
||||
HLOGC(cclog.Debug, log << "FileCC: UPD (speed mode) wndsize="
|
||||
<< m_dCWndSize << "/" << m_dMaxCWndSize << " RTT = " << m_parent->RTT()
|
||||
<< m_dCWndSize << "/" << m_dMaxCWndSize << " RTT = " << m_parent->SRTT()
|
||||
<< " sndperiod=" << m_dPktSndPeriod << "us. deliverRate = "
|
||||
<< m_parent->deliveryRate() << " pkts/s)");
|
||||
}
|
||||
|
@ -393,7 +400,7 @@ private:
|
|||
else
|
||||
{
|
||||
double inc = 0;
|
||||
const int loss_bw = 2 * (1000000 / m_dLastDecPeriod); // 2 times last loss point
|
||||
const int loss_bw = static_cast<int>(2 * (1000000 / m_dLastDecPeriod)); // 2 times last loss point
|
||||
const int bw_pktps = min(loss_bw, m_parent->bandwidth());
|
||||
|
||||
int64_t B = (int64_t)(bw_pktps - 1000000.0 / m_dPktSndPeriod);
|
||||
|
@ -456,9 +463,10 @@ private:
|
|||
|
||||
}
|
||||
|
||||
// When a lossreport has been received, it might be due to having
|
||||
// reached the available bandwidth limit. Slowdown to avoid further losses.
|
||||
void slowdownSndPeriod(ETransmissionEvent, EventVariant arg)
|
||||
/// When a lossreport has been received, it might be due to having
|
||||
/// reached the available bandwidth limit. Slowdown to avoid further losses.
|
||||
/// Leave the slow start stage if it was active.
|
||||
void onLossReport(ETransmissionEvent, EventVariant arg)
|
||||
{
|
||||
const int32_t* losslist = arg.get_ptr();
|
||||
size_t losslist_size = arg.get_len();
|
||||
|
@ -483,9 +491,9 @@ private:
|
|||
}
|
||||
else
|
||||
{
|
||||
m_dPktSndPeriod = m_dCWndSize / (m_parent->RTT() + m_iRCInterval);
|
||||
m_dPktSndPeriod = m_dCWndSize / (m_parent->SRTT() + m_iRCInterval);
|
||||
HLOGC(cclog.Debug, log << "FileCC: LOSS, SLOWSTART:OFF, sndperiod=" << m_dPktSndPeriod << "us AS wndsize/(RTT+RCIV) (RTT="
|
||||
<< m_parent->RTT() << " RCIV=" << m_iRCInterval << ")");
|
||||
<< m_parent->SRTT() << " RCIV=" << m_iRCInterval << ")");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -493,14 +501,14 @@ private:
|
|||
m_bLoss = true;
|
||||
|
||||
// TODO: const int pktsInFlight = CSeqNo::seqoff(m_iLastAck, m_parent->sndSeqNo());
|
||||
const int pktsInFlight = m_parent->RTT() / m_dPktSndPeriod;
|
||||
const int pktsInFlight = static_cast<int>(m_parent->SRTT() / m_dPktSndPeriod);
|
||||
const int numPktsLost = m_parent->sndLossLength();
|
||||
const int lost_pcent_x10 = pktsInFlight > 0 ? (numPktsLost * 1000) / pktsInFlight : 0;
|
||||
|
||||
HLOGC(cclog.Debug, log << "FileCC: LOSS: "
|
||||
<< "sent=" << CSeqNo::seqlen(m_iLastAck, m_parent->sndSeqNo()) << ", inFlight=" << pktsInFlight
|
||||
<< ", lost=" << numPktsLost << " ("
|
||||
<< lost_pcent_x10 / 10 << "." << lost_pcent_x10 % 10 << "\%)");
|
||||
<< lost_pcent_x10 / 10 << "." << lost_pcent_x10 % 10 << "%)");
|
||||
if (lost_pcent_x10 < 20) // 2.0%
|
||||
{
|
||||
HLOGC(cclog.Debug, log << "FileCC: LOSS: m_dLastDecPeriod=" << m_dLastDecPeriod << "->" << m_dPktSndPeriod);
|
||||
|
@ -527,11 +535,8 @@ private:
|
|||
|
||||
m_iLastDecSeq = m_parent->sndSeqNo();
|
||||
|
||||
// remove global synchronization using randomization
|
||||
srand(m_iLastDecSeq);
|
||||
m_iDecRandom = (int)ceil(m_iAvgNAKNum * (double(rand()) / RAND_MAX));
|
||||
if (m_iDecRandom < 1)
|
||||
m_iDecRandom = 1;
|
||||
m_iDecRandom = m_iAvgNAKNum > 1 ? genRandomInt(1, m_iAvgNAKNum) : 1;
|
||||
SRT_ASSERT(m_iDecRandom >= 1);
|
||||
HLOGC(cclog.Debug, log << "FileCC: LOSS:NEW lseqno=" << lossbegin
|
||||
<< ", lastsentseqno=" << m_iLastDecSeq
|
||||
<< ", seqdiff=" << CSeqNo::seqoff(m_iLastDecSeq, lossbegin)
|
||||
|
@ -562,7 +567,9 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void speedupToWindowSize(ETransmissionEvent, EventVariant arg)
|
||||
/// @brief On retransmission timeout leave slow start stage if it was active.
|
||||
/// @param arg EventVariant::STAGE to distinguish between INIT and actual RTO.
|
||||
void onRTO(ETransmissionEvent, EventVariant arg)
|
||||
{
|
||||
ECheckTimerStage stg = arg.get<EventVariant::STAGE>();
|
||||
|
||||
|
@ -583,9 +590,9 @@ private:
|
|||
}
|
||||
else
|
||||
{
|
||||
m_dPktSndPeriod = m_dCWndSize / (m_parent->RTT() + m_iRCInterval);
|
||||
m_dPktSndPeriod = m_dCWndSize / (m_parent->SRTT() + m_iRCInterval);
|
||||
HLOGC(cclog.Debug, log << "FileCC: CHKTIMER, SLOWSTART:OFF, sndperiod=" << m_dPktSndPeriod << "us AS wndsize/(RTT+RCIV) (wndsize="
|
||||
<< setprecision(6) << m_dCWndSize << " RTT=" << m_parent->RTT() << " RCIV=" << m_iRCInterval << ")");
|
||||
<< setprecision(6) << m_dCWndSize << " RTT=" << m_parent->SRTT() << " RCIV=" << m_iRCInterval << ")");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -636,8 +643,18 @@ bool SrtCongestion::configure(CUDT* parent)
|
|||
return !!congctl;
|
||||
}
|
||||
|
||||
void SrtCongestion::dispose()
|
||||
{
|
||||
if (congctl)
|
||||
{
|
||||
delete congctl;
|
||||
congctl = 0;
|
||||
}
|
||||
}
|
||||
|
||||
SrtCongestion::~SrtCongestion()
|
||||
{
|
||||
delete congctl;
|
||||
congctl = 0;
|
||||
dispose();
|
||||
}
|
||||
|
||||
} // namespace srt
|
||||
|
|
58
trunk/3rdparty/srt-1-fit/srtcore/congctl.h
vendored
58
trunk/3rdparty/srt-1-fit/srtcore/congctl.h
vendored
|
@ -8,17 +8,19 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef INC__CONGCTL_H
|
||||
#define INC__CONGCTL_H
|
||||
#ifndef INC_SRT_CONGCTL_H
|
||||
#define INC_SRT_CONGCTL_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace srt {
|
||||
|
||||
class CUDT;
|
||||
class SrtCongestionControlBase;
|
||||
|
||||
typedef SrtCongestionControlBase* srtcc_create_t(CUDT* parent);
|
||||
typedef SrtCongestionControlBase* srtcc_create_t(srt::CUDT* parent);
|
||||
|
||||
class SrtCongestion
|
||||
{
|
||||
|
@ -55,13 +57,24 @@ public:
|
|||
bool operator()(NamePtr np) { return n == np.first; }
|
||||
};
|
||||
|
||||
static NamePtr* find(const std::string& name)
|
||||
{
|
||||
NamePtr* end = congctls+N_CONTROLLERS;
|
||||
NamePtr* try_selector = std::find_if(congctls, end, IsName(name));
|
||||
return try_selector != end ? try_selector : NULL;
|
||||
}
|
||||
|
||||
static bool exists(const std::string& name)
|
||||
{
|
||||
return find(name);
|
||||
}
|
||||
|
||||
// You can call select() multiple times, until finally
|
||||
// the 'configure' method is called.
|
||||
bool select(const std::string& name)
|
||||
{
|
||||
NamePtr* end = congctls+N_CONTROLLERS;
|
||||
NamePtr* try_selector = std::find_if(congctls, end, IsName(name));
|
||||
if (try_selector == end)
|
||||
NamePtr* try_selector = find(name);
|
||||
if (!try_selector)
|
||||
return false;
|
||||
selector = try_selector - congctls;
|
||||
return true;
|
||||
|
@ -79,12 +92,18 @@ public:
|
|||
// 1. The congctl is individual, so don't copy it. Set NULL.
|
||||
// 2. The selected name is copied so that it's configured correctly.
|
||||
SrtCongestion(const SrtCongestion& source): congctl(), selector(source.selector) {}
|
||||
void operator=(const SrtCongestion& source) { congctl = 0; selector = source.selector; }
|
||||
|
||||
// This function will be called by the parent CUDT
|
||||
// in appropriate time. It should select appropriate
|
||||
// congctl basing on the value in selector, then
|
||||
// pin oneself in into CUDT for receiving event signals.
|
||||
bool configure(CUDT* parent);
|
||||
bool configure(srt::CUDT* parent);
|
||||
|
||||
// This function will intentionally delete the contained object.
|
||||
// This makes future calls to ready() return false. Calling
|
||||
// configure on it again will create it again.
|
||||
void dispose();
|
||||
|
||||
// Will delete the pinned in congctl object.
|
||||
// This must be defined in *.cpp file due to virtual
|
||||
|
@ -111,12 +130,13 @@ public:
|
|||
};
|
||||
};
|
||||
|
||||
class CPacket;
|
||||
|
||||
class SrtCongestionControlBase
|
||||
{
|
||||
protected:
|
||||
// Here can be some common fields
|
||||
CUDT* m_parent;
|
||||
srt::CUDT* m_parent;
|
||||
|
||||
double m_dPktSndPeriod;
|
||||
double m_dCWndSize;
|
||||
|
@ -127,11 +147,11 @@ protected:
|
|||
//int m_iMSS; // NOT REQUIRED. Use m_parent->MSS() instead.
|
||||
//int32_t m_iSndCurrSeqNo; // NOT REQUIRED. Use m_parent->sndSeqNo().
|
||||
//int m_iRcvRate; // NOT REQUIRED. Use m_parent->deliveryRate() instead.
|
||||
//int m_RTT; // NOT REQUIRED. Use m_parent->RTT() instead.
|
||||
//int m_RTT; // NOT REQUIRED. Use m_parent->SRTT() instead.
|
||||
//char* m_pcParam; // Used to access m_llMaxBw. Use m_parent->maxBandwidth() instead.
|
||||
|
||||
// Constructor in protected section so that this class is semi-abstract.
|
||||
SrtCongestionControlBase(CUDT* parent);
|
||||
SrtCongestionControlBase(srt::CUDT* parent);
|
||||
public:
|
||||
|
||||
// This could be also made abstract, but this causes a linkage
|
||||
|
@ -169,11 +189,11 @@ public:
|
|||
virtual int ACKTimeout_us() const { return 0; }
|
||||
|
||||
// Called when the settings concerning m_llMaxBW were changed.
|
||||
// Arg 1: value of CUDT::m_llMaxBW
|
||||
// Arg 2: value calculated out of CUDT::m_llInputBW and CUDT::m_iOverheadBW.
|
||||
// Arg 1: value of CUDT's m_config.m_llMaxBW
|
||||
// Arg 2: value calculated out of CUDT's m_config.llInputBW and m_config.iOverheadBW.
|
||||
virtual void updateBandwidth(int64_t, int64_t) {}
|
||||
|
||||
virtual bool needsQuickACK(const CPacket&)
|
||||
virtual bool needsQuickACK(const srt::CPacket&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -186,21 +206,21 @@ public:
|
|||
|
||||
virtual SrtCongestion::RexmitMethod rexmitMethod() = 0; // Implementation enforced.
|
||||
|
||||
virtual uint64_t updateNAKInterval(uint64_t nakint_tk, int rcv_speed, size_t loss_length)
|
||||
virtual int64_t updateNAKInterval(int64_t nakint_us, int rcv_speed, size_t loss_length)
|
||||
{
|
||||
if (rcv_speed > 0)
|
||||
nakint_tk += (loss_length * uint64_t(1000000) / rcv_speed) * CTimer::getCPUFrequency();
|
||||
nakint_us += (loss_length * int64_t(1000000) / rcv_speed);
|
||||
|
||||
return nakint_tk;
|
||||
return nakint_us;
|
||||
}
|
||||
|
||||
virtual uint64_t minNAKInterval()
|
||||
virtual int64_t minNAKInterval()
|
||||
{
|
||||
return 0; // Leave default
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
9675
trunk/3rdparty/srt-1-fit/srtcore/core.cpp
vendored
9675
trunk/3rdparty/srt-1-fit/srtcore/core.cpp
vendored
File diff suppressed because it is too large
Load diff
1009
trunk/3rdparty/srt-1-fit/srtcore/core.h
vendored
1009
trunk/3rdparty/srt-1-fit/srtcore/core.h
vendored
File diff suppressed because it is too large
Load diff
338
trunk/3rdparty/srt-1-fit/srtcore/crypto.cpp
vendored
338
trunk/3rdparty/srt-1-fit/srtcore/crypto.cpp
vendored
|
@ -13,6 +13,8 @@ written by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
@ -24,6 +26,7 @@ written by
|
|||
#include "crypto.h"
|
||||
#include "logging.h"
|
||||
#include "core.h"
|
||||
#include "api.h"
|
||||
|
||||
using namespace srt_logging;
|
||||
|
||||
|
@ -40,9 +43,10 @@ using namespace srt_logging;
|
|||
*/
|
||||
|
||||
// 10* HAICRYPT_DEF_KM_PRE_ANNOUNCE
|
||||
const int SRT_CRYPT_KM_PRE_ANNOUNCE = 0x10000;
|
||||
const int SRT_CRYPT_KM_PRE_ANNOUNCE SRT_ATR_UNUSED = 0x10000;
|
||||
|
||||
#if ENABLE_LOGGING
|
||||
namespace srt_logging
|
||||
{
|
||||
std::string KmStateStr(SRT_KM_STATE state)
|
||||
{
|
||||
switch (state)
|
||||
|
@ -62,9 +66,21 @@ std::string KmStateStr(SRT_KM_STATE state)
|
|||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
using srt_logging::KmStateStr;
|
||||
|
||||
std::string CCryptoControl::FormatKmMessage(std::string hdr, int cmd, size_t srtlen)
|
||||
void srt::CCryptoControl::globalInit()
|
||||
{
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
// We need to force the Cryspr to be initialized during startup to avoid the
|
||||
// possibility of multiple threads initialzing the same static data later on.
|
||||
HaiCryptCryspr_Get_Instance();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ENABLE_LOGGING
|
||||
std::string srt::CCryptoControl::FormatKmMessage(std::string hdr, int cmd, size_t srtlen)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << hdr << ": cmd=" << cmd << "(" << (cmd == SRT_CMD_KMREQ ? "KMREQ":"KMRSP") <<") len="
|
||||
|
@ -75,7 +91,7 @@ std::string CCryptoControl::FormatKmMessage(std::string hdr, int cmd, size_t srt
|
|||
}
|
||||
#endif
|
||||
|
||||
void CCryptoControl::updateKmState(int cmd, size_t srtlen SRT_ATR_UNUSED)
|
||||
void srt::CCryptoControl::updateKmState(int cmd, size_t srtlen SRT_ATR_UNUSED)
|
||||
{
|
||||
if (cmd == SRT_CMD_KMREQ)
|
||||
{
|
||||
|
@ -83,43 +99,41 @@ void CCryptoControl::updateKmState(int cmd, size_t srtlen SRT_ATR_UNUSED)
|
|||
{
|
||||
m_SndKmState = SRT_KM_S_SECURING;
|
||||
}
|
||||
LOGP(mglog.Note, FormatKmMessage("sendSrtMsg", cmd, srtlen));
|
||||
LOGP(cnlog.Note, FormatKmMessage("sendSrtMsg", cmd, srtlen));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGP(mglog.Note, FormatKmMessage("sendSrtMsg", cmd, srtlen));
|
||||
LOGP(cnlog.Note, FormatKmMessage("sendSrtMsg", cmd, srtlen));
|
||||
}
|
||||
}
|
||||
|
||||
void CCryptoControl::createFakeSndContext()
|
||||
void srt::CCryptoControl::createFakeSndContext()
|
||||
{
|
||||
if (!m_iSndKmKeyLen)
|
||||
m_iSndKmKeyLen = 16;
|
||||
|
||||
if (!createCryptoCtx(Ref(m_hSndCrypto), m_iSndKmKeyLen, HAICRYPT_CRYPTO_DIR_TX))
|
||||
if (!createCryptoCtx(m_iSndKmKeyLen, HAICRYPT_CRYPTO_DIR_TX, (m_hSndCrypto)))
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "Error: Can't create fake crypto context for sending - sending will return ERROR!");
|
||||
HLOGC(cnlog.Debug, log << "Error: Can't create fake crypto context for sending - sending will return ERROR!");
|
||||
m_hSndCrypto = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int CCryptoControl::processSrtMsg_KMREQ(
|
||||
int srt::CCryptoControl::processSrtMsg_KMREQ(
|
||||
const uint32_t* srtdata SRT_ATR_UNUSED,
|
||||
size_t bytelen SRT_ATR_UNUSED,
|
||||
uint32_t* srtdata_out, ref_t<size_t> r_srtlen, int hsv SRT_ATR_UNUSED)
|
||||
int hsv SRT_ATR_UNUSED,
|
||||
uint32_t pw_srtdata_out[], size_t& w_srtlen)
|
||||
{
|
||||
size_t& srtlen = *r_srtlen;
|
||||
//Receiver
|
||||
/* All 32-bit msg fields swapped on reception
|
||||
* But HaiCrypt expect network order message
|
||||
* Re-swap to cancel it.
|
||||
*/
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
srtlen = bytelen/sizeof(srtdata[SRT_KMR_KMSTATE]);
|
||||
HtoNLA(srtdata_out, srtdata, srtlen);
|
||||
unsigned char* kmdata = reinterpret_cast<unsigned char*>(srtdata_out);
|
||||
|
||||
std::vector<unsigned char> kmcopy(kmdata, kmdata + bytelen);
|
||||
w_srtlen = bytelen/sizeof(srtdata[SRT_KMR_KMSTATE]);
|
||||
HtoNLA((pw_srtdata_out), srtdata, w_srtlen);
|
||||
unsigned char* kmdata = reinterpret_cast<unsigned char*>(pw_srtdata_out);
|
||||
|
||||
// The side that has received KMREQ is always an HSD_RESPONDER, regardless of
|
||||
// what has called this function. The HSv5 handshake only enforces bidirectional
|
||||
|
@ -131,11 +145,11 @@ int CCryptoControl::processSrtMsg_KMREQ(
|
|||
// CHANGED. The first version made HSv5 reject the connection.
|
||||
// This isn't well handled by applications, so the connection is
|
||||
// still established, but unable to handle any transport.
|
||||
//#define KMREQ_RESULT_REJECTION() if (bidirectional) { return SRT_CMD_NONE; } else { srtlen = 1; goto HSv4_ErrorReport; }
|
||||
#define KMREQ_RESULT_REJECTION() { srtlen = 1; goto HSv4_ErrorReport; }
|
||||
//#define KMREQ_RESULT_REJECTION() if (bidirectional) { return SRT_CMD_NONE; } else { w_srtlen = 1; goto HSv4_ErrorReport; }
|
||||
#define KMREQ_RESULT_REJECTION() { w_srtlen = 1; goto HSv4_ErrorReport; }
|
||||
|
||||
int rc = HAICRYPT_OK; // needed before 'goto' run from KMREQ_RESULT_REJECTION macro
|
||||
bool SRT_ATR_UNUSED wasb4 = false;
|
||||
bool wasb4 SRT_ATR_UNUSED = false;
|
||||
size_t sek_len = 0;
|
||||
|
||||
// What we have to do:
|
||||
|
@ -147,16 +161,16 @@ int CCryptoControl::processSrtMsg_KMREQ(
|
|||
// function normally return SRT_CMD_KMRSP.
|
||||
if ( bytelen <= HCRYPT_MSG_KM_OFS_SALT ) //Sanity on message
|
||||
{
|
||||
LOGC(mglog.Error, log << "processSrtMsg_KMREQ: size of the KM (" << bytelen << ") is too small, must be >" << HCRYPT_MSG_KM_OFS_SALT);
|
||||
LOGC(cnlog.Error, log << "processSrtMsg_KMREQ: size of the KM (" << bytelen << ") is too small, must be >" << HCRYPT_MSG_KM_OFS_SALT);
|
||||
m_RcvKmState = SRT_KM_S_BADSECRET;
|
||||
KMREQ_RESULT_REJECTION();
|
||||
}
|
||||
|
||||
HLOGC(mglog.Debug, log << "KMREQ: getting SEK and creating receiver crypto");
|
||||
HLOGC(cnlog.Debug, log << "KMREQ: getting SEK and creating receiver crypto");
|
||||
sek_len = hcryptMsg_KM_GetSekLen(kmdata);
|
||||
if ( sek_len == 0 )
|
||||
{
|
||||
LOGC(mglog.Error, log << "processSrtMsg_KMREQ: Received SEK is empty - REJECTING!");
|
||||
LOGC(cnlog.Error, log << "processSrtMsg_KMREQ: Received SEK is empty - REJECTING!");
|
||||
m_RcvKmState = SRT_KM_S_BADSECRET;
|
||||
KMREQ_RESULT_REJECTION();
|
||||
}
|
||||
|
@ -168,7 +182,7 @@ int CCryptoControl::processSrtMsg_KMREQ(
|
|||
#if ENABLE_HEAVY_LOGGING
|
||||
if (m_iSndKmKeyLen != m_iRcvKmKeyLen)
|
||||
{
|
||||
LOGC(mglog.Debug, log << "processSrtMsg_KMREQ: Agent's PBKEYLEN=" << m_iSndKmKeyLen
|
||||
LOGC(cnlog.Debug, log << "processSrtMsg_KMREQ: Agent's PBKEYLEN=" << m_iSndKmKeyLen
|
||||
<< " overwritten by Peer's PBKEYLEN=" << m_iRcvKmKeyLen);
|
||||
}
|
||||
#endif
|
||||
|
@ -179,22 +193,22 @@ int CCryptoControl::processSrtMsg_KMREQ(
|
|||
// a wrong password.
|
||||
if (m_KmSecret.len == 0) //We have a shared secret <==> encryption is on
|
||||
{
|
||||
LOGC(mglog.Error, log << "processSrtMsg_KMREQ: Agent does not declare encryption - won't decrypt incoming packets!");
|
||||
LOGC(cnlog.Warn, log << "processSrtMsg_KMREQ: Agent does not declare encryption - won't decrypt incoming packets!");
|
||||
m_RcvKmState = SRT_KM_S_NOSECRET;
|
||||
KMREQ_RESULT_REJECTION();
|
||||
}
|
||||
wasb4 = m_hRcvCrypto;
|
||||
|
||||
if (!createCryptoCtx(Ref(m_hRcvCrypto), m_iRcvKmKeyLen, HAICRYPT_CRYPTO_DIR_RX))
|
||||
if (!createCryptoCtx(m_iRcvKmKeyLen, HAICRYPT_CRYPTO_DIR_RX, (m_hRcvCrypto)))
|
||||
{
|
||||
LOGC(mglog.Error, log << "processSrtMsg_KMREQ: Can't create RCV CRYPTO CTX - must reject...");
|
||||
LOGC(cnlog.Error, log << "processSrtMsg_KMREQ: Can't create RCV CRYPTO CTX - must reject...");
|
||||
m_RcvKmState = SRT_KM_S_NOSECRET;
|
||||
KMREQ_RESULT_REJECTION();
|
||||
}
|
||||
|
||||
if (!wasb4)
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "processSrtMsg_KMREQ: created RX ENC with KeyLen=" << m_iRcvKmKeyLen);
|
||||
HLOGC(cnlog.Debug, log << "processSrtMsg_KMREQ: created RX ENC with KeyLen=" << m_iRcvKmKeyLen);
|
||||
}
|
||||
// We have both sides set with password, so both are pending for security
|
||||
m_RcvKmState = SRT_KM_S_SECURING;
|
||||
|
@ -207,36 +221,36 @@ int CCryptoControl::processSrtMsg_KMREQ(
|
|||
{
|
||||
case HAICRYPT_OK:
|
||||
m_RcvKmState = SRT_KM_S_SECURED;
|
||||
HLOGC(mglog.Debug, log << "KMREQ/rcv: (snd) Rx process successful - SECURED.");
|
||||
HLOGC(cnlog.Debug, log << "KMREQ/rcv: (snd) Rx process successful - SECURED.");
|
||||
//Send back the whole message to confirm
|
||||
break;
|
||||
case HAICRYPT_ERROR_WRONG_SECRET: //Unmatched shared secret to decrypt wrapped key
|
||||
m_RcvKmState = m_SndKmState = SRT_KM_S_BADSECRET;
|
||||
//Send status KMRSP message to tel error
|
||||
srtlen = 1;
|
||||
LOGC(mglog.Error, log << "KMREQ/rcv: (snd) Rx process failure - BADSECRET");
|
||||
w_srtlen = 1;
|
||||
LOGC(cnlog.Warn, log << "KMREQ/rcv: (snd) Rx process failure - BADSECRET");
|
||||
break;
|
||||
case HAICRYPT_ERROR: //Other errors
|
||||
default:
|
||||
m_RcvKmState = m_SndKmState = SRT_KM_S_NOSECRET;
|
||||
srtlen = 1;
|
||||
LOGC(mglog.Error, log << "KMREQ/rcv: (snd) Rx process failure (IPE) - NOSECRET");
|
||||
w_srtlen = 1;
|
||||
LOGC(cnlog.Warn, log << "KMREQ/rcv: (snd) Rx process failure (IPE) - NOSECRET");
|
||||
break;
|
||||
}
|
||||
|
||||
LOGP(mglog.Note, FormatKmMessage("processSrtMsg_KMREQ", SRT_CMD_KMREQ, bytelen));
|
||||
LOGP(cnlog.Note, FormatKmMessage("processSrtMsg_KMREQ", SRT_CMD_KMREQ, bytelen));
|
||||
|
||||
// Since now, when CCryptoControl::decrypt() encounters an error, it will print it, ONCE,
|
||||
// until the next KMREQ is received as a key regeneration.
|
||||
m_bErrorReported = false;
|
||||
|
||||
|
||||
if (srtlen == 1)
|
||||
if (w_srtlen == 1)
|
||||
goto HSv4_ErrorReport;
|
||||
|
||||
// Configure the sender context also, if it succeeded to configure the
|
||||
// receiver context and we are using bidirectional mode.
|
||||
if ( bidirectional )
|
||||
if (bidirectional)
|
||||
{
|
||||
// Note: 'bidirectional' means that we want a bidirectional key update,
|
||||
// which happens only and exclusively with HSv5 handshake - not when the
|
||||
|
@ -249,7 +263,7 @@ int CCryptoControl::processSrtMsg_KMREQ(
|
|||
m_iSndKmKeyLen = m_iRcvKmKeyLen;
|
||||
if (HaiCrypt_Clone(m_hRcvCrypto, HAICRYPT_CRYPTO_DIR_TX, &m_hSndCrypto) != HAICRYPT_OK)
|
||||
{
|
||||
LOGC(mglog.Error, log << "processSrtMsg_KMREQ: Can't create SND CRYPTO CTX - WILL NOT SEND-ENCRYPT correctly!");
|
||||
LOGC(cnlog.Error, log << "processSrtMsg_KMREQ: Can't create SND CRYPTO CTX - WILL NOT SEND-ENCRYPT correctly!");
|
||||
if (hasPassphrase())
|
||||
m_SndKmState = SRT_KM_S_BADSECRET;
|
||||
else
|
||||
|
@ -260,30 +274,30 @@ int CCryptoControl::processSrtMsg_KMREQ(
|
|||
m_SndKmState = SRT_KM_S_SECURED;
|
||||
}
|
||||
|
||||
LOGC(mglog.Note, log << FormatKmMessage("processSrtMsg_KMREQ", SRT_CMD_KMREQ, bytelen)
|
||||
LOGC(cnlog.Note, log << FormatKmMessage("processSrtMsg_KMREQ", SRT_CMD_KMREQ, bytelen)
|
||||
<< " SndKeyLen=" << m_iSndKmKeyLen
|
||||
<< " TX CRYPTO CTX CLONED FROM RX"
|
||||
);
|
||||
|
||||
// Write the KM message into the field from which it will be next sent.
|
||||
memcpy(m_SndKmMsg[0].Msg, kmdata, bytelen);
|
||||
memcpy((m_SndKmMsg[0].Msg), kmdata, bytelen);
|
||||
m_SndKmMsg[0].MsgLen = bytelen;
|
||||
m_SndKmMsg[0].iPeerRetry = 0; // Don't start sending them upon connection :)
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "processSrtMsg_KMREQ: NOT cloning RX to TX crypto: already in "
|
||||
HLOGC(cnlog.Debug, log << "processSrtMsg_KMREQ: NOT cloning RX to TX crypto: already in "
|
||||
<< KmStateStr(m_SndKmState) << " state");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGP(mglog.Debug, "processSrtMsg_KMREQ: NOT SECURED - not replaying failed security association to TX CRYPTO CTX");
|
||||
HLOGP(cnlog.Debug, "processSrtMsg_KMREQ: NOT SECURED - not replaying failed security association to TX CRYPTO CTX");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "processSrtMsg_KMREQ: NOT REPLAYING the key update to TX CRYPTO CTX.");
|
||||
HLOGC(cnlog.Debug, log << "processSrtMsg_KMREQ: NOT REPLAYING the key update to TX CRYPTO CTX.");
|
||||
}
|
||||
|
||||
return SRT_CMD_KMRSP;
|
||||
|
@ -304,17 +318,17 @@ HSv4_ErrorReport:
|
|||
// It's ok that this is reported as error because this happens in a scenario,
|
||||
// when non-encryption-enabled SRT application is contacted by encryption-enabled SRT
|
||||
// application which tries to make a security association.
|
||||
LOGC(mglog.Error, log << "processSrtMsg_KMREQ: Encryption not enabled at compile time - must reject...");
|
||||
LOGC(cnlog.Warn, log << "processSrtMsg_KMREQ: Encryption not enabled at compile time - must reject...");
|
||||
m_RcvKmState = SRT_KM_S_NOSECRET;
|
||||
#endif
|
||||
|
||||
srtlen = 1;
|
||||
w_srtlen = 1;
|
||||
|
||||
srtdata_out[SRT_KMR_KMSTATE] = m_RcvKmState;
|
||||
pw_srtdata_out[SRT_KMR_KMSTATE] = m_RcvKmState;
|
||||
return SRT_CMD_KMRSP;
|
||||
}
|
||||
|
||||
int CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len, int /* XXX unused? hsv*/)
|
||||
int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len, int /* XXX unused? hsv*/)
|
||||
{
|
||||
/* All 32-bit msg fields (if present) swapped on reception
|
||||
* But HaiCrypt expect network order message
|
||||
|
@ -367,7 +381,7 @@ int CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len, int
|
|||
break;
|
||||
|
||||
default:
|
||||
LOGC(mglog.Fatal, log << "processSrtMsg_KMRSP: IPE: unknown peer error state: "
|
||||
LOGC(cnlog.Fatal, log << "processSrtMsg_KMRSP: IPE: unknown peer error state: "
|
||||
<< KmStateStr(peerstate) << " (" << int(peerstate) << ")");
|
||||
m_RcvKmState = SRT_KM_S_NOSECRET;
|
||||
m_SndKmState = SRT_KM_S_NOSECRET;
|
||||
|
@ -375,11 +389,11 @@ int CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len, int
|
|||
break;
|
||||
}
|
||||
|
||||
LOGC(mglog.Error, log << "processSrtMsg_KMRSP: received failure report. STATE: " << KmStateStr(m_RcvKmState));
|
||||
LOGC(cnlog.Warn, log << "processSrtMsg_KMRSP: received failure report. STATE: " << KmStateStr(m_RcvKmState));
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "processSrtMsg_KMRSP: received key response len=" << len);
|
||||
HLOGC(cnlog.Debug, log << "processSrtMsg_KMRSP: received key response len=" << len);
|
||||
// XXX INSECURE << ": [" << FormatBinaryString((uint8_t*)srtd, len) << "]";
|
||||
bool key1 = getKmMsg_acceptResponse(0, srtd, len);
|
||||
bool key2 = true;
|
||||
|
@ -389,40 +403,40 @@ int CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len, int
|
|||
if (key1 || key2)
|
||||
{
|
||||
m_SndKmState = m_RcvKmState = SRT_KM_S_SECURED;
|
||||
HLOGC(mglog.Debug, log << "processSrtMsg_KMRSP: KM response matches " << (key1 ? "EVEN" : "ODD") << " key");
|
||||
HLOGC(cnlog.Debug, log << "processSrtMsg_KMRSP: KM response matches " << (key1 ? "EVEN" : "ODD") << " key");
|
||||
retstatus = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
retstatus = -1;
|
||||
LOGC(mglog.Error, log << "processSrtMsg_KMRSP: IPE??? KM response key matches no key");
|
||||
LOGC(cnlog.Error, log << "processSrtMsg_KMRSP: IPE??? KM response key matches no key");
|
||||
/* XXX INSECURE
|
||||
LOGC(mglog.Error, log << "processSrtMsg_KMRSP: KM response: [" << FormatBinaryString((uint8_t*)srtd, len)
|
||||
LOGC(cnlog.Error, log << "processSrtMsg_KMRSP: KM response: [" << FormatBinaryString((uint8_t*)srtd, len)
|
||||
<< "] matches no key 0=[" << FormatBinaryString((uint8_t*)m_SndKmMsg[0].Msg, m_SndKmMsg[0].MsgLen)
|
||||
<< "] 1=[" << FormatBinaryString((uint8_t*)m_SndKmMsg[1].Msg, m_SndKmMsg[1].MsgLen) << "]");
|
||||
*/
|
||||
|
||||
m_SndKmState = m_RcvKmState = SRT_KM_S_BADSECRET;
|
||||
}
|
||||
HLOGC(mglog.Debug, log << "processSrtMsg_KMRSP: key[0]: len=" << m_SndKmMsg[0].MsgLen << " retry=" << m_SndKmMsg[0].iPeerRetry
|
||||
HLOGC(cnlog.Debug, log << "processSrtMsg_KMRSP: key[0]: len=" << m_SndKmMsg[0].MsgLen << " retry=" << m_SndKmMsg[0].iPeerRetry
|
||||
<< "; key[1]: len=" << m_SndKmMsg[1].MsgLen << " retry=" << m_SndKmMsg[1].iPeerRetry);
|
||||
}
|
||||
|
||||
LOGP(mglog.Note, FormatKmMessage("processSrtMsg_KMRSP", SRT_CMD_KMRSP, len));
|
||||
LOGP(cnlog.Note, FormatKmMessage("processSrtMsg_KMRSP", SRT_CMD_KMRSP, len));
|
||||
|
||||
return retstatus;
|
||||
}
|
||||
|
||||
void CCryptoControl::sendKeysToPeer(Whether2RegenKm regen SRT_ATR_UNUSED)
|
||||
void srt::CCryptoControl::sendKeysToPeer(CUDT* sock SRT_ATR_UNUSED, int iSRTT SRT_ATR_UNUSED, Whether2RegenKm regen SRT_ATR_UNUSED)
|
||||
{
|
||||
if ( !m_hSndCrypto || m_SndKmState == SRT_KM_S_UNSECURED)
|
||||
if (!m_hSndCrypto || m_SndKmState == SRT_KM_S_UNSECURED)
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "sendKeysToPeer: NOT sending/regenerating keys: "
|
||||
HLOGC(cnlog.Debug, log << "sendKeysToPeer: NOT sending/regenerating keys: "
|
||||
<< (m_hSndCrypto ? "CONNECTION UNSECURED" : "NO TX CRYPTO CTX created"));
|
||||
return;
|
||||
}
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
uint64_t now = 0;
|
||||
srt::sync::steady_clock::time_point now = srt::sync::steady_clock::now();
|
||||
/*
|
||||
* Crypto Key Distribution to peer:
|
||||
* If...
|
||||
|
@ -432,38 +446,35 @@ void CCryptoControl::sendKeysToPeer(Whether2RegenKm regen SRT_ATR_UNUSED)
|
|||
* - last sent Keying Material req should have been replied (RTT*1.5 elapsed);
|
||||
* then (re-)send handshake request.
|
||||
*/
|
||||
if ( ((m_SndKmMsg[0].iPeerRetry > 0) || (m_SndKmMsg[1].iPeerRetry > 0))
|
||||
&& ((m_SndKmLastTime + ((m_parent->RTT() * 3)/2)) <= (now = CTimer::getTime())))
|
||||
if (((m_SndKmMsg[0].iPeerRetry > 0) || (m_SndKmMsg[1].iPeerRetry > 0))
|
||||
&& ((m_SndKmLastTime + srt::sync::microseconds_from((iSRTT * 3)/2)) <= now))
|
||||
{
|
||||
for (int ki = 0; ki < 2; ki++)
|
||||
{
|
||||
if (m_SndKmMsg[ki].iPeerRetry > 0 && m_SndKmMsg[ki].MsgLen > 0)
|
||||
{
|
||||
m_SndKmMsg[ki].iPeerRetry--;
|
||||
HLOGC(mglog.Debug, log << "sendKeysToPeer: SENDING ki=" << ki << " len=" << m_SndKmMsg[ki].MsgLen
|
||||
HLOGC(cnlog.Debug, log << "sendKeysToPeer: SENDING ki=" << ki << " len=" << m_SndKmMsg[ki].MsgLen
|
||||
<< " retry(updated)=" << m_SndKmMsg[ki].iPeerRetry);
|
||||
m_SndKmLastTime = now;
|
||||
m_parent->sendSrtMsg(SRT_CMD_KMREQ, (uint32_t *)m_SndKmMsg[ki].Msg, m_SndKmMsg[ki].MsgLen/sizeof(uint32_t));
|
||||
sock->sendSrtMsg(SRT_CMD_KMREQ, (uint32_t *)m_SndKmMsg[ki].Msg, m_SndKmMsg[ki].MsgLen / sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (now == 0)
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "sendKeysToPeer: NO KEYS RESENT, will " <<
|
||||
(regen ? "" : "NOT ") << "regenerate.");
|
||||
}
|
||||
|
||||
if (regen)
|
||||
{
|
||||
regenCryptoKm(
|
||||
true, // send UMSG_EXT + SRT_CMD_KMREQ to the peer, if regenerated the key
|
||||
false // Do not apply the regenerated key to the to the receiver context
|
||||
); // regenerate and send
|
||||
sock, // send UMSG_EXT + SRT_CMD_KMREQ to the peer using this socket
|
||||
false // Do not apply the regenerated key to the to the receiver context
|
||||
); // regenerate and send
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
void CCryptoControl::regenCryptoKm(bool sendit, bool bidirectional)
|
||||
void srt::CCryptoControl::regenCryptoKm(CUDT* sock, bool bidirectional)
|
||||
{
|
||||
if (!m_hSndCrypto)
|
||||
return;
|
||||
|
@ -473,8 +484,8 @@ void CCryptoControl::regenCryptoKm(bool sendit, bool bidirectional)
|
|||
int nbo = HaiCrypt_Tx_ManageKeys(m_hSndCrypto, out_p, out_len_p, 2);
|
||||
int sent = 0;
|
||||
|
||||
HLOGC(mglog.Debug, log << "regenCryptoKm: regenerating crypto keys nbo=" << nbo <<
|
||||
" THEN=" << (sendit ? "SEND" : "KEEP") << " DIR=" << (bidirectional ? "BOTH" : "SENDER"));
|
||||
HLOGC(cnlog.Debug, log << "regenCryptoKm: regenerating crypto keys nbo=" << nbo <<
|
||||
" THEN=" << (sock ? "SEND" : "KEEP") << " DIR=" << (bidirectional ? "BOTH" : "SENDER"));
|
||||
|
||||
for (int i = 0; i < nbo && i < 2; i++)
|
||||
{
|
||||
|
@ -491,71 +502,69 @@ void CCryptoControl::regenCryptoKm(bool sendit, bool bidirectional)
|
|||
{
|
||||
|
||||
uint8_t* oldkey SRT_ATR_UNUSED = m_SndKmMsg[ki].Msg;
|
||||
HLOGC(mglog.Debug, log << "new key[" << ki << "] index=" << kix
|
||||
HLOGC(cnlog.Debug, log << "new key[" << ki << "] index=" << kix
|
||||
<< " OLD=[" << m_SndKmMsg[ki].MsgLen << "]"
|
||||
<< FormatBinaryString(m_SndKmMsg[ki].Msg, m_SndKmMsg[ki].MsgLen)
|
||||
<< " NEW=[" << out_len_p[i] << "]"
|
||||
<< FormatBinaryString((const uint8_t*)out_p[i], out_len_p[i]));
|
||||
|
||||
/* New Keying material, send to peer */
|
||||
memcpy(m_SndKmMsg[ki].Msg, out_p[i], out_len_p[i]);
|
||||
memcpy((m_SndKmMsg[ki].Msg), out_p[i], out_len_p[i]);
|
||||
m_SndKmMsg[ki].MsgLen = out_len_p[i];
|
||||
m_SndKmMsg[ki].iPeerRetry = SRT_MAX_KMRETRY;
|
||||
|
||||
if (bidirectional && !sendit)
|
||||
if (bidirectional && !sock)
|
||||
{
|
||||
// "Send" this key also to myself, just to be applied to the receiver crypto,
|
||||
// exactly the same way how this key is interpreted on the peer side into its receiver crypto
|
||||
int rc = HaiCrypt_Rx_Process(m_hRcvCrypto, m_SndKmMsg[ki].Msg, m_SndKmMsg[ki].MsgLen, NULL, NULL, 0);
|
||||
if ( rc < 0 )
|
||||
{
|
||||
LOGC(mglog.Fatal, log << "regenCryptoKm: IPE: applying key generated in snd crypto into rcv crypto: failed code=" << rc);
|
||||
LOGC(cnlog.Fatal, log << "regenCryptoKm: IPE: applying key generated in snd crypto into rcv crypto: failed code=" << rc);
|
||||
// The party won't be able to decrypt incoming data!
|
||||
// Not sure if anything has to be reported.
|
||||
}
|
||||
}
|
||||
|
||||
if (sendit)
|
||||
if (sock)
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "regenCryptoKm: SENDING ki=" << ki << " len=" << m_SndKmMsg[ki].MsgLen
|
||||
HLOGC(cnlog.Debug, log << "regenCryptoKm: SENDING ki=" << ki << " len=" << m_SndKmMsg[ki].MsgLen
|
||||
<< " retry(updated)=" << m_SndKmMsg[ki].iPeerRetry);
|
||||
m_parent->sendSrtMsg(SRT_CMD_KMREQ, (uint32_t *)m_SndKmMsg[ki].Msg, m_SndKmMsg[ki].MsgLen/sizeof(uint32_t));
|
||||
sock->sendSrtMsg(SRT_CMD_KMREQ, (uint32_t *)m_SndKmMsg[ki].Msg, m_SndKmMsg[ki].MsgLen / sizeof(uint32_t));
|
||||
sent++;
|
||||
}
|
||||
}
|
||||
else if (out_len_p[i] == 0)
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "no key[" << ki << "] index=" << kix << ": not generated");
|
||||
HLOGC(cnlog.Debug, log << "no key[" << ki << "] index=" << kix << ": not generated");
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "no key[" << ki << "] index=" << kix << ": key unchanged");
|
||||
HLOGC(cnlog.Debug, log << "no key[" << ki << "] index=" << kix << ": key unchanged");
|
||||
}
|
||||
}
|
||||
|
||||
HLOGC(mglog.Debug, log << "regenCryptoKm: key[0]: len=" << m_SndKmMsg[0].MsgLen << " retry=" << m_SndKmMsg[0].iPeerRetry
|
||||
HLOGC(cnlog.Debug, log << "regenCryptoKm: key[0]: len=" << m_SndKmMsg[0].MsgLen << " retry=" << m_SndKmMsg[0].iPeerRetry
|
||||
<< "; key[1]: len=" << m_SndKmMsg[1].MsgLen << " retry=" << m_SndKmMsg[1].iPeerRetry);
|
||||
|
||||
if (sent)
|
||||
m_SndKmLastTime = CTimer::getTime();
|
||||
m_SndKmLastTime = srt::sync::steady_clock::now();
|
||||
}
|
||||
#endif
|
||||
|
||||
CCryptoControl::CCryptoControl(CUDT* parent, SRTSOCKET id):
|
||||
m_parent(parent), // should be initialized in createCC()
|
||||
m_SocketID(id),
|
||||
m_iSndKmKeyLen(0),
|
||||
m_iRcvKmKeyLen(0),
|
||||
m_SndKmState(SRT_KM_S_UNSECURED),
|
||||
m_RcvKmState(SRT_KM_S_UNSECURED),
|
||||
m_KmRefreshRatePkt(0),
|
||||
m_KmPreAnnouncePkt(0),
|
||||
m_bErrorReported(false)
|
||||
srt::CCryptoControl::CCryptoControl(SRTSOCKET id)
|
||||
: m_SocketID(id)
|
||||
, m_iSndKmKeyLen(0)
|
||||
, m_iRcvKmKeyLen(0)
|
||||
, m_SndKmState(SRT_KM_S_UNSECURED)
|
||||
, m_RcvKmState(SRT_KM_S_UNSECURED)
|
||||
, m_KmRefreshRatePkt(0)
|
||||
, m_KmPreAnnouncePkt(0)
|
||||
, m_bErrorReported(false)
|
||||
{
|
||||
|
||||
m_KmSecret.len = 0;
|
||||
//send
|
||||
m_SndKmLastTime = 0;
|
||||
m_SndKmMsg[0].MsgLen = 0;
|
||||
m_SndKmMsg[0].iPeerRetry = 0;
|
||||
m_SndKmMsg[1].MsgLen = 0;
|
||||
|
@ -565,14 +574,14 @@ m_bErrorReported(false)
|
|||
m_hRcvCrypto = NULL;
|
||||
}
|
||||
|
||||
bool CCryptoControl::init(HandshakeSide side, bool bidirectional SRT_ATR_UNUSED)
|
||||
bool srt::CCryptoControl::init(HandshakeSide side, const CSrtConfig& cfg, bool bidirectional SRT_ATR_UNUSED)
|
||||
{
|
||||
// NOTE: initiator creates m_hSndCrypto. When bidirectional,
|
||||
// it creates also m_hRcvCrypto with the same key length.
|
||||
// Acceptor creates nothing - it will create appropriate
|
||||
// contexts when receiving KMREQ from the initiator.
|
||||
|
||||
HLOGC(mglog.Debug, log << "CCryptoControl::init: HS SIDE:"
|
||||
HLOGC(cnlog.Debug, log << "CCryptoControl::init: HS SIDE:"
|
||||
<< (side == HSD_INITIATOR ? "INITIATOR" : "RESPONDER")
|
||||
<< " DIRECTION:" << (bidirectional ? "BOTH" : (side == HSD_INITIATOR) ? "SENDER" : "RECEIVER"));
|
||||
|
||||
|
@ -582,8 +591,8 @@ bool CCryptoControl::init(HandshakeSide side, bool bidirectional SRT_ATR_UNUSED)
|
|||
// Set security-pending state, if a password was set.
|
||||
m_SndKmState = hasPassphrase() ? SRT_KM_S_SECURING : SRT_KM_S_UNSECURED;
|
||||
|
||||
m_KmPreAnnouncePkt = m_parent->m_uKmPreAnnouncePkt;
|
||||
m_KmRefreshRatePkt = m_parent->m_uKmRefreshRatePkt;
|
||||
m_KmPreAnnouncePkt = cfg.uKmPreAnnouncePkt;
|
||||
m_KmRefreshRatePkt = cfg.uKmRefreshRatePkt;
|
||||
|
||||
if ( side == HSD_INITIATOR )
|
||||
{
|
||||
|
@ -592,18 +601,18 @@ bool CCryptoControl::init(HandshakeSide side, bool bidirectional SRT_ATR_UNUSED)
|
|||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
if (m_iSndKmKeyLen == 0)
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "CCryptoControl::init: PBKEYLEN still 0, setting default 16");
|
||||
HLOGC(cnlog.Debug, log << "CCryptoControl::init: PBKEYLEN still 0, setting default 16");
|
||||
m_iSndKmKeyLen = 16;
|
||||
}
|
||||
|
||||
bool ok = createCryptoCtx(Ref(m_hSndCrypto), m_iSndKmKeyLen, HAICRYPT_CRYPTO_DIR_TX);
|
||||
HLOGC(mglog.Debug, log << "CCryptoControl::init: creating SND crypto context: " << ok);
|
||||
bool ok = createCryptoCtx(m_iSndKmKeyLen, HAICRYPT_CRYPTO_DIR_TX, (m_hSndCrypto));
|
||||
HLOGC(cnlog.Debug, log << "CCryptoControl::init: creating SND crypto context: " << ok);
|
||||
|
||||
if (ok && bidirectional)
|
||||
{
|
||||
m_iRcvKmKeyLen = m_iSndKmKeyLen;
|
||||
int st = HaiCrypt_Clone(m_hSndCrypto, HAICRYPT_CRYPTO_DIR_RX, &m_hRcvCrypto);
|
||||
HLOGC(mglog.Debug, log << "CCryptoControl::init: creating CLONED RCV crypto context: status=" << st);
|
||||
HLOGC(cnlog.Debug, log << "CCryptoControl::init: creating CLONED RCV crypto context: status=" << st);
|
||||
ok = st == 0;
|
||||
}
|
||||
|
||||
|
@ -618,45 +627,51 @@ bool CCryptoControl::init(HandshakeSide side, bool bidirectional SRT_ATR_UNUSED)
|
|||
}
|
||||
|
||||
regenCryptoKm(
|
||||
false, // Do not send the key (will be attached it to the HSv5 handshake)
|
||||
bidirectional // replicate the key to the receiver context, if bidirectional
|
||||
);
|
||||
NULL, // Do not send the key (the KM msg will be attached to the HSv5 handshake)
|
||||
bidirectional // replicate the key to the receiver context, if bidirectional
|
||||
);
|
||||
#else
|
||||
LOGC(mglog.Error, log << "CCryptoControl::init: encryption not supported");
|
||||
// This error would be a consequence of setting the passphrase, while encryption
|
||||
// is turned off at compile time. Setting the password itself should be not allowed
|
||||
// so this could only happen as a consequence of an IPE.
|
||||
LOGC(cnlog.Error, log << "CCryptoControl::init: IPE: encryption not supported");
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "CCryptoControl::init: CAN'T CREATE crypto: key length for SND = " << m_iSndKmKeyLen);
|
||||
HLOGC(cnlog.Debug, log << "CCryptoControl::init: CAN'T CREATE crypto: key length for SND = " << m_iSndKmKeyLen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "CCryptoControl::init: NOT creating crypto contexts - will be created upon reception of KMREQ");
|
||||
HLOGC(cnlog.Debug, log << "CCryptoControl::init: NOT creating crypto contexts - will be created upon reception of KMREQ");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCryptoControl::close()
|
||||
void srt::CCryptoControl::close()
|
||||
{
|
||||
/* Wipeout secrets */
|
||||
memset(&m_KmSecret, 0, sizeof(m_KmSecret));
|
||||
}
|
||||
|
||||
std::string CCryptoControl::CONID() const
|
||||
std::string srt::CCryptoControl::CONID() const
|
||||
{
|
||||
if ( m_SocketID == 0 )
|
||||
if (m_SocketID == 0)
|
||||
return "";
|
||||
|
||||
std::ostringstream os;
|
||||
os << "%" << m_SocketID << ":";
|
||||
os << "@" << m_SocketID << ":";
|
||||
|
||||
return os.str();
|
||||
}
|
||||
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
namespace srt {
|
||||
static std::string CryptoFlags(int flg)
|
||||
{
|
||||
using namespace std;
|
||||
|
@ -673,13 +688,13 @@ static std::string CryptoFlags(int flg)
|
|||
copy(f.begin(), f.end(), ostream_iterator<string>(os, "|"));
|
||||
return os.str();
|
||||
}
|
||||
#endif
|
||||
} // namespace srt
|
||||
#endif // ENABLE_HEAVY_LOGGING
|
||||
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
bool CCryptoControl::createCryptoCtx(ref_t<HaiCrypt_Handle> hCrypto, size_t keylen, HaiCrypt_CryptoDir cdir)
|
||||
bool srt::CCryptoControl::createCryptoCtx(size_t keylen, HaiCrypt_CryptoDir cdir, HaiCrypt_Handle& w_hCrypto)
|
||||
{
|
||||
|
||||
if (*hCrypto)
|
||||
if (w_hCrypto)
|
||||
{
|
||||
// XXX You can check here if the existing handle represents
|
||||
// a correctly defined crypto. But this doesn't seem to be
|
||||
|
@ -690,7 +705,7 @@ bool CCryptoControl::createCryptoCtx(ref_t<HaiCrypt_Handle> hCrypto, size_t keyl
|
|||
|
||||
if ((m_KmSecret.len <= 0) || (keylen <= 0))
|
||||
{
|
||||
LOGC(mglog.Error, log << CONID() << "cryptoCtx: missing secret (" << m_KmSecret.len << ") or key length (" << keylen << ")");
|
||||
LOGC(cnlog.Error, log << CONID() << "cryptoCtx: IPE missing secret (" << m_KmSecret.len << ") or key length (" << keylen << ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -711,36 +726,35 @@ bool CCryptoControl::createCryptoCtx(ref_t<HaiCrypt_Handle> hCrypto, size_t keyl
|
|||
crypto_cfg.secret = m_KmSecret;
|
||||
//memcpy(&crypto_cfg.secret, &m_KmSecret, sizeof(crypto_cfg.secret));
|
||||
|
||||
HLOGC(mglog.Debug, log << "CRYPTO CFG: flags=" << CryptoFlags(crypto_cfg.flags) << " xport=" << crypto_cfg.xport << " cryspr=" << crypto_cfg.cryspr
|
||||
HLOGC(cnlog.Debug, log << "CRYPTO CFG: flags=" << CryptoFlags(crypto_cfg.flags) << " xport=" << crypto_cfg.xport << " cryspr=" << crypto_cfg.cryspr
|
||||
<< " keylen=" << crypto_cfg.key_len << " passphrase_length=" << crypto_cfg.secret.len);
|
||||
|
||||
if (HaiCrypt_Create(&crypto_cfg, &hCrypto.get()) != HAICRYPT_OK)
|
||||
if (HaiCrypt_Create(&crypto_cfg, (&w_hCrypto)) != HAICRYPT_OK)
|
||||
{
|
||||
LOGC(mglog.Error, log << CONID() << "cryptoCtx: could not create " << (cdir == HAICRYPT_CRYPTO_DIR_TX ? "tx" : "rx") << " crypto ctx");
|
||||
LOGC(cnlog.Error, log << CONID() << "cryptoCtx: could not create " << (cdir == HAICRYPT_CRYPTO_DIR_TX ? "tx" : "rx") << " crypto ctx");
|
||||
return false;
|
||||
}
|
||||
|
||||
HLOGC(mglog.Debug, log << CONID() << "cryptoCtx: CREATED crypto for dir=" << (cdir == HAICRYPT_CRYPTO_DIR_TX ? "tx" : "rx") << " keylen=" << keylen);
|
||||
HLOGC(cnlog.Debug, log << CONID() << "cryptoCtx: CREATED crypto for dir=" << (cdir == HAICRYPT_CRYPTO_DIR_TX ? "tx" : "rx") << " keylen=" << keylen);
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
bool CCryptoControl::createCryptoCtx(ref_t<HaiCrypt_Handle>, size_t, HaiCrypt_CryptoDir)
|
||||
bool srt::CCryptoControl::createCryptoCtx(size_t, HaiCrypt_CryptoDir, HaiCrypt_Handle&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#endif // SRT_ENABLE_ENCRYPTION
|
||||
|
||||
|
||||
EncryptionStatus CCryptoControl::encrypt(ref_t<CPacket> r_packet SRT_ATR_UNUSED)
|
||||
srt::EncryptionStatus srt::CCryptoControl::encrypt(CPacket& w_packet SRT_ATR_UNUSED)
|
||||
{
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
// Encryption not enabled - do nothing.
|
||||
if ( getSndCryptoFlags() == EK_NOENC )
|
||||
return ENCS_CLEAR;
|
||||
|
||||
CPacket& packet = *r_packet;
|
||||
int rc = HaiCrypt_Tx_Data(m_hSndCrypto, (uint8_t*)packet.getHeader(), (uint8_t*)packet.m_pcData, packet.getLength());
|
||||
int rc = HaiCrypt_Tx_Data(m_hSndCrypto, ((uint8_t*)w_packet.getHeader()), ((uint8_t*)w_packet.m_pcData), w_packet.getLength());
|
||||
if (rc < 0)
|
||||
{
|
||||
return ENCS_FAILED;
|
||||
|
@ -749,7 +763,7 @@ EncryptionStatus CCryptoControl::encrypt(ref_t<CPacket> r_packet SRT_ATR_UNUSED)
|
|||
{
|
||||
// XXX what happens if the encryption is said to be "succeeded",
|
||||
// but the length is 0? Shouldn't this be treated as unwanted?
|
||||
packet.setLength(rc);
|
||||
w_packet.setLength(rc);
|
||||
}
|
||||
|
||||
return ENCS_CLEAR;
|
||||
|
@ -758,14 +772,12 @@ EncryptionStatus CCryptoControl::encrypt(ref_t<CPacket> r_packet SRT_ATR_UNUSED)
|
|||
#endif
|
||||
}
|
||||
|
||||
EncryptionStatus CCryptoControl::decrypt(ref_t<CPacket> r_packet SRT_ATR_UNUSED)
|
||||
srt::EncryptionStatus srt::CCryptoControl::decrypt(CPacket& w_packet SRT_ATR_UNUSED)
|
||||
{
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
CPacket& packet = *r_packet;
|
||||
|
||||
if (packet.getMsgCryptoFlags() == EK_NOENC)
|
||||
if (w_packet.getMsgCryptoFlags() == EK_NOENC)
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "CPacket::decrypt: packet not encrypted");
|
||||
HLOGC(cnlog.Debug, log << "CPacket::decrypt: packet not encrypted");
|
||||
return ENCS_CLEAR; // not encrypted, no need do decrypt, no flags to be modified
|
||||
}
|
||||
|
||||
|
@ -776,8 +788,8 @@ EncryptionStatus CCryptoControl::decrypt(ref_t<CPacket> r_packet SRT_ATR_UNUSED)
|
|||
// We were unaware that the peer has set password,
|
||||
// but now here we are.
|
||||
m_RcvKmState = SRT_KM_S_SECURING;
|
||||
LOGC(mglog.Note, log << "SECURITY UPDATE: Peer has surprised Agent with encryption, but KMX is pending - current packet size="
|
||||
<< packet.getLength() << " dropped");
|
||||
LOGC(cnlog.Note, log << "SECURITY UPDATE: Peer has surprised Agent with encryption, but KMX is pending - current packet size="
|
||||
<< w_packet.getLength() << " dropped");
|
||||
return ENCS_FAILED;
|
||||
}
|
||||
else
|
||||
|
@ -786,7 +798,7 @@ EncryptionStatus CCryptoControl::decrypt(ref_t<CPacket> r_packet SRT_ATR_UNUSED)
|
|||
// which means that it will be unable to decrypt
|
||||
// sent payloads anyway.
|
||||
m_RcvKmState = SRT_KM_S_NOSECRET;
|
||||
LOGP(mglog.Error, "SECURITY FAILURE: Agent has no PW, but Peer sender has declared one, can't decrypt");
|
||||
LOGP(cnlog.Warn, "SECURITY FAILURE: Agent has no PW, but Peer sender has declared one, can't decrypt");
|
||||
// This only informs about the state change; it will be also caught by the condition below
|
||||
}
|
||||
}
|
||||
|
@ -807,28 +819,28 @@ EncryptionStatus CCryptoControl::decrypt(ref_t<CPacket> r_packet SRT_ATR_UNUSED)
|
|||
if (!m_bErrorReported)
|
||||
{
|
||||
m_bErrorReported = true;
|
||||
LOGC(mglog.Error, log << "SECURITY STATUS: " << KmStateStr(m_RcvKmState) << " - can't decrypt packet.");
|
||||
LOGC(cnlog.Error, log << "SECURITY STATUS: " << KmStateStr(m_RcvKmState) << " - can't decrypt w_packet.");
|
||||
}
|
||||
HLOGC(mglog.Debug, log << "Packet still not decrypted, status=" << KmStateStr(m_RcvKmState)
|
||||
<< " - dropping size=" << packet.getLength());
|
||||
HLOGC(cnlog.Debug, log << "Packet still not decrypted, status=" << KmStateStr(m_RcvKmState)
|
||||
<< " - dropping size=" << w_packet.getLength());
|
||||
return ENCS_FAILED;
|
||||
}
|
||||
|
||||
int rc = HaiCrypt_Rx_Data(m_hRcvCrypto, (uint8_t *)packet.getHeader(), (uint8_t *)packet.m_pcData, packet.getLength());
|
||||
int rc = HaiCrypt_Rx_Data(m_hRcvCrypto, ((uint8_t *)w_packet.getHeader()), ((uint8_t *)w_packet.m_pcData), w_packet.getLength());
|
||||
if ( rc <= 0 )
|
||||
{
|
||||
LOGC(mglog.Error, log << "decrypt ERROR (IPE): HaiCrypt_Rx_Data failure=" << rc << " - returning failed decryption");
|
||||
LOGC(cnlog.Error, log << "decrypt ERROR (IPE): HaiCrypt_Rx_Data failure=" << rc << " - returning failed decryption");
|
||||
// -1: decryption failure
|
||||
// 0: key not received yet
|
||||
return ENCS_FAILED;
|
||||
}
|
||||
// Otherwise: rc == decrypted text length.
|
||||
packet.setLength(rc); /* In case clr txt size is different from cipher txt */
|
||||
w_packet.setLength(rc); /* In case clr txt size is different from cipher txt */
|
||||
|
||||
// Decryption succeeded. Update flags.
|
||||
packet.setMsgCryptoFlags(EK_NOENC);
|
||||
w_packet.setMsgCryptoFlags(EK_NOENC);
|
||||
|
||||
HLOGC(mglog.Debug, log << "decrypt: successfully decrypted, resulting length=" << rc);
|
||||
HLOGC(cnlog.Debug, log << "decrypt: successfully decrypted, resulting length=" << rc);
|
||||
return ENCS_CLEAR;
|
||||
#else
|
||||
return ENCS_NOTSUP;
|
||||
|
@ -836,9 +848,10 @@ EncryptionStatus CCryptoControl::decrypt(ref_t<CPacket> r_packet SRT_ATR_UNUSED)
|
|||
}
|
||||
|
||||
|
||||
CCryptoControl::~CCryptoControl()
|
||||
srt::CCryptoControl::~CCryptoControl()
|
||||
{
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
close();
|
||||
if (m_hSndCrypto)
|
||||
{
|
||||
HaiCrypt_Close(m_hSndCrypto);
|
||||
|
@ -850,38 +863,3 @@ CCryptoControl::~CCryptoControl()
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
std::string SrtFlagString(int32_t flags)
|
||||
{
|
||||
#define LEN(arr) (sizeof (arr)/(sizeof ((arr)[0])))
|
||||
|
||||
std::string output;
|
||||
static std::string namera[] = { "TSBPD-snd", "TSBPD-rcv", "haicrypt", "TLPktDrop", "NAKReport", "ReXmitFlag", "StreamAPI" };
|
||||
|
||||
size_t i = 0;
|
||||
for ( ; i < LEN(namera); ++i )
|
||||
{
|
||||
if ( (flags & 1) == 1 )
|
||||
{
|
||||
output += "+" + namera[i] + " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
output += "-" + namera[i] + " ";
|
||||
}
|
||||
|
||||
flags >>= 1;
|
||||
//if ( flags == 0 )
|
||||
// break;
|
||||
}
|
||||
|
||||
#undef LEN
|
||||
|
||||
if ( flags != 0 )
|
||||
{
|
||||
output += "+unknown";
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
70
trunk/3rdparty/srt-1-fit/srtcore/crypto.h
vendored
70
trunk/3rdparty/srt-1-fit/srtcore/crypto.h
vendored
|
@ -13,8 +13,8 @@ written by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC__CRYPTO_H
|
||||
#define INC__CRYPTO_H
|
||||
#ifndef INC_SRT_CRYPTO_H
|
||||
#define INC_SRT_CRYPTO_H
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
@ -28,33 +28,36 @@ written by
|
|||
#include <haicrypt.h>
|
||||
#include <hcrypt_msg.h>
|
||||
|
||||
#if ENABLE_LOGGING
|
||||
|
||||
std::string KmStateStr(SRT_KM_STATE state);
|
||||
|
||||
namespace srt_logging
|
||||
{
|
||||
extern Logger mglog;
|
||||
std::string KmStateStr(SRT_KM_STATE state);
|
||||
#if ENABLE_LOGGING
|
||||
extern Logger cnlog;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
namespace srt
|
||||
{
|
||||
class CUDT;
|
||||
struct CSrtConfig;
|
||||
|
||||
|
||||
// For KMREQ/KMRSP. Only one field is used.
|
||||
const size_t SRT_KMR_KMSTATE = 0;
|
||||
|
||||
#define SRT_CMD_MAXSZ HCRYPT_MSG_KM_MAX_SZ /* Maximum SRT custom messages payload size (bytes) */
|
||||
const size_t SRTDATA_MAXSIZE = SRT_CMD_MAXSZ/sizeof(int32_t);
|
||||
const size_t SRTDATA_MAXSIZE = SRT_CMD_MAXSZ/sizeof(uint32_t);
|
||||
|
||||
enum Whether2RegenKm {DONT_REGEN_KM = 0, REGEN_KM = 1};
|
||||
|
||||
class CCryptoControl
|
||||
{
|
||||
//public:
|
||||
class CUDT* m_parent;
|
||||
SRTSOCKET m_SocketID;
|
||||
SRTSOCKET m_SocketID;
|
||||
|
||||
size_t m_iSndKmKeyLen; //Key length
|
||||
size_t m_iRcvKmKeyLen; //Key length from rx KM
|
||||
size_t m_iSndKmKeyLen; //Key length
|
||||
size_t m_iRcvKmKeyLen; //Key length from rx KM
|
||||
|
||||
// Temporarily allow these to be accessed.
|
||||
public:
|
||||
|
@ -69,7 +72,7 @@ private:
|
|||
|
||||
HaiCrypt_Secret m_KmSecret; //Key material shared secret
|
||||
// Sender
|
||||
uint64_t m_SndKmLastTime;
|
||||
sync::steady_clock::time_point m_SndKmLastTime;
|
||||
struct {
|
||||
unsigned char Msg[HCRYPT_MSG_KM_MAX_SZ];
|
||||
size_t MsgLen;
|
||||
|
@ -82,6 +85,7 @@ private:
|
|||
bool m_bErrorReported;
|
||||
|
||||
public:
|
||||
static void globalInit();
|
||||
|
||||
bool sendingAllowed()
|
||||
{
|
||||
|
@ -106,9 +110,11 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
void regenCryptoKm(bool sendit, bool bidirectional);
|
||||
/// Regenerate cryptographic key material.
|
||||
/// @param[in] sock If not null, the socket will be used to send the KM message to the peer (e.g. KM refresh).
|
||||
/// @param[in] bidirectional If true, the key material will be regenerated for both directions (receiver and sender).
|
||||
void regenCryptoKm(CUDT* sock, bool bidirectional);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
@ -119,7 +125,8 @@ public:
|
|||
void updateKmState(int cmd, size_t srtlen);
|
||||
|
||||
// Detailed processing
|
||||
int processSrtMsg_KMREQ(const uint32_t* srtdata, size_t len, uint32_t* srtdata_out, ref_t<size_t> r_srtlen, int hsv);
|
||||
int processSrtMsg_KMREQ(const uint32_t* srtdata, size_t len, int hsv,
|
||||
uint32_t srtdata_out[], size_t&);
|
||||
|
||||
// This returns:
|
||||
// 1 - the given payload is the same as the currently used key
|
||||
|
@ -158,18 +165,18 @@ public:
|
|||
void getKmMsg_markSent(size_t ki, bool runtime)
|
||||
{
|
||||
#if ENABLE_LOGGING
|
||||
using srt_logging::mglog;
|
||||
using srt_logging::cnlog;
|
||||
#endif
|
||||
|
||||
m_SndKmLastTime = CTimer::getTime();
|
||||
m_SndKmLastTime = sync::steady_clock::now();
|
||||
if (runtime)
|
||||
{
|
||||
m_SndKmMsg[ki].iPeerRetry--;
|
||||
HLOGC(mglog.Debug, log << "getKmMsg_markSent: key[" << ki << "]: len=" << m_SndKmMsg[ki].MsgLen << " retry=" << m_SndKmMsg[ki].iPeerRetry);
|
||||
HLOGC(cnlog.Debug, log << "getKmMsg_markSent: key[" << ki << "]: len=" << m_SndKmMsg[ki].MsgLen << " retry=" << m_SndKmMsg[ki].iPeerRetry);
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "getKmMsg_markSent: key[" << ki << "]: len=" << m_SndKmMsg[ki].MsgLen << " STILL IN USE.");
|
||||
HLOGC(cnlog.Debug, log << "getKmMsg_markSent: key[" << ki << "]: len=" << m_SndKmMsg[ki].MsgLen << " STILL IN USE.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,25 +198,24 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
CCryptoControl(CUDT* parent, SRTSOCKET id);
|
||||
CCryptoControl(SRTSOCKET id);
|
||||
|
||||
// DEBUG PURPOSES:
|
||||
std::string CONID() const;
|
||||
std::string FormatKmMessage(std::string hdr, int cmd, size_t srtlen);
|
||||
|
||||
bool init(HandshakeSide, bool);
|
||||
bool init(HandshakeSide, const CSrtConfig&, bool);
|
||||
void close();
|
||||
|
||||
// This function is used in:
|
||||
// - HSv4 (initial key material exchange - in HSv5 it's attached to handshake)
|
||||
// - case of key regeneration, which should be then exchanged again
|
||||
void sendKeysToPeer(Whether2RegenKm regen);
|
||||
|
||||
/// @return True if the handshake is in progress.
|
||||
/// This function is used in:
|
||||
/// - HSv4 (initial key material exchange - in HSv5 it's attached to handshake)
|
||||
/// - case of key regeneration, which should be then exchanged again.
|
||||
void sendKeysToPeer(CUDT* sock, int iSRTT, Whether2RegenKm regen);
|
||||
|
||||
void setCryptoSecret(const HaiCrypt_Secret& secret)
|
||||
{
|
||||
m_KmSecret = secret;
|
||||
//memcpy(&m_KmSecret, &secret, sizeof(m_KmSecret));
|
||||
}
|
||||
|
||||
void setCryptoKeylen(size_t keylen)
|
||||
|
@ -218,7 +224,7 @@ public:
|
|||
m_iRcvKmKeyLen = keylen;
|
||||
}
|
||||
|
||||
bool createCryptoCtx(ref_t<HaiCrypt_Handle> rh, size_t keylen, HaiCrypt_CryptoDir tx);
|
||||
bool createCryptoCtx(size_t keylen, HaiCrypt_CryptoDir tx, HaiCrypt_Handle& rh);
|
||||
|
||||
int getSndCryptoFlags() const
|
||||
{
|
||||
|
@ -253,16 +259,18 @@ public:
|
|||
/// the encryption will fail.
|
||||
/// XXX Encryption flags in the PH_MSGNO
|
||||
/// field in the header must be correctly set before calling.
|
||||
EncryptionStatus encrypt(ref_t<CPacket> r_packet);
|
||||
EncryptionStatus encrypt(CPacket& w_packet);
|
||||
|
||||
/// Decrypts the packet. If the packet has ENCKEYSPEC part
|
||||
/// in PH_MSGNO set to EK_NOENC, it does nothing. It decrypts
|
||||
/// only if the encryption correctly configured, otherwise it
|
||||
/// fails. After successful decryption, the ENCKEYSPEC part
|
||||
// in PH_MSGNO is set to EK_NOENC.
|
||||
EncryptionStatus decrypt(ref_t<CPacket> r_packet);
|
||||
EncryptionStatus decrypt(CPacket& w_packet);
|
||||
|
||||
~CCryptoControl();
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif // SRT_CONGESTION_CONTROL_H
|
||||
|
|
457
trunk/3rdparty/srt-1-fit/srtcore/epoll.cpp
vendored
457
trunk/3rdparty/srt-1-fit/srtcore/epoll.cpp
vendored
|
@ -50,37 +50,35 @@ modified by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef LINUX
|
||||
#include <sys/epoll.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if __APPLE__
|
||||
#include "TargetConditionals.h"
|
||||
#endif
|
||||
#if defined(BSD) || defined(OSX) || (TARGET_OS_IOS == 1) || (TARGET_OS_TV == 1)
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#define SRT_IMPORT_EVENT
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
|
||||
#if defined(__FreeBSD_kernel__)
|
||||
#include <sys/event.h>
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "epoll.h"
|
||||
#include "logging.h"
|
||||
#include "udt.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace srt::sync;
|
||||
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
namespace srt {
|
||||
static ostream& PrintEpollEvent(ostream& os, int events, int et_events = 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace srt_logging
|
||||
{
|
||||
extern Logger mglog;
|
||||
extern Logger eilog, ealog;
|
||||
}
|
||||
|
||||
using namespace srt_logging;
|
||||
|
@ -89,20 +87,21 @@ using namespace srt_logging;
|
|||
#define IF_DIRNAME(tested, flag, name) (tested & flag ? name : "")
|
||||
#endif
|
||||
|
||||
CEPoll::CEPoll():
|
||||
srt::CEPoll::CEPoll():
|
||||
m_iIDSeed(0)
|
||||
{
|
||||
CGuard::createMutex(m_EPollLock);
|
||||
// Exception -> CUDTUnited ctor.
|
||||
setupMutex(m_EPollLock, "EPoll");
|
||||
}
|
||||
|
||||
CEPoll::~CEPoll()
|
||||
srt::CEPoll::~CEPoll()
|
||||
{
|
||||
CGuard::releaseMutex(m_EPollLock);
|
||||
releaseMutex(m_EPollLock);
|
||||
}
|
||||
|
||||
int CEPoll::create()
|
||||
int srt::CEPoll::create(CEPollDesc** pout)
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
ScopedLock pg(m_EPollLock);
|
||||
|
||||
if (++ m_iIDSeed >= 0x7FFFFFFF)
|
||||
m_iIDSeed = 0;
|
||||
|
@ -114,7 +113,31 @@ int CEPoll::create()
|
|||
int localid = 0;
|
||||
|
||||
#ifdef LINUX
|
||||
localid = epoll_create(1024);
|
||||
|
||||
// NOTE: epoll_create1() and EPOLL_CLOEXEC were introduced in GLIBC-2.9.
|
||||
// So earlier versions of GLIBC, must use epoll_create() and set
|
||||
// FD_CLOEXEC on the file descriptor returned by it after the fact.
|
||||
#if defined(EPOLL_CLOEXEC)
|
||||
int flags = 0;
|
||||
#if ENABLE_SOCK_CLOEXEC
|
||||
flags |= EPOLL_CLOEXEC;
|
||||
#endif
|
||||
localid = epoll_create1(flags);
|
||||
#else
|
||||
localid = epoll_create(1);
|
||||
#if ENABLE_SOCK_CLOEXEC
|
||||
if (localid != -1)
|
||||
{
|
||||
int fdFlags = fcntl(localid, F_GETFD);
|
||||
if (fdFlags != -1)
|
||||
{
|
||||
fdFlags |= FD_CLOEXEC;
|
||||
fcntl(localid, F_SETFD, fdFlags);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Possible reasons of -1 error:
|
||||
EMFILE: The per-user limit on the number of epoll instances imposed by /proc/sys/fs/epoll/max_user_instances was encountered.
|
||||
ENFILE: The system limit on the total number of open files has been reached.
|
||||
|
@ -122,25 +145,82 @@ ENOMEM: There was insufficient memory to create the kernel object.
|
|||
*/
|
||||
if (localid < 0)
|
||||
throw CUDTException(MJ_SETUP, MN_NONE, errno);
|
||||
#elif defined(BSD) || defined(OSX) || (TARGET_OS_IOS == 1) || (TARGET_OS_TV == 1)
|
||||
#elif defined(BSD) || TARGET_OS_MAC
|
||||
localid = kqueue();
|
||||
if (localid < 0)
|
||||
throw CUDTException(MJ_SETUP, MN_NONE, errno);
|
||||
#else
|
||||
// on Solaris, use /dev/poll
|
||||
// TODO: Solaris, use port_getn()
|
||||
// https://docs.oracle.com/cd/E86824_01/html/E54766/port-get-3c.html
|
||||
// on Windows, select
|
||||
#endif
|
||||
|
||||
pair<map<int, CEPollDesc>::iterator, bool> res = m_mPolls.insert(make_pair(m_iIDSeed, CEPollDesc(m_iIDSeed, localid)));
|
||||
if (!res.second) // Insertion failed (no memory?)
|
||||
throw CUDTException(MJ_SETUP, MN_NONE);
|
||||
if (pout)
|
||||
*pout = &res.first->second;
|
||||
|
||||
return m_iIDSeed;
|
||||
}
|
||||
|
||||
int CEPoll::add_ssock(const int eid, const SYSSOCKET& s, const int* events)
|
||||
int srt::CEPoll::clear_usocks(int eid)
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
// This should remove all SRT sockets from given eid.
|
||||
ScopedLock pg (m_EPollLock);
|
||||
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
|
||||
if (p == m_mPolls.end())
|
||||
throw CUDTException(MJ_NOTSUP, MN_EIDINVAL);
|
||||
|
||||
CEPollDesc& d = p->second;
|
||||
|
||||
d.clearAll();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void srt::CEPoll::clear_ready_usocks(CEPollDesc& d, int direction)
|
||||
{
|
||||
if ((direction & ~SRT_EPOLL_EVENTTYPES) != 0)
|
||||
{
|
||||
// This is internal function, so simply report an IPE on incorrect usage.
|
||||
LOGC(eilog.Error, log << "CEPoll::clear_ready_usocks: IPE, event flags exceed event types: " << direction);
|
||||
return;
|
||||
}
|
||||
ScopedLock pg (m_EPollLock);
|
||||
|
||||
vector<SRTSOCKET> cleared;
|
||||
|
||||
CEPollDesc::enotice_t::iterator i = d.enotice_begin();
|
||||
while (i != d.enotice_end())
|
||||
{
|
||||
IF_HEAVY_LOGGING(SRTSOCKET subsock = i->fd);
|
||||
SRTSOCKET rs = d.clearEventSub(i++, direction);
|
||||
// This function returns:
|
||||
// - a valid socket - if there are no other subscription after 'direction' was cleared
|
||||
// - SRT_INVALID_SOCK otherwise
|
||||
// Valid sockets should be collected as sockets that no longer
|
||||
// have a subscribed event should be deleted from subscriptions.
|
||||
if (rs != SRT_INVALID_SOCK)
|
||||
{
|
||||
HLOGC(eilog.Debug, log << "CEPoll::clear_ready_usocks: @" << rs << " got all subscription cleared");
|
||||
cleared.push_back(rs);
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(eilog.Debug, log << "CEPoll::clear_ready_usocks: @" << subsock << " is still subscribed");
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < cleared.size(); ++i)
|
||||
d.removeSubscription(cleared[i]);
|
||||
}
|
||||
|
||||
int srt::CEPoll::add_ssock(const int eid, const SYSSOCKET& s, const int* events)
|
||||
{
|
||||
ScopedLock pg(m_EPollLock);
|
||||
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
|
||||
if (p == m_mPolls.end())
|
||||
|
@ -155,18 +235,18 @@ int CEPoll::add_ssock(const int eid, const SYSSOCKET& s, const int* events)
|
|||
else
|
||||
{
|
||||
ev.events = 0;
|
||||
if (*events & UDT_EPOLL_IN)
|
||||
if (*events & SRT_EPOLL_IN)
|
||||
ev.events |= EPOLLIN;
|
||||
if (*events & UDT_EPOLL_OUT)
|
||||
if (*events & SRT_EPOLL_OUT)
|
||||
ev.events |= EPOLLOUT;
|
||||
if (*events & UDT_EPOLL_ERR)
|
||||
if (*events & SRT_EPOLL_ERR)
|
||||
ev.events |= EPOLLERR;
|
||||
}
|
||||
|
||||
ev.data.fd = s;
|
||||
if (::epoll_ctl(p->second.m_iLocalID, EPOLL_CTL_ADD, s, &ev) < 0)
|
||||
throw CUDTException();
|
||||
#elif defined(BSD) || defined(OSX) || (TARGET_OS_IOS == 1) || (TARGET_OS_TV == 1)
|
||||
#elif defined(BSD) || TARGET_OS_MAC
|
||||
struct kevent ke[2];
|
||||
int num = 0;
|
||||
|
||||
|
@ -177,11 +257,11 @@ int CEPoll::add_ssock(const int eid, const SYSSOCKET& s, const int* events)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (*events & UDT_EPOLL_IN)
|
||||
if (*events & SRT_EPOLL_IN)
|
||||
{
|
||||
EV_SET(&ke[num++], s, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
||||
}
|
||||
if (*events & UDT_EPOLL_OUT)
|
||||
if (*events & SRT_EPOLL_OUT)
|
||||
{
|
||||
EV_SET(&ke[num++], s, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
|
||||
}
|
||||
|
@ -190,6 +270,10 @@ int CEPoll::add_ssock(const int eid, const SYSSOCKET& s, const int* events)
|
|||
throw CUDTException();
|
||||
#else
|
||||
|
||||
// fake use 'events' to prevent warning. Remove when implemented.
|
||||
(void)events;
|
||||
(void)s;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Microsoft Visual Studio doesn't support the #warning directive - nonstandard anyway.
|
||||
// Use #pragma message with the same text.
|
||||
|
@ -206,9 +290,9 @@ int CEPoll::add_ssock(const int eid, const SYSSOCKET& s, const int* events)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CEPoll::remove_ssock(const int eid, const SYSSOCKET& s)
|
||||
int srt::CEPoll::remove_ssock(const int eid, const SYSSOCKET& s)
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
ScopedLock pg(m_EPollLock);
|
||||
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
|
||||
if (p == m_mPolls.end())
|
||||
|
@ -218,7 +302,7 @@ int CEPoll::remove_ssock(const int eid, const SYSSOCKET& s)
|
|||
epoll_event ev; // ev is ignored, for compatibility with old Linux kernel only.
|
||||
if (::epoll_ctl(p->second.m_iLocalID, EPOLL_CTL_DEL, s, &ev) < 0)
|
||||
throw CUDTException();
|
||||
#elif defined(BSD) || defined(OSX) || (TARGET_OS_IOS == 1) || (TARGET_OS_TV == 1)
|
||||
#elif defined(BSD) || TARGET_OS_MAC
|
||||
struct kevent ke;
|
||||
|
||||
//
|
||||
|
@ -237,9 +321,10 @@ int CEPoll::remove_ssock(const int eid, const SYSSOCKET& s)
|
|||
}
|
||||
|
||||
// Need this to atomically modify polled events (ex: remove write/keep read)
|
||||
int CEPoll::update_usock(const int eid, const SRTSOCKET& u, const int* events)
|
||||
int srt::CEPoll::update_usock(const int eid, const SRTSOCKET& u, const int* events)
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
ScopedLock pg(m_EPollLock);
|
||||
IF_HEAVY_LOGGING(ostringstream evd);
|
||||
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
|
||||
if (p == m_mPolls.end())
|
||||
|
@ -250,9 +335,12 @@ int CEPoll::update_usock(const int eid, const SRTSOCKET& u, const int* events)
|
|||
int32_t evts = events ? *events : uint32_t(SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR);
|
||||
bool edgeTriggered = evts & SRT_EPOLL_ET;
|
||||
evts &= ~SRT_EPOLL_ET;
|
||||
|
||||
// et_evts = all events, if SRT_EPOLL_ET, or only those that are always ET otherwise.
|
||||
int32_t et_evts = edgeTriggered ? evts : evts & SRT_EPOLL_ETONLY;
|
||||
if (evts)
|
||||
{
|
||||
pair<CEPollDesc::ewatch_t::iterator, bool> iter_new = d.addWatch(u, evts, edgeTriggered);
|
||||
pair<CEPollDesc::ewatch_t::iterator, bool> iter_new = d.addWatch(u, evts, et_evts);
|
||||
CEPollDesc::Wait& wait = iter_new.first->second;
|
||||
if (!iter_new.second)
|
||||
{
|
||||
|
@ -260,6 +348,7 @@ int CEPoll::update_usock(const int eid, const SRTSOCKET& u, const int* events)
|
|||
// parameter, but others are probably unchanged. Change them
|
||||
// forcefully and take out notices that are no longer valid.
|
||||
const int removable = wait.watch & ~evts;
|
||||
IF_HEAVY_LOGGING(PrintEpollEvent(evd, evts & (~wait.watch)));
|
||||
|
||||
// Check if there are any events that would be removed.
|
||||
// If there are no removed events watched (for example, when
|
||||
|
@ -272,11 +361,16 @@ int CEPoll::update_usock(const int eid, const SRTSOCKET& u, const int* events)
|
|||
|
||||
// Update the watch configuration, including edge
|
||||
wait.watch = evts;
|
||||
if (edgeTriggered)
|
||||
wait.edge = evts;
|
||||
wait.edge = et_evts;
|
||||
|
||||
// Now it should look exactly like newly added
|
||||
// and the state is also updated
|
||||
HLOGC(ealog.Debug, log << "srt_epoll_update_usock: UPDATED E" << eid << " for @" << u << " +" << evd.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
IF_HEAVY_LOGGING(PrintEpollEvent(evd, evts));
|
||||
HLOGC(ealog.Debug, log << "srt_epoll_update_usock: ADDED E" << eid << " for @" << u << " " << evd.str());
|
||||
}
|
||||
|
||||
const int newstate = wait.watch & wait.state;
|
||||
|
@ -287,20 +381,21 @@ int CEPoll::update_usock(const int eid, const SRTSOCKET& u, const int* events)
|
|||
}
|
||||
else if (edgeTriggered)
|
||||
{
|
||||
// Specified only SRT_EPOLL_ET flag, but no event flag. Error.
|
||||
LOGC(ealog.Error, log << "srt_epoll_update_usock: Specified only SRT_EPOLL_ET flag, but no event flag. Error.");
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update with no events means to remove subscription
|
||||
HLOGC(ealog.Debug, log << "srt_epoll_update_usock: REMOVED E" << eid << " socket @" << u);
|
||||
d.removeSubscription(u);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CEPoll::update_ssock(const int eid, const SYSSOCKET& s, const int* events)
|
||||
int srt::CEPoll::update_ssock(const int eid, const SYSSOCKET& s, const int* events)
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
ScopedLock pg(m_EPollLock);
|
||||
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
|
||||
if (p == m_mPolls.end())
|
||||
|
@ -315,18 +410,18 @@ int CEPoll::update_ssock(const int eid, const SYSSOCKET& s, const int* events)
|
|||
else
|
||||
{
|
||||
ev.events = 0;
|
||||
if (*events & UDT_EPOLL_IN)
|
||||
if (*events & SRT_EPOLL_IN)
|
||||
ev.events |= EPOLLIN;
|
||||
if (*events & UDT_EPOLL_OUT)
|
||||
if (*events & SRT_EPOLL_OUT)
|
||||
ev.events |= EPOLLOUT;
|
||||
if (*events & UDT_EPOLL_ERR)
|
||||
if (*events & SRT_EPOLL_ERR)
|
||||
ev.events |= EPOLLERR;
|
||||
}
|
||||
|
||||
ev.data.fd = s;
|
||||
if (::epoll_ctl(p->second.m_iLocalID, EPOLL_CTL_MOD, s, &ev) < 0)
|
||||
throw CUDTException();
|
||||
#elif defined(BSD) || defined(OSX) || (TARGET_OS_IOS == 1) || (TARGET_OS_TV == 1)
|
||||
#elif defined(BSD) || TARGET_OS_MAC
|
||||
struct kevent ke[2];
|
||||
int num = 0;
|
||||
|
||||
|
@ -345,17 +440,23 @@ int CEPoll::update_ssock(const int eid, const SYSSOCKET& s, const int* events)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (*events & UDT_EPOLL_IN)
|
||||
if (*events & SRT_EPOLL_IN)
|
||||
{
|
||||
EV_SET(&ke[num++], s, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
||||
}
|
||||
if (*events & UDT_EPOLL_OUT)
|
||||
if (*events & SRT_EPOLL_OUT)
|
||||
{
|
||||
EV_SET(&ke[num++], s, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
|
||||
}
|
||||
}
|
||||
if (kevent(p->second.m_iLocalID, ke, num, NULL, 0, NULL) < 0)
|
||||
throw CUDTException();
|
||||
#else
|
||||
|
||||
// fake use 'events' to prevent warning. Remove when implemented.
|
||||
(void)events;
|
||||
(void)s;
|
||||
|
||||
#endif
|
||||
// Assuming add is used if not inserted
|
||||
// p->second.m_sLocals.insert(s);
|
||||
|
@ -363,9 +464,9 @@ int CEPoll::update_ssock(const int eid, const SYSSOCKET& s, const int* events)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CEPoll::setflags(const int eid, int32_t flags)
|
||||
int srt::CEPoll::setflags(const int eid, int32_t flags)
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
ScopedLock pg(m_EPollLock);
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
|
||||
if (p == m_mPolls.end())
|
||||
throw CUDTException(MJ_NOTSUP, MN_EIDINVAL);
|
||||
|
@ -388,7 +489,7 @@ int CEPoll::setflags(const int eid, int32_t flags)
|
|||
return oflags;
|
||||
}
|
||||
|
||||
int CEPoll::uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut)
|
||||
int srt::CEPoll::uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut)
|
||||
{
|
||||
// It is allowed to call this function witn fdsSize == 0
|
||||
// and therefore also NULL fdsSet. This will then only report
|
||||
|
@ -396,12 +497,12 @@ int CEPoll::uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t m
|
|||
if (fdsSize < 0 || (fdsSize > 0 && !fdsSet))
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL);
|
||||
|
||||
int64_t entertime = CTimer::getTime();
|
||||
steady_clock::time_point entertime = steady_clock::now();
|
||||
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
ScopedLock pg(m_EPollLock);
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
|
||||
if (p == m_mPolls.end())
|
||||
throw CUDTException(MJ_NOTSUP, MN_EIDINVAL);
|
||||
|
@ -410,7 +511,7 @@ int CEPoll::uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t m
|
|||
if (!ed.flags(SRT_EPOLL_ENABLE_EMPTY) && ed.watch_empty())
|
||||
{
|
||||
// Empty EID is not allowed, report error.
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL);
|
||||
throw CUDTException(MJ_NOTSUP, MN_EEMPTY);
|
||||
}
|
||||
|
||||
if (ed.flags(SRT_EPOLL_ENABLE_OUTPUTCHECK) && (fdsSet == NULL || fdsSize == 0))
|
||||
|
@ -444,16 +545,16 @@ int CEPoll::uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t m
|
|||
return total;
|
||||
}
|
||||
|
||||
if ((msTimeOut >= 0) && (int64_t(CTimer::getTime() - entertime) >= msTimeOut * int64_t(1000)))
|
||||
if ((msTimeOut >= 0) && (count_microseconds(srt::sync::steady_clock::now() - entertime) >= msTimeOut * int64_t(1000)))
|
||||
break; // official wait does: throw CUDTException(MJ_AGAIN, MN_XMTIMEOUT, 0);
|
||||
|
||||
CTimer::waitForEvent();
|
||||
CGlobEvent::waitForEvent();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CEPoll::wait(const int eid, set<SRTSOCKET>* readfds, set<SRTSOCKET>* writefds, int64_t msTimeOut, set<SYSSOCKET>* lrfds, set<SYSSOCKET>* lwfds)
|
||||
int srt::CEPoll::wait(const int eid, set<SRTSOCKET>* readfds, set<SRTSOCKET>* writefds, int64_t msTimeOut, set<SYSSOCKET>* lrfds, set<SYSSOCKET>* lwfds)
|
||||
{
|
||||
// if all fields is NULL and waiting time is infinite, then this would be a deadlock
|
||||
if (!readfds && !writefds && !lrfds && !lwfds && (msTimeOut < 0))
|
||||
|
@ -467,18 +568,16 @@ int CEPoll::wait(const int eid, set<SRTSOCKET>* readfds, set<SRTSOCKET>* writefd
|
|||
|
||||
int total = 0;
|
||||
|
||||
int64_t entertime = CTimer::getTime();
|
||||
|
||||
HLOGC(mglog.Debug, log << "CEPoll::wait: START for eid=" << eid);
|
||||
|
||||
srt::sync::steady_clock::time_point entertime = srt::sync::steady_clock::now();
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
CGuard epollock(m_EPollLock);
|
||||
ScopedLock epollock(m_EPollLock);
|
||||
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
|
||||
if (p == m_mPolls.end())
|
||||
{
|
||||
LOGC(ealog.Error, log << "EID:" << eid << " INVALID.");
|
||||
throw CUDTException(MJ_NOTSUP, MN_EIDINVAL);
|
||||
}
|
||||
|
||||
|
@ -487,7 +586,9 @@ int CEPoll::wait(const int eid, set<SRTSOCKET>* readfds, set<SRTSOCKET>* writefd
|
|||
if (!ed.flags(SRT_EPOLL_ENABLE_EMPTY) && ed.watch_empty() && ed.m_sLocals.empty())
|
||||
{
|
||||
// Empty EID is not allowed, report error.
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL);
|
||||
//throw CUDTException(MJ_NOTSUP, MN_INVAL);
|
||||
LOGC(ealog.Error, log << "EID:" << eid << " no sockets to check, this would deadlock");
|
||||
throw CUDTException(MJ_NOTSUP, MN_EEMPTY, 0);
|
||||
}
|
||||
|
||||
if (ed.flags(SRT_EPOLL_ENABLE_OUTPUTCHECK))
|
||||
|
@ -507,13 +608,13 @@ int CEPoll::wait(const int eid, set<SRTSOCKET>* readfds, set<SRTSOCKET>* writefd
|
|||
{
|
||||
++it_next;
|
||||
IF_HEAVY_LOGGING(++total_noticed);
|
||||
if (readfds && ((it->events & UDT_EPOLL_IN) || (it->events & UDT_EPOLL_ERR)))
|
||||
if (readfds && ((it->events & SRT_EPOLL_IN) || (it->events & SRT_EPOLL_ERR)))
|
||||
{
|
||||
if (readfds->insert(it->fd).second)
|
||||
++total;
|
||||
}
|
||||
|
||||
if (writefds && ((it->events & UDT_EPOLL_OUT) || (it->events & UDT_EPOLL_ERR)))
|
||||
if (writefds && ((it->events & SRT_EPOLL_OUT) || (it->events & SRT_EPOLL_ERR)))
|
||||
{
|
||||
if (writefds->insert(it->fd).second)
|
||||
++total;
|
||||
|
@ -530,13 +631,14 @@ int CEPoll::wait(const int eid, set<SRTSOCKET>* readfds, set<SRTSOCKET>* writefd
|
|||
}
|
||||
}
|
||||
|
||||
HLOGC(mglog.Debug, log << "CEPoll::wait: REPORTED " << total << "/" << total_noticed
|
||||
HLOGC(ealog.Debug, log << "CEPoll::wait: REPORTED " << total << "/" << total_noticed
|
||||
<< debug_sockets.str());
|
||||
|
||||
if (lrfds || lwfds)
|
||||
if ((lrfds || lwfds) && !ed.m_sLocals.empty())
|
||||
{
|
||||
#ifdef LINUX
|
||||
const int max_events = ed.m_sLocals.size();
|
||||
SRT_ASSERT(max_events > 0);
|
||||
epoll_event ev[max_events];
|
||||
int nfds = ::epoll_wait(ed.m_iLocalID, ev, max_events, 0);
|
||||
|
||||
|
@ -554,11 +656,12 @@ int CEPoll::wait(const int eid, set<SRTSOCKET>* readfds, set<SRTSOCKET>* writefd
|
|||
++ total;
|
||||
}
|
||||
}
|
||||
HLOGC(mglog.Debug, log << "CEPoll::wait: LINUX: picking up " << (total - prev_total) << " ready fds.");
|
||||
HLOGC(ealog.Debug, log << "CEPoll::wait: LINUX: picking up " << (total - prev_total) << " ready fds.");
|
||||
|
||||
#elif defined(BSD) || defined(OSX) || (TARGET_OS_IOS == 1) || (TARGET_OS_TV == 1)
|
||||
#elif defined(BSD) || TARGET_OS_MAC
|
||||
struct timespec tmout = {0, 0};
|
||||
const int max_events = ed.m_sLocals.size();
|
||||
SRT_ASSERT(max_events > 0);
|
||||
struct kevent ke[max_events];
|
||||
|
||||
int nfds = kevent(ed.m_iLocalID, NULL, 0, ke, max_events, &tmout);
|
||||
|
@ -578,7 +681,7 @@ int CEPoll::wait(const int eid, set<SRTSOCKET>* readfds, set<SRTSOCKET>* writefd
|
|||
}
|
||||
}
|
||||
|
||||
HLOGC(mglog.Debug, log << "CEPoll::wait: Darwin/BSD: picking up " << (total - prev_total) << " ready fds.");
|
||||
HLOGC(ealog.Debug, log << "CEPoll::wait: Darwin/BSD: picking up " << (total - prev_total) << " ready fds.");
|
||||
|
||||
#else
|
||||
//currently "select" is used for all non-Linux platforms.
|
||||
|
@ -623,34 +726,127 @@ int CEPoll::wait(const int eid, set<SRTSOCKET>* readfds, set<SRTSOCKET>* writefd
|
|||
}
|
||||
}
|
||||
|
||||
HLOGC(mglog.Debug, log << "CEPoll::wait: select(otherSYS): picking up " << (total - prev_total) << " ready fds.");
|
||||
HLOGC(ealog.Debug, log << "CEPoll::wait: select(otherSYS): picking up " << (total - prev_total) << " ready fds.");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // END-LOCK: m_EPollLock
|
||||
|
||||
HLOGC(mglog.Debug, log << "CEPoll::wait: Total of " << total << " READY SOCKETS");
|
||||
HLOGC(ealog.Debug, log << "CEPoll::wait: Total of " << total << " READY SOCKETS");
|
||||
|
||||
if (total > 0)
|
||||
return total;
|
||||
|
||||
if ((msTimeOut >= 0) && (int64_t(CTimer::getTime() - entertime) >= msTimeOut * int64_t(1000)))
|
||||
if ((msTimeOut >= 0) && (count_microseconds(srt::sync::steady_clock::now() - entertime) >= msTimeOut * int64_t(1000)))
|
||||
{
|
||||
HLOGP(mglog.Debug, "... not waiting longer - timeout");
|
||||
HLOGC(ealog.Debug, log << "EID:" << eid << ": TIMEOUT.");
|
||||
throw CUDTException(MJ_AGAIN, MN_XMTIMEOUT, 0);
|
||||
}
|
||||
|
||||
CTimer::EWait wt ATR_UNUSED = CTimer::waitForEvent();
|
||||
HLOGC(mglog.Debug, log << "CEPoll::wait: EVENT WAITING: "
|
||||
<< (wt == CTimer::WT_TIMEOUT ? "CHECKPOINT" : wt == CTimer::WT_EVENT ? "TRIGGERED" : "ERROR"));
|
||||
const bool wait_signaled SRT_ATR_UNUSED = CGlobEvent::waitForEvent();
|
||||
HLOGC(ealog.Debug, log << "CEPoll::wait: EVENT WAITING: "
|
||||
<< (wait_signaled ? "TRIGGERED" : "CHECKPOINT"));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CEPoll::release(const int eid)
|
||||
int srt::CEPoll::swait(CEPollDesc& d, map<SRTSOCKET, int>& st, int64_t msTimeOut, bool report_by_exception)
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
{
|
||||
ScopedLock lg (m_EPollLock);
|
||||
if (!d.flags(SRT_EPOLL_ENABLE_EMPTY) && d.watch_empty() && msTimeOut < 0)
|
||||
{
|
||||
// no socket is being monitored, this may be a deadlock
|
||||
LOGC(ealog.Error, log << "EID:" << d.m_iID << " no sockets to check, this would deadlock");
|
||||
if (report_by_exception)
|
||||
throw CUDTException(MJ_NOTSUP, MN_EEMPTY, 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
st.clear();
|
||||
|
||||
steady_clock::time_point entertime = steady_clock::now();
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
// Not extracting separately because this function is
|
||||
// for internal use only and we state that the eid could
|
||||
// not be deleted or changed the target CEPollDesc in the
|
||||
// meantime.
|
||||
|
||||
// Here we only prevent the pollset be updated simultaneously
|
||||
// with unstable reading.
|
||||
ScopedLock lg (m_EPollLock);
|
||||
|
||||
if (!d.flags(SRT_EPOLL_ENABLE_EMPTY) && d.watch_empty())
|
||||
{
|
||||
// Empty EID is not allowed, report error.
|
||||
throw CUDTException(MJ_NOTSUP, MN_EEMPTY);
|
||||
}
|
||||
|
||||
if (!d.m_sLocals.empty())
|
||||
{
|
||||
// XXX Add error log
|
||||
// uwait should not be used with EIDs subscribed to system sockets
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL);
|
||||
}
|
||||
|
||||
bool empty = d.enotice_empty();
|
||||
|
||||
if (!empty || msTimeOut == 0)
|
||||
{
|
||||
IF_HEAVY_LOGGING(ostringstream singles);
|
||||
// If msTimeOut == 0, it means that we need the information
|
||||
// immediately, we don't want to wait. Therefore in this case
|
||||
// report also when none is ready.
|
||||
int total = 0; // This is a list, so count it during iteration
|
||||
CEPollDesc::enotice_t::iterator i = d.enotice_begin();
|
||||
while (i != d.enotice_end())
|
||||
{
|
||||
++total;
|
||||
st[i->fd] = i->events;
|
||||
IF_HEAVY_LOGGING(singles << "@" << i->fd << ":");
|
||||
IF_HEAVY_LOGGING(PrintEpollEvent(singles, i->events, i->parent->edgeOnly()));
|
||||
const bool edged SRT_ATR_UNUSED = d.checkEdge(i++); // NOTE: potentially deletes `i`
|
||||
IF_HEAVY_LOGGING(singles << (edged ? "<^> " : " "));
|
||||
}
|
||||
|
||||
// Logging into 'singles' because it notifies as to whether
|
||||
// the edge-triggered event has been cleared
|
||||
HLOGC(ealog.Debug, log << "E" << d.m_iID << " rdy=" << total << ": "
|
||||
<< singles.str()
|
||||
<< " TRACKED: " << d.DisplayEpollWatch());
|
||||
return total;
|
||||
}
|
||||
// Don't report any updates because this check happens
|
||||
// extremely often.
|
||||
}
|
||||
|
||||
if ((msTimeOut >= 0) && ((steady_clock::now() - entertime) >= microseconds_from(msTimeOut * int64_t(1000))))
|
||||
{
|
||||
HLOGC(ealog.Debug, log << "EID:" << d.m_iID << ": TIMEOUT.");
|
||||
if (report_by_exception)
|
||||
throw CUDTException(MJ_AGAIN, MN_XMTIMEOUT, 0);
|
||||
return 0; // meaning "none is ready"
|
||||
}
|
||||
|
||||
CGlobEvent::waitForEvent();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool srt::CEPoll::empty(const CEPollDesc& d) const
|
||||
{
|
||||
ScopedLock lg (m_EPollLock);
|
||||
return d.watch_empty();
|
||||
}
|
||||
|
||||
int srt::CEPoll::release(const int eid)
|
||||
{
|
||||
ScopedLock pg(m_EPollLock);
|
||||
|
||||
map<int, CEPollDesc>::iterator i = m_mPolls.find(eid);
|
||||
if (i == m_mPolls.end())
|
||||
|
@ -659,7 +855,7 @@ int CEPoll::release(const int eid)
|
|||
#ifdef LINUX
|
||||
// release local/system epoll descriptor
|
||||
::close(i->second.m_iLocalID);
|
||||
#elif defined(BSD) || defined(OSX) || (TARGET_OS_IOS == 1) || (TARGET_OS_TV == 1)
|
||||
#elif defined(BSD) || TARGET_OS_MAC
|
||||
::close(i->second.m_iLocalID);
|
||||
#endif
|
||||
|
||||
|
@ -669,16 +865,29 @@ int CEPoll::release(const int eid)
|
|||
}
|
||||
|
||||
|
||||
int CEPoll::update_events(const SRTSOCKET& uid, std::set<int>& eids, const int events, const bool enable)
|
||||
int srt::CEPoll::update_events(const SRTSOCKET& uid, std::set<int>& eids, const int events, const bool enable)
|
||||
{
|
||||
// As event flags no longer contain only event types, check now.
|
||||
if ((events & ~SRT_EPOLL_EVENTTYPES) != 0)
|
||||
{
|
||||
LOGC(eilog.Fatal, log << "epoll/update: IPE: 'events' parameter shall not contain special flags!");
|
||||
return -1; // still, ignored.
|
||||
}
|
||||
|
||||
int nupdated = 0;
|
||||
vector<int> lost;
|
||||
|
||||
CGuard pg(m_EPollLock);
|
||||
IF_HEAVY_LOGGING(ostringstream debug);
|
||||
IF_HEAVY_LOGGING(debug << "epoll/update: @" << uid << " " << (enable ? "+" : "-"));
|
||||
IF_HEAVY_LOGGING(PrintEpollEvent(debug, events));
|
||||
|
||||
ScopedLock pg (m_EPollLock);
|
||||
for (set<int>::iterator i = eids.begin(); i != eids.end(); ++ i)
|
||||
{
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(*i);
|
||||
if (p == m_mPolls.end())
|
||||
{
|
||||
HLOGC(eilog.Note, log << "epoll/update: E" << *i << " was deleted in the meantime");
|
||||
// EID invalid, though still present in the socket's subscriber list
|
||||
// (dangling in the socket). Postpone to fix the subscruption and continue.
|
||||
lost.push_back(*i);
|
||||
|
@ -692,9 +901,12 @@ int CEPoll::update_events(const SRTSOCKET& uid, std::set<int>& eids, const int e
|
|||
if (!pwait)
|
||||
{
|
||||
// As this is mapped in the socket's data, it should be impossible.
|
||||
LOGC(eilog.Error, log << "epoll/update: IPE: update struck E"
|
||||
<< (*i) << " which is NOT SUBSCRIBED to @" << uid);
|
||||
continue;
|
||||
}
|
||||
|
||||
IF_HEAVY_LOGGING(string tracking = " TRACKING: " + ed.DisplayEpollWatch());
|
||||
// compute new states
|
||||
|
||||
// New state to be set into the permanent state
|
||||
|
@ -704,13 +916,21 @@ int CEPoll::update_events(const SRTSOCKET& uid, std::set<int>& eids, const int e
|
|||
// compute states changes!
|
||||
int changes = pwait->state ^ newstate; // oldState XOR newState
|
||||
if (!changes)
|
||||
{
|
||||
HLOGC(eilog.Debug, log << debug.str() << ": E" << (*i)
|
||||
<< tracking << " NOT updated: no changes");
|
||||
continue; // no changes!
|
||||
}
|
||||
// assign new state
|
||||
pwait->state = newstate;
|
||||
// filter change relating what is watching
|
||||
changes &= pwait->watch;
|
||||
if (!changes)
|
||||
{
|
||||
HLOGC(eilog.Debug, log << debug.str() << ": E" << (*i)
|
||||
<< tracking << " NOT updated: not subscribed");
|
||||
continue; // no change watching
|
||||
}
|
||||
// set events changes!
|
||||
|
||||
// This function will update the notice object associated with
|
||||
|
@ -718,10 +938,75 @@ int CEPoll::update_events(const SRTSOCKET& uid, std::set<int>& eids, const int e
|
|||
// - if enable, it will set event flags, possibly in a new notice object
|
||||
// - if !enable, it will clear event flags, possibly remove notice if resulted in 0
|
||||
ed.updateEventNotice(*pwait, uid, events, enable);
|
||||
++nupdated;
|
||||
|
||||
HLOGC(eilog.Debug, log << debug.str() << ": E" << (*i)
|
||||
<< " TRACKING: " << ed.DisplayEpollWatch());
|
||||
}
|
||||
|
||||
for (vector<int>::iterator i = lost.begin(); i != lost.end(); ++ i)
|
||||
eids.erase(*i);
|
||||
|
||||
return 0;
|
||||
return nupdated;
|
||||
}
|
||||
|
||||
// Debug use only.
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
namespace srt
|
||||
{
|
||||
|
||||
static ostream& PrintEpollEvent(ostream& os, int events, int et_events)
|
||||
{
|
||||
static pair<int, const char*> const namemap [] = {
|
||||
make_pair(SRT_EPOLL_IN, "R"),
|
||||
make_pair(SRT_EPOLL_OUT, "W"),
|
||||
make_pair(SRT_EPOLL_ERR, "E"),
|
||||
make_pair(SRT_EPOLL_UPDATE, "U")
|
||||
};
|
||||
|
||||
int N = Size(namemap);
|
||||
|
||||
for (int i = 0; i < N; ++i)
|
||||
{
|
||||
if (events & namemap[i].first)
|
||||
{
|
||||
os << "[";
|
||||
if (et_events & namemap[i].first)
|
||||
os << "^";
|
||||
os << namemap[i].second << "]";
|
||||
}
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
string DisplayEpollResults(const std::map<SRTSOCKET, int>& sockset)
|
||||
{
|
||||
typedef map<SRTSOCKET, int> fmap_t;
|
||||
ostringstream os;
|
||||
for (fmap_t::const_iterator i = sockset.begin(); i != sockset.end(); ++i)
|
||||
{
|
||||
os << "@" << i->first << ":";
|
||||
PrintEpollEvent(os, i->second);
|
||||
os << " ";
|
||||
}
|
||||
|
||||
return os.str();
|
||||
}
|
||||
|
||||
string CEPollDesc::DisplayEpollWatch()
|
||||
{
|
||||
ostringstream os;
|
||||
for (ewatch_t::const_iterator i = m_USockWatchState.begin(); i != m_USockWatchState.end(); ++i)
|
||||
{
|
||||
os << "@" << i->first << ":";
|
||||
PrintEpollEvent(os, i->second.watch, i->second.edge);
|
||||
os << " ";
|
||||
}
|
||||
|
||||
return os.str();
|
||||
}
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
269
trunk/3rdparty/srt-1-fit/srtcore/epoll.h
vendored
Executable file → Normal file
269
trunk/3rdparty/srt-1-fit/srtcore/epoll.h
vendored
Executable file → Normal file
|
@ -50,8 +50,8 @@ modified by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_EPOLL_H__
|
||||
#define __UDT_EPOLL_H__
|
||||
#ifndef INC_SRT_EPOLL_H
|
||||
#define INC_SRT_EPOLL_H
|
||||
|
||||
|
||||
#include <map>
|
||||
|
@ -59,8 +59,15 @@ modified by
|
|||
#include <list>
|
||||
#include "udt.h"
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
struct CEPollDesc
|
||||
class CUDT;
|
||||
class CRendezvousQueue;
|
||||
class CUDTGroup;
|
||||
|
||||
|
||||
class CEPollDesc
|
||||
{
|
||||
const int m_iID; // epoll ID
|
||||
|
||||
|
@ -86,40 +93,62 @@ struct CEPollDesc
|
|||
{
|
||||
/// Events the subscriber is interested with. Only those will be
|
||||
/// regarded when updating event flags.
|
||||
int watch;
|
||||
int32_t watch;
|
||||
|
||||
/// Which events should be edge-triggered. When the event isn't
|
||||
/// mentioned in `watch`, this bit flag is disregarded. Otherwise
|
||||
/// it means that the event is to be waited for persistent state
|
||||
/// if this flag is not present here, and for edge trigger, if
|
||||
/// the flag is present here.
|
||||
int edge;
|
||||
int32_t edge;
|
||||
|
||||
/// The current persistent state. This is usually duplicated in
|
||||
/// a dedicated state object in `m_USockEventNotice`, however the state
|
||||
/// here will stay forever as is, regardless of the edge/persistent
|
||||
/// subscription mode for the event.
|
||||
int state;
|
||||
int32_t state;
|
||||
|
||||
/// The iterator to `m_USockEventNotice` container that contains the
|
||||
/// event notice object for this subscription, or the value from
|
||||
/// `nullNotice()` if there is no such object.
|
||||
enotice_t::iterator notit;
|
||||
|
||||
Wait(int sub, bool etr, enotice_t::iterator i)
|
||||
Wait(explicit_t<int32_t> sub, explicit_t<int32_t> etr, enotice_t::iterator i)
|
||||
:watch(sub)
|
||||
,edge(etr ? sub : 0)
|
||||
,edge(etr)
|
||||
,state(0)
|
||||
,notit(i)
|
||||
{
|
||||
}
|
||||
|
||||
int edgeOnly() { return edge & watch; }
|
||||
|
||||
/// Clear all flags for given direction from the notices
|
||||
/// and subscriptions, and checks if this made the event list
|
||||
/// for this watch completely empty.
|
||||
/// @param direction event type that has to be cleared
|
||||
/// @return true, if this cleared the last event (the caller
|
||||
/// want to remove the subscription for this socket)
|
||||
bool clear(int32_t direction)
|
||||
{
|
||||
if (watch & direction)
|
||||
{
|
||||
watch &= ~direction;
|
||||
edge &= ~direction;
|
||||
state &= ~direction;
|
||||
|
||||
return watch == 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<SRTSOCKET, Wait> ewatch_t;
|
||||
|
||||
private:
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
std::string DisplayEpollWatch();
|
||||
#endif
|
||||
|
||||
/// Sockets that are subscribed for events in this eid.
|
||||
ewatch_t m_USockWatchState;
|
||||
|
@ -135,7 +164,10 @@ private:
|
|||
|
||||
enotice_t::iterator nullNotice() { return m_USockEventNotice.end(); }
|
||||
|
||||
public:
|
||||
// Only CEPoll class should have access to it.
|
||||
// Guarding private access to the class is not necessary
|
||||
// within the epoll module.
|
||||
friend class CEPoll;
|
||||
|
||||
CEPollDesc(int id, int localID)
|
||||
: m_iID(id)
|
||||
|
@ -147,13 +179,13 @@ public:
|
|||
static const int32_t EF_NOCHECK_EMPTY = 1 << 0;
|
||||
static const int32_t EF_CHECK_REP = 1 << 1;
|
||||
|
||||
int32_t flags() { return m_Flags; }
|
||||
bool flags(int32_t f) { return (m_Flags & f) != 0; }
|
||||
int32_t flags() const { return m_Flags; }
|
||||
bool flags(int32_t f) const { return (m_Flags & f) != 0; }
|
||||
void set_flags(int32_t flg) { m_Flags |= flg; }
|
||||
void clr_flags(int32_t flg) { m_Flags &= ~flg; }
|
||||
|
||||
// Container accessors for ewatch_t.
|
||||
bool watch_empty() { return m_USockWatchState.empty(); }
|
||||
bool watch_empty() const { return m_USockWatchState.empty(); }
|
||||
Wait* watch_find(SRTSOCKET sock)
|
||||
{
|
||||
ewatch_t::iterator i = m_USockWatchState.find(sock);
|
||||
|
@ -165,13 +197,16 @@ public:
|
|||
// Container accessors for enotice_t.
|
||||
enotice_t::iterator enotice_begin() { return m_USockEventNotice.begin(); }
|
||||
enotice_t::iterator enotice_end() { return m_USockEventNotice.end(); }
|
||||
enotice_t::const_iterator enotice_begin() const { return m_USockEventNotice.begin(); }
|
||||
enotice_t::const_iterator enotice_end() const { return m_USockEventNotice.end(); }
|
||||
bool enotice_empty() const { return m_USockEventNotice.empty(); }
|
||||
|
||||
const int m_iLocalID; // local system epoll ID
|
||||
std::set<SYSSOCKET> m_sLocals; // set of local (non-UDT) descriptors
|
||||
|
||||
std::pair<ewatch_t::iterator, bool> addWatch(SRTSOCKET sock, int32_t events, bool edgeTrg)
|
||||
std::pair<ewatch_t::iterator, bool> addWatch(SRTSOCKET sock, explicit_t<int32_t> events, explicit_t<int32_t> et_events)
|
||||
{
|
||||
return m_USockWatchState.insert(std::make_pair(sock, Wait(events, edgeTrg, nullNotice())));
|
||||
return m_USockWatchState.insert(std::make_pair(sock, Wait(events, et_events, nullNotice())));
|
||||
}
|
||||
|
||||
void addEventNotice(Wait& wait, SRTSOCKET sock, int events)
|
||||
|
@ -224,6 +259,12 @@ public:
|
|||
m_USockWatchState.erase(i);
|
||||
}
|
||||
|
||||
void clearAll()
|
||||
{
|
||||
m_USockEventNotice.clear();
|
||||
m_USockWatchState.clear();
|
||||
}
|
||||
|
||||
void removeExistingNotices(Wait& wait)
|
||||
{
|
||||
m_USockEventNotice.erase(wait.notit);
|
||||
|
@ -281,12 +322,44 @@ public:
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// This should work in a loop around the notice container of
|
||||
/// the given eid container and clear out the notice for
|
||||
/// particular event type. If this has cleared effectively the
|
||||
/// last existing event, it should return the socket id
|
||||
/// so that the caller knows to remove it also from subscribers.
|
||||
///
|
||||
/// @param i iterator in the notice container
|
||||
/// @param event event type to be cleared
|
||||
/// @retval (socket) Socket to be removed from subscriptions
|
||||
/// @retval SRT_INVALID_SOCK Nothing to be done (associated socket
|
||||
/// still has other subscriptions)
|
||||
SRTSOCKET clearEventSub(enotice_t::iterator i, int event)
|
||||
{
|
||||
// We need to remove the notice and subscription
|
||||
// for this event. The 'i' iterator is safe to
|
||||
// delete, even indirectly.
|
||||
|
||||
// This works merely like checkEdge, just on request to clear the
|
||||
// identified event, if found.
|
||||
if (i->events & event)
|
||||
{
|
||||
// The notice has a readiness flag on this event.
|
||||
// This means that there exists also a subscription.
|
||||
Wait* w = i->parent;
|
||||
if (w->clear(event))
|
||||
return i->fd;
|
||||
}
|
||||
|
||||
return SRT_INVALID_SOCK;
|
||||
}
|
||||
};
|
||||
|
||||
class CEPoll
|
||||
{
|
||||
friend class CUDT;
|
||||
friend class CRendezvousQueue;
|
||||
friend class srt::CUDT;
|
||||
friend class srt::CUDTGroup;
|
||||
friend class srt::CRendezvousQueue;
|
||||
|
||||
public:
|
||||
CEPoll();
|
||||
|
@ -294,90 +367,122 @@ public:
|
|||
|
||||
public: // for CUDTUnited API
|
||||
|
||||
/// create a new EPoll.
|
||||
/// @return new EPoll ID if success, otherwise an error number.
|
||||
/// create a new EPoll.
|
||||
/// @return new EPoll ID if success, otherwise an error number.
|
||||
int create(CEPollDesc** ppd = 0);
|
||||
|
||||
int create();
|
||||
|
||||
/// add a UDT socket to an EPoll.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [in] u UDT Socket ID.
|
||||
/// @param [in] events events to watch.
|
||||
/// @return 0 if success, otherwise an error number.
|
||||
/// delete all user sockets (SRT sockets) from an EPoll
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @return 0
|
||||
int clear_usocks(int eid);
|
||||
|
||||
int add_usock(const int eid, const SRTSOCKET& u, const int* events = NULL) { return update_usock(eid, u, events); }
|
||||
|
||||
/// add a system socket to an EPoll.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [in] s system Socket ID.
|
||||
/// @param [in] events events to watch.
|
||||
/// @return 0 if success, otherwise an error number.
|
||||
/// add a system socket to an EPoll.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [in] s system Socket ID.
|
||||
/// @param [in] events events to watch.
|
||||
/// @return 0 if success, otherwise an error number.
|
||||
|
||||
int add_ssock(const int eid, const SYSSOCKET& s, const int* events = NULL);
|
||||
|
||||
/// remove a UDT socket event from an EPoll; socket will be removed if no events to watch.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [in] u UDT socket ID.
|
||||
/// @return 0 if success, otherwise an error number.
|
||||
|
||||
int remove_usock(const int eid, const SRTSOCKET& u) { static const int Null(0); return update_usock(eid, u, &Null);}
|
||||
|
||||
/// remove a system socket event from an EPoll; socket will be removed if no events to watch.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [in] s system socket ID.
|
||||
/// @return 0 if success, otherwise an error number.
|
||||
/// remove a system socket event from an EPoll; socket will be removed if no events to watch.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [in] s system socket ID.
|
||||
/// @return 0 if success, otherwise an error number.
|
||||
|
||||
int remove_ssock(const int eid, const SYSSOCKET& s);
|
||||
/// update a UDT socket events from an EPoll.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [in] u UDT socket ID.
|
||||
/// @param [in] events events to watch.
|
||||
/// @return 0 if success, otherwise an error number.
|
||||
/// update a UDT socket events from an EPoll.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [in] u UDT socket ID.
|
||||
/// @param [in] events events to watch.
|
||||
/// @return 0 if success, otherwise an error number.
|
||||
|
||||
int update_usock(const int eid, const SRTSOCKET& u, const int* events);
|
||||
|
||||
/// update a system socket events from an EPoll.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [in] u UDT socket ID.
|
||||
/// @param [in] events events to watch.
|
||||
/// @return 0 if success, otherwise an error number.
|
||||
/// update a system socket events from an EPoll.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [in] u UDT socket ID.
|
||||
/// @param [in] events events to watch.
|
||||
/// @return 0 if success, otherwise an error number.
|
||||
|
||||
int update_ssock(const int eid, const SYSSOCKET& s, const int* events = NULL);
|
||||
|
||||
/// wait for EPoll events or timeout.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [out] readfds UDT sockets available for reading.
|
||||
/// @param [out] writefds UDT sockets available for writing.
|
||||
/// @param [in] msTimeOut timeout threshold, in milliseconds.
|
||||
/// @param [out] lrfds system file descriptors for reading.
|
||||
/// @param [out] lwfds system file descriptors for writing.
|
||||
/// @return number of sockets available for IO.
|
||||
/// wait for EPoll events or timeout.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [out] readfds UDT sockets available for reading.
|
||||
/// @param [out] writefds UDT sockets available for writing.
|
||||
/// @param [in] msTimeOut timeout threshold, in milliseconds.
|
||||
/// @param [out] lrfds system file descriptors for reading.
|
||||
/// @param [out] lwfds system file descriptors for writing.
|
||||
/// @return number of sockets available for IO.
|
||||
|
||||
int wait(const int eid, std::set<SRTSOCKET>* readfds, std::set<SRTSOCKET>* writefds, int64_t msTimeOut, std::set<SYSSOCKET>* lrfds, std::set<SYSSOCKET>* lwfds);
|
||||
|
||||
/// wait for EPoll events or timeout optimized with explicit EPOLL_ERR event and the edge mode option.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [out] fdsSet array of user socket events (SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR).
|
||||
/// @param [int] fdsSize of fds array
|
||||
/// @param [in] msTimeOut timeout threshold, in milliseconds.
|
||||
/// @return total of available events in the epoll system (can be greater than fdsSize)
|
||||
typedef std::map<SRTSOCKET, int> fmap_t;
|
||||
|
||||
/// Lightweit and more internal-reaching version of `uwait` for internal use only.
|
||||
/// This function wait for sockets to be ready and reports them in `st` map.
|
||||
///
|
||||
/// @param d the internal structure of the epoll container
|
||||
/// @param st output container for the results: { socket_type, event }
|
||||
/// @param msTimeOut timeout after which return with empty output is allowed
|
||||
/// @param report_by_exception if true, errors will result in exception intead of returning -1
|
||||
/// @retval -1 error occurred
|
||||
/// @retval >=0 number of ready sockets (actually size of `st`)
|
||||
int swait(CEPollDesc& d, fmap_t& st, int64_t msTimeOut, bool report_by_exception = true);
|
||||
|
||||
/// Empty subscription check - for internal use only.
|
||||
bool empty(const CEPollDesc& d) const;
|
||||
|
||||
/// Reports which events are ready on the given socket.
|
||||
/// @param mp socket event map retirned by `swait`
|
||||
/// @param sock which socket to ask
|
||||
/// @return event flags for given socket, or 0 if none
|
||||
static int ready(const fmap_t& mp, SRTSOCKET sock)
|
||||
{
|
||||
fmap_t::const_iterator y = mp.find(sock);
|
||||
if (y == mp.end())
|
||||
return 0;
|
||||
return y->second;
|
||||
}
|
||||
|
||||
/// Reports whether socket is ready for given event.
|
||||
/// @param mp socket event map retirned by `swait`
|
||||
/// @param sock which socket to ask
|
||||
/// @param event which events it should be ready for
|
||||
/// @return true if the given socket is ready for given event
|
||||
static bool isready(const fmap_t& mp, SRTSOCKET sock, SRT_EPOLL_OPT event)
|
||||
{
|
||||
return (ready(mp, sock) & event) != 0;
|
||||
}
|
||||
|
||||
// Could be a template directly, but it's now hidden in the imp file.
|
||||
void clear_ready_usocks(CEPollDesc& d, int direction);
|
||||
|
||||
/// wait for EPoll events or timeout optimized with explicit EPOLL_ERR event and the edge mode option.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @param [out] fdsSet array of user socket events (SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR).
|
||||
/// @param [int] fdsSize of fds array
|
||||
/// @param [in] msTimeOut timeout threshold, in milliseconds.
|
||||
/// @return total of available events in the epoll system (can be greater than fdsSize)
|
||||
|
||||
int uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut);
|
||||
|
||||
/// close and release an EPoll.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @return 0 if success, otherwise an error number.
|
||||
|
||||
/// close and release an EPoll.
|
||||
/// @param [in] eid EPoll ID.
|
||||
/// @return 0 if success, otherwise an error number.
|
||||
|
||||
int release(const int eid);
|
||||
|
||||
public: // for CUDT to acknowledge IO status
|
||||
|
||||
/// Update events available for a UDT socket.
|
||||
/// @param [in] uid UDT socket ID.
|
||||
/// @param [in] eids EPoll IDs to be set
|
||||
/// @param [in] events Combination of events to update
|
||||
/// @param [in] enable true -> enable, otherwise disable
|
||||
/// @return 0 if success, otherwise an error number
|
||||
/// Update events available for a UDT socket. At the end this function
|
||||
/// counts the number of updated EIDs with given events.
|
||||
/// @param [in] uid UDT socket ID.
|
||||
/// @param [in] eids EPoll IDs to be set
|
||||
/// @param [in] events Combination of events to update
|
||||
/// @param [in] enable true -> enable, otherwise disable
|
||||
/// @return -1 if invalid events, otherwise the number of changes
|
||||
|
||||
int update_events(const SRTSOCKET& uid, std::set<int>& eids, int events, bool enable);
|
||||
|
||||
|
@ -385,11 +490,17 @@ public: // for CUDT to acknowledge IO status
|
|||
|
||||
private:
|
||||
int m_iIDSeed; // seed to generate a new ID
|
||||
pthread_mutex_t m_SeedLock;
|
||||
srt::sync::Mutex m_SeedLock;
|
||||
|
||||
std::map<int, CEPollDesc> m_mPolls; // all epolls
|
||||
pthread_mutex_t m_EPollLock;
|
||||
mutable srt::sync::Mutex m_EPollLock;
|
||||
};
|
||||
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
std::string DisplayEpollResults(const std::map<SRTSOCKET, int>& sockset);
|
||||
#endif
|
||||
|
||||
} // namespace srt
|
||||
|
||||
|
||||
#endif
|
||||
|
|
932
trunk/3rdparty/srt-1-fit/srtcore/fec.cpp
vendored
932
trunk/3rdparty/srt-1-fit/srtcore/fec.cpp
vendored
File diff suppressed because it is too large
Load diff
53
trunk/3rdparty/srt-1-fit/srtcore/fec.h
vendored
53
trunk/3rdparty/srt-1-fit/srtcore/fec.h
vendored
|
@ -9,8 +9,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef INC__SRT_FEC_H
|
||||
#define INC__SRT_FEC_H
|
||||
#ifndef INC_SRT_FEC_H
|
||||
#define INC_SRT_FEC_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "packetfilter_api.h"
|
||||
|
||||
namespace srt {
|
||||
|
||||
class FECFilterBuiltin: public SrtPacketFilterBase
|
||||
{
|
||||
SrtFilterConfig cfg;
|
||||
|
@ -68,6 +70,12 @@ public:
|
|||
SINGLE // Horizontal-only with no recursion
|
||||
};
|
||||
|
||||
static Type FlipType(Type t)
|
||||
{
|
||||
SRT_ASSERT(t != SINGLE);
|
||||
return (t == HORIZ) ? VERT : HORIZ;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct RcvGroup: Group
|
||||
|
@ -183,21 +191,43 @@ private:
|
|||
|
||||
// Receiving
|
||||
void CheckLargeDrop(int32_t seqno);
|
||||
int ExtendRows(int rowx);
|
||||
int ExtendColumns(int colgx);
|
||||
void MarkCellReceived(int32_t seq);
|
||||
bool HangHorizontal(const CPacket& pkt, bool fec_ctl, loss_seqs_t& irrecover);
|
||||
bool HangVertical(const CPacket& pkt, signed char fec_colx, loss_seqs_t& irrecover);
|
||||
size_t ExtendRows(size_t rowx);
|
||||
size_t ExtendColumns(size_t colgx);
|
||||
|
||||
enum ECellReceived
|
||||
{
|
||||
CELL_RECEIVED, //< mark cell for a received packet (no matter current value)
|
||||
CELL_EXTEND, //< just make sure there's a place for a packet, set false if not
|
||||
CELL_REMOVE //< even if a packet was marked true, remove the cell existence confirmation
|
||||
};
|
||||
void MarkCellReceived(int32_t seq, ECellReceived recv = CELL_RECEIVED);
|
||||
|
||||
enum EHangStatus
|
||||
{
|
||||
HANG_NOTDONE,
|
||||
HANG_SUCCESS,
|
||||
HANG_PAST,
|
||||
HANG_CRAZY
|
||||
};
|
||||
|
||||
friend bool operator <(FECFilterBuiltin::EHangStatus a, FECFilterBuiltin::EHangStatus b)
|
||||
{
|
||||
return int(a) < int(b);
|
||||
}
|
||||
|
||||
EHangStatus HangHorizontal(const CPacket& pkt, bool fec_ctl, loss_seqs_t& irrecover);
|
||||
EHangStatus HangVertical(const CPacket& pkt, signed char fec_colx, loss_seqs_t& irrecover);
|
||||
void ClipControlPacket(Group& g, const CPacket& pkt);
|
||||
void ClipRebuiltPacket(Group& g, Receive::PrivPacket& pkt);
|
||||
void RcvRebuild(Group& g, int32_t seqno, Group::Type tp);
|
||||
int32_t RcvGetLossSeqHoriz(Group& g);
|
||||
int32_t RcvGetLossSeqVert(Group& g);
|
||||
void EmergencyShrink(size_t n_series);
|
||||
|
||||
static void TranslateLossRecords(const std::set<int32_t>& loss, loss_seqs_t& irrecover);
|
||||
void RcvCheckDismissColumn(int32_t seqno, int colgx, loss_seqs_t& irrecover);
|
||||
int RcvGetRowGroupIndex(int32_t seq);
|
||||
int RcvGetColumnGroupIndex(int32_t seq);
|
||||
int RcvGetRowGroupIndex(int32_t seq, EHangStatus& w_status);
|
||||
int RcvGetColumnGroupIndex(int32_t seqno, EHangStatus& w_status);
|
||||
void CollectIrrecoverRow(RcvGroup& g, loss_seqs_t& irrecover) const;
|
||||
bool IsLost(int32_t seq) const;
|
||||
|
||||
|
@ -243,6 +273,11 @@ public:
|
|||
static const size_t EXTRA_SIZE = 4;
|
||||
|
||||
virtual SRT_ARQLevel arqLevel() ATR_OVERRIDE { return m_fallback_level; }
|
||||
|
||||
static const char defaultConfig [];
|
||||
static bool verifyConfig(const SrtFilterConfig& config, std::string& w_errormsg);
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
37
trunk/3rdparty/srt-1-fit/srtcore/filelist.maf
vendored
37
trunk/3rdparty/srt-1-fit/srtcore/filelist.maf
vendored
|
@ -3,6 +3,7 @@
|
|||
SOURCES
|
||||
api.cpp
|
||||
buffer.cpp
|
||||
buffer_rcv.cpp
|
||||
cache.cpp
|
||||
channel.cpp
|
||||
common.cpp
|
||||
|
@ -12,27 +13,48 @@ epoll.cpp
|
|||
fec.cpp
|
||||
handshake.cpp
|
||||
list.cpp
|
||||
logger_default.cpp
|
||||
logger_defs.cpp
|
||||
md5.cpp
|
||||
packet.cpp
|
||||
packetfilter.cpp
|
||||
queue.cpp
|
||||
congctl.cpp
|
||||
socketconfig.cpp
|
||||
srt_c_api.cpp
|
||||
window.cpp
|
||||
srt_compat.c
|
||||
strerror_defs.cpp
|
||||
sync.cpp
|
||||
tsbpd_time.cpp
|
||||
window.cpp
|
||||
|
||||
SOURCES - ENABLE_BONDING
|
||||
group.cpp
|
||||
group_backup.cpp
|
||||
group_common.cpp
|
||||
|
||||
SOURCES - !ENABLE_STDCXX_SYNC
|
||||
sync_posix.cpp
|
||||
|
||||
SOURCES - ENABLE_STDCXX_SYNC
|
||||
sync_cxx11.cpp
|
||||
|
||||
SOURCES - EXTRA_WIN32_SHARED
|
||||
srt_shared.rc
|
||||
|
||||
PUBLIC HEADERS
|
||||
srt.h
|
||||
logging_api.h
|
||||
access_control.h
|
||||
|
||||
PROTECTED HEADERS
|
||||
platform_sys.h
|
||||
udt.h
|
||||
srt4udt.h
|
||||
|
||||
PRIVATE HEADERS
|
||||
api.h
|
||||
buffer.h
|
||||
buffer_rcv.h
|
||||
cache.h
|
||||
channel.h
|
||||
common.h
|
||||
|
@ -45,13 +67,18 @@ logging.h
|
|||
md5.h
|
||||
netinet_any.h
|
||||
packet.h
|
||||
sync.h
|
||||
queue.h
|
||||
congctl.h
|
||||
srt4udt.h
|
||||
socketconfig.h
|
||||
srt_compat.h
|
||||
stats.h
|
||||
threadname.h
|
||||
tsbpd_time.h
|
||||
utilities.h
|
||||
window.h
|
||||
|
||||
SOURCES WIN32 SHARED
|
||||
srt_shared.rc
|
||||
PRIVATE HEADERS - ENABLE_BONDING
|
||||
group.h
|
||||
group_backup.h
|
||||
group_common.h
|
||||
|
|
4717
trunk/3rdparty/srt-1-fit/srtcore/group.cpp
vendored
Normal file
4717
trunk/3rdparty/srt-1-fit/srtcore/group.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
822
trunk/3rdparty/srt-1-fit/srtcore/group.h
vendored
Normal file
822
trunk/3rdparty/srt-1-fit/srtcore/group.h
vendored
Normal file
|
@ -0,0 +1,822 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2020 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
Written by
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC_SRT_GROUP_H
|
||||
#define INC_SRT_GROUP_H
|
||||
|
||||
#include "srt.h"
|
||||
#include "common.h"
|
||||
#include "packet.h"
|
||||
#include "group_common.h"
|
||||
#include "group_backup.h"
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
const char* const srt_log_grp_state[] = {"PENDING", "IDLE", "RUNNING", "BROKEN"};
|
||||
#endif
|
||||
|
||||
|
||||
class CUDTGroup
|
||||
{
|
||||
friend class CUDTUnited;
|
||||
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
typedef sync::steady_clock::duration duration;
|
||||
typedef sync::steady_clock steady_clock;
|
||||
typedef groups::SocketData SocketData;
|
||||
typedef groups::SendBackupCtx SendBackupCtx;
|
||||
typedef groups::BackupMemberState BackupMemberState;
|
||||
|
||||
public:
|
||||
typedef SRT_MEMBERSTATUS GroupState;
|
||||
|
||||
// Note that the use of states may differ in particular group types:
|
||||
//
|
||||
// Broadcast: links that are freshly connected become PENDING and then IDLE only
|
||||
// for a short moment to be activated immediately at the nearest sending operation.
|
||||
//
|
||||
// Balancing: like with broadcast, just that the link activation gets its shared percentage
|
||||
// of traffic balancing
|
||||
//
|
||||
// Multicast: The link is never idle. The data are always sent over the UDP multicast link
|
||||
// and the receiver simply gets subscribed and reads packets once it's ready.
|
||||
//
|
||||
// Backup: The link stays idle until it's activated, and the activation can only happen
|
||||
// at the moment when the currently active link is "suspected of being likely broken"
|
||||
// (the current active link fails to receive ACK in a time when two ACKs should already
|
||||
// be received). After a while when the current active link is confirmed broken, it turns
|
||||
// into broken state.
|
||||
|
||||
static const char* StateStr(GroupState);
|
||||
|
||||
static int32_t s_tokenGen;
|
||||
static int32_t genToken() { ++s_tokenGen; if (s_tokenGen < 0) s_tokenGen = 0; return s_tokenGen;}
|
||||
|
||||
struct ConfigItem
|
||||
{
|
||||
SRT_SOCKOPT so;
|
||||
std::vector<unsigned char> value;
|
||||
|
||||
template <class T>
|
||||
bool get(T& refr)
|
||||
{
|
||||
if (sizeof(T) > value.size())
|
||||
return false;
|
||||
refr = *(T*)&value[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
ConfigItem(SRT_SOCKOPT o, const void* val, int size)
|
||||
: so(o)
|
||||
{
|
||||
value.resize(size);
|
||||
unsigned char* begin = (unsigned char*)val;
|
||||
std::copy(begin, begin + size, value.begin());
|
||||
}
|
||||
|
||||
struct OfType
|
||||
{
|
||||
SRT_SOCKOPT so;
|
||||
OfType(SRT_SOCKOPT soso)
|
||||
: so(soso)
|
||||
{
|
||||
}
|
||||
bool operator()(ConfigItem& ci) { return ci.so == so; }
|
||||
};
|
||||
};
|
||||
|
||||
typedef std::list<SocketData> group_t;
|
||||
typedef group_t::iterator gli_t;
|
||||
typedef std::vector< std::pair<SRTSOCKET, srt::CUDTSocket*> > sendable_t;
|
||||
|
||||
struct Sendstate
|
||||
{
|
||||
SRTSOCKET id;
|
||||
SocketData* mb;
|
||||
int stat;
|
||||
int code;
|
||||
};
|
||||
|
||||
CUDTGroup(SRT_GROUP_TYPE);
|
||||
~CUDTGroup();
|
||||
|
||||
SocketData* add(SocketData data);
|
||||
|
||||
struct HaveID
|
||||
{
|
||||
SRTSOCKET id;
|
||||
HaveID(SRTSOCKET sid)
|
||||
: id(sid)
|
||||
{
|
||||
}
|
||||
bool operator()(const SocketData& s) { return s.id == id; }
|
||||
};
|
||||
|
||||
bool contains(SRTSOCKET id, SocketData*& w_f)
|
||||
{
|
||||
srt::sync::ScopedLock g(m_GroupLock);
|
||||
gli_t f = std::find_if(m_Group.begin(), m_Group.end(), HaveID(id));
|
||||
if (f == m_Group.end())
|
||||
{
|
||||
w_f = NULL;
|
||||
return false;
|
||||
}
|
||||
w_f = &*f;
|
||||
return true;
|
||||
}
|
||||
|
||||
// NEED LOCKING
|
||||
gli_t begin() { return m_Group.begin(); }
|
||||
gli_t end() { return m_Group.end(); }
|
||||
|
||||
/// Remove the socket from the group container.
|
||||
/// REMEMBER: the group spec should be taken from the socket
|
||||
/// (set m_GroupOf and m_GroupMemberData to NULL
|
||||
/// PRIOR TO calling this function.
|
||||
/// @param id Socket ID to look for in the container to remove
|
||||
/// @return true if the container still contains any sockets after the operation
|
||||
bool remove(SRTSOCKET id)
|
||||
{
|
||||
using srt_logging::gmlog;
|
||||
srt::sync::ScopedLock g(m_GroupLock);
|
||||
|
||||
bool empty = false;
|
||||
HLOGC(gmlog.Debug, log << "group/remove: going to remove @" << id << " from $" << m_GroupID);
|
||||
|
||||
gli_t f = std::find_if(m_Group.begin(), m_Group.end(), HaveID(id));
|
||||
if (f != m_Group.end())
|
||||
{
|
||||
m_Group.erase(f);
|
||||
|
||||
// Reset sequence numbers on a dead group so that they are
|
||||
// initialized anew with the new alive connection within
|
||||
// the group.
|
||||
// XXX The problem is that this should be done after the
|
||||
// socket is considered DISCONNECTED, not when it's being
|
||||
// closed. After being disconnected, the sequence numbers
|
||||
// are no longer valid, and will be reinitialized when the
|
||||
// socket is connected again. This may stay as is for now
|
||||
// as in SRT it's not predicted to do anything with the socket
|
||||
// that was disconnected other than immediately closing it.
|
||||
if (m_Group.empty())
|
||||
{
|
||||
// When the group is empty, there's no danger that this
|
||||
// number will collide with any ISN provided by a socket.
|
||||
// Also since now every socket will derive this ISN.
|
||||
m_iLastSchedSeqNo = generateISN();
|
||||
resetInitialRxSequence();
|
||||
empty = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(gmlog.Debug, log << "group/remove: IPE: id @" << id << " NOT FOUND");
|
||||
empty = true; // not exactly true, but this is to cause error on group in the APP
|
||||
}
|
||||
|
||||
if (m_Group.empty())
|
||||
{
|
||||
m_bOpened = false;
|
||||
m_bConnected = false;
|
||||
}
|
||||
|
||||
// XXX BUGFIX
|
||||
m_Positions.erase(id);
|
||||
|
||||
return !empty;
|
||||
}
|
||||
|
||||
bool groupEmpty()
|
||||
{
|
||||
srt::sync::ScopedLock g(m_GroupLock);
|
||||
return m_Group.empty();
|
||||
}
|
||||
|
||||
void setGroupConnected();
|
||||
|
||||
int send(const char* buf, int len, SRT_MSGCTRL& w_mc);
|
||||
int sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc);
|
||||
int sendBackup(const char* buf, int len, SRT_MSGCTRL& w_mc);
|
||||
static int32_t generateISN();
|
||||
|
||||
private:
|
||||
// For Backup, sending all previous packet
|
||||
int sendBackupRexmit(srt::CUDT& core, SRT_MSGCTRL& w_mc);
|
||||
|
||||
// Support functions for sendBackup and sendBroadcast
|
||||
/// Check if group member is idle.
|
||||
/// @param d group member
|
||||
/// @param[in,out] w_wipeme array of sockets to remove from group
|
||||
/// @param[in,out] w_pendingLinks array of sockets pending for connection
|
||||
/// @returns true if d is idle (standby), false otherwise
|
||||
bool send_CheckIdle(const gli_t d, std::vector<SRTSOCKET>& w_wipeme, std::vector<SRTSOCKET>& w_pendingLinks);
|
||||
|
||||
|
||||
/// This function checks if the member has just become idle (check if sender buffer is empty) to send a KEEPALIVE immidiatelly.
|
||||
/// @todo Check it is some abandoned logic.
|
||||
void sendBackup_CheckIdleTime(gli_t w_d);
|
||||
|
||||
/// Qualify states of member links.
|
||||
/// [[using locked(this->m_GroupLock, m_pGlobal->m_GlobControlLock)]]
|
||||
/// @param[out] w_sendBackupCtx the context will be updated with state qualifications
|
||||
/// @param[in] currtime current timestamp
|
||||
void sendBackup_QualifyMemberStates(SendBackupCtx& w_sendBackupCtx, const steady_clock::time_point& currtime);
|
||||
|
||||
void sendBackup_AssignBackupState(srt::CUDT& socket, BackupMemberState state, const steady_clock::time_point& currtime);
|
||||
|
||||
/// Qualify the state of the active link: fresh, stable, unstable, wary.
|
||||
/// @retval active backup member state: fresh, stable, unstable, wary.
|
||||
BackupMemberState sendBackup_QualifyActiveState(const gli_t d, const time_point currtime);
|
||||
|
||||
BackupMemberState sendBackup_QualifyIfStandBy(const gli_t d);
|
||||
|
||||
/// Sends the same payload over all active members.
|
||||
/// @param[in] buf payload
|
||||
/// @param[in] len payload length in bytes
|
||||
/// @param[in,out] w_mc message control
|
||||
/// @param[in] currtime current time
|
||||
/// @param[in] currseq current packet sequence number
|
||||
/// @param[out] w_nsuccessful number of members with successfull sending.
|
||||
/// @param[in,out] maxActiveWeight
|
||||
/// @param[in,out] sendBackupCtx context
|
||||
/// @param[in,out] w_cx error
|
||||
/// @return group send result: -1 if sending over all members has failed; number of bytes sent overwise.
|
||||
int sendBackup_SendOverActive(const char* buf, int len, SRT_MSGCTRL& w_mc, const steady_clock::time_point& currtime, int32_t& w_curseq,
|
||||
size_t& w_nsuccessful, uint16_t& w_maxActiveWeight, SendBackupCtx& w_sendBackupCtx, CUDTException& w_cx);
|
||||
|
||||
/// Check link sending status
|
||||
/// @param[in] currtime Current time (logging only)
|
||||
/// @param[in] send_status Result of sending over the socket
|
||||
/// @param[in] lastseq Last sent sequence number before the current sending operation
|
||||
/// @param[in] pktseq Packet sequence number currently tried to be sent
|
||||
/// @param[out] w_u CUDT unit of the current member (to allow calling overrideSndSeqNo)
|
||||
/// @param[out] w_curseq Group's current sequence number (either -1 or the value used already for other links)
|
||||
/// @param[out] w_final_stat w_final_stat = send_status if sending succeded.
|
||||
///
|
||||
/// @returns true if the sending operation result (submitted in stat) is a success, false otherwise.
|
||||
bool sendBackup_CheckSendStatus(const time_point& currtime,
|
||||
const int send_status,
|
||||
const int32_t lastseq,
|
||||
const int32_t pktseq,
|
||||
CUDT& w_u,
|
||||
int32_t& w_curseq,
|
||||
int& w_final_stat);
|
||||
void sendBackup_Buffering(const char* buf, const int len, int32_t& curseq, SRT_MSGCTRL& w_mc);
|
||||
|
||||
size_t sendBackup_TryActivateStandbyIfNeeded(
|
||||
const char* buf,
|
||||
const int len,
|
||||
bool& w_none_succeeded,
|
||||
SRT_MSGCTRL& w_mc,
|
||||
int32_t& w_curseq,
|
||||
int32_t& w_final_stat,
|
||||
SendBackupCtx& w_sendBackupCtx,
|
||||
CUDTException& w_cx,
|
||||
const steady_clock::time_point& currtime);
|
||||
|
||||
/// Check if pending sockets are to be qualified as broken.
|
||||
/// This qualification later results in removing the socket from a group and closing it.
|
||||
/// @param[in,out] a context with a list of member sockets, some pending might qualified broken
|
||||
void sendBackup_CheckPendingSockets(SendBackupCtx& w_sendBackupCtx, const steady_clock::time_point& currtime);
|
||||
|
||||
/// Check if unstable sockets are to be qualified as broken.
|
||||
/// The main reason for such qualification is if a socket is unstable for too long.
|
||||
/// This qualification later results in removing the socket from a group and closing it.
|
||||
/// @param[in,out] a context with a list of member sockets, some pending might qualified broken
|
||||
void sendBackup_CheckUnstableSockets(SendBackupCtx& w_sendBackupCtx, const steady_clock::time_point& currtime);
|
||||
|
||||
/// @brief Marks broken sockets as closed. Used in broadcast sending.
|
||||
/// @param w_wipeme a list of sockets to close
|
||||
void send_CloseBrokenSockets(std::vector<SRTSOCKET>& w_wipeme);
|
||||
|
||||
/// @brief Marks broken sockets as closed. Used in backup sending.
|
||||
/// @param w_sendBackupCtx the context with a list of broken sockets
|
||||
void sendBackup_CloseBrokenSockets(SendBackupCtx& w_sendBackupCtx);
|
||||
|
||||
void sendBackup_RetryWaitBlocked(SendBackupCtx& w_sendBackupCtx,
|
||||
int& w_final_stat,
|
||||
bool& w_none_succeeded,
|
||||
SRT_MSGCTRL& w_mc,
|
||||
CUDTException& w_cx);
|
||||
void sendBackup_SilenceRedundantLinks(SendBackupCtx& w_sendBackupCtx, const steady_clock::time_point& currtime);
|
||||
|
||||
void send_CheckValidSockets();
|
||||
|
||||
public:
|
||||
int recv(char* buf, int len, SRT_MSGCTRL& w_mc);
|
||||
|
||||
void close();
|
||||
|
||||
void setOpt(SRT_SOCKOPT optname, const void* optval, int optlen);
|
||||
void getOpt(SRT_SOCKOPT optName, void* optval, int& w_optlen);
|
||||
void deriveSettings(srt::CUDT* source);
|
||||
bool applyFlags(uint32_t flags, HandshakeSide);
|
||||
|
||||
SRT_SOCKSTATUS getStatus();
|
||||
|
||||
void debugMasterData(SRTSOCKET slave);
|
||||
|
||||
bool isGroupReceiver()
|
||||
{
|
||||
// XXX add here also other group types, which
|
||||
// predict group receiving.
|
||||
return m_type == SRT_GTYPE_BROADCAST;
|
||||
}
|
||||
|
||||
sync::Mutex* exp_groupLock() { return &m_GroupLock; }
|
||||
void addEPoll(int eid);
|
||||
void removeEPollEvents(const int eid);
|
||||
void removeEPollID(const int eid);
|
||||
|
||||
/// @brief Update read-ready state.
|
||||
/// @param sock member socket ID (unused)
|
||||
/// @param sequence the latest packet sequence number available for reading.
|
||||
void updateReadState(SRTSOCKET sock, int32_t sequence);
|
||||
|
||||
void updateWriteState();
|
||||
void updateFailedLink();
|
||||
void activateUpdateEvent(bool still_have_items);
|
||||
int32_t getRcvBaseSeqNo();
|
||||
|
||||
/// Update the in-group array of packet providers per sequence number.
|
||||
/// Also basing on the information already provided by possibly other sockets,
|
||||
/// report the real status of packet loss, including packets maybe lost
|
||||
/// by the caller provider, but already received from elsewhere. Note that
|
||||
/// these packets are not ready for extraction until ACK-ed.
|
||||
///
|
||||
/// @param exp_sequence The previously received sequence at this socket
|
||||
/// @param sequence The sequence of this packet
|
||||
/// @param provider The core of the socket for which the packet was dispatched
|
||||
/// @param time TSBPD time of this packet
|
||||
/// @return The bitmap that marks by 'false' packets lost since next to exp_sequence
|
||||
std::vector<bool> providePacket(int32_t exp_sequence, int32_t sequence, srt::CUDT* provider, uint64_t time);
|
||||
|
||||
/// This is called from the ACK action by particular socket, which
|
||||
/// actually signs off the packet for extraction.
|
||||
///
|
||||
/// @param core The socket core for which the ACK was sent
|
||||
/// @param ack The past-the-last-received ACK sequence number
|
||||
void readyPackets(srt::CUDT* core, int32_t ack);
|
||||
|
||||
void syncWithSocket(const srt::CUDT& core, const HandshakeSide side);
|
||||
int getGroupData(SRT_SOCKGROUPDATA* pdata, size_t* psize);
|
||||
int getGroupData_LOCKED(SRT_SOCKGROUPDATA* pdata, size_t* psize);
|
||||
|
||||
/// Predicted to be called from the reading function to fill
|
||||
/// the group data array as requested.
|
||||
void fillGroupData(SRT_MSGCTRL& w_out, //< MSGCTRL to be written
|
||||
const SRT_MSGCTRL& in //< MSGCTRL read from the data-providing socket
|
||||
);
|
||||
|
||||
void copyGroupData(const CUDTGroup::SocketData& source, SRT_SOCKGROUPDATA& w_target);
|
||||
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
void debugGroup();
|
||||
#else
|
||||
void debugGroup() {}
|
||||
#endif
|
||||
|
||||
void ackMessage(int32_t msgno);
|
||||
void processKeepalive(SocketData*);
|
||||
void internalKeepalive(SocketData*);
|
||||
|
||||
private:
|
||||
// Check if there's at least one connected socket.
|
||||
// If so, grab the status of all member sockets.
|
||||
void getGroupCount(size_t& w_size, bool& w_still_alive);
|
||||
|
||||
srt::CUDTUnited& m_Global;
|
||||
srt::sync::Mutex m_GroupLock;
|
||||
|
||||
SRTSOCKET m_GroupID;
|
||||
SRTSOCKET m_PeerGroupID;
|
||||
struct GroupContainer
|
||||
{
|
||||
std::list<SocketData> m_List;
|
||||
|
||||
/// This field is used only by some types of groups that need
|
||||
/// to keep track as to which link was lately used. Note that
|
||||
/// by removal of a node from the m_List container, this link
|
||||
/// must be appropriately reset.
|
||||
gli_t m_LastActiveLink;
|
||||
|
||||
GroupContainer()
|
||||
: m_LastActiveLink(m_List.end())
|
||||
{
|
||||
}
|
||||
|
||||
// Property<gli_t> active = { m_LastActiveLink; }
|
||||
SRTU_PROPERTY_RW(gli_t, active, m_LastActiveLink);
|
||||
|
||||
gli_t begin() { return m_List.begin(); }
|
||||
gli_t end() { return m_List.end(); }
|
||||
bool empty() { return m_List.empty(); }
|
||||
void push_back(const SocketData& data) { m_List.push_back(data); }
|
||||
void clear()
|
||||
{
|
||||
m_LastActiveLink = end();
|
||||
m_List.clear();
|
||||
}
|
||||
size_t size() { return m_List.size(); }
|
||||
|
||||
void erase(gli_t it);
|
||||
};
|
||||
GroupContainer m_Group;
|
||||
const bool m_bSyncOnMsgNo; // It goes into a dedicated HS field. Could be true for balancing groups (not implemented).
|
||||
SRT_GROUP_TYPE m_type;
|
||||
CUDTSocket* m_listener; // A "group" can only have one listener.
|
||||
srt::sync::atomic<int> m_iBusy;
|
||||
CallbackHolder<srt_connect_callback_fn> m_cbConnectHook;
|
||||
void installConnectHook(srt_connect_callback_fn* hook, void* opaq)
|
||||
{
|
||||
m_cbConnectHook.set(opaq, hook);
|
||||
}
|
||||
|
||||
public:
|
||||
void apiAcquire() { ++m_iBusy; }
|
||||
void apiRelease() { --m_iBusy; }
|
||||
|
||||
// A normal cycle of the send/recv functions is the following:
|
||||
// - [Initial API call for a group]
|
||||
// - GroupKeeper - ctor
|
||||
// - LOCK: GlobControlLock
|
||||
// - Find the group ID in the group container (break if not found)
|
||||
// - LOCK: GroupLock of that group
|
||||
// - Set BUSY flag
|
||||
// - UNLOCK GroupLock
|
||||
// - UNLOCK GlobControlLock
|
||||
// - [Call the sending function (sendBroadcast/sendBackup)]
|
||||
// - LOCK GroupLock
|
||||
// - Preparation activities
|
||||
// - Loop over group members
|
||||
// - Send over a single socket
|
||||
// - Check send status and conditions
|
||||
// - Exit, if nothing else to be done
|
||||
// - Check links to send extra
|
||||
// - UNLOCK GroupLock
|
||||
// - Wait for first ready link
|
||||
// - LOCK GroupLock
|
||||
// - Check status and find sendable link
|
||||
// - Send over a single socket
|
||||
// - Check status and update data
|
||||
// - UNLOCK GroupLock, Exit
|
||||
// - GroupKeeper - dtor
|
||||
// - LOCK GroupLock
|
||||
// - Clear BUSY flag
|
||||
// - UNLOCK GroupLock
|
||||
// END.
|
||||
//
|
||||
// The possibility for isStillBusy to go on is only the following:
|
||||
// 1. Before calling the API function. As GlobControlLock is locked,
|
||||
// the nearest lock on GlobControlLock by GroupKeeper can happen:
|
||||
// - before the group is moved to ClosedGroups (this allows it to be found)
|
||||
// - after the group is moved to ClosedGroups (this makes the group not found)
|
||||
// - NOT after the group was deleted, as it could not be found and occupied.
|
||||
//
|
||||
// 2. Before release of GlobControlLock (acquired by GC), but before the
|
||||
// API function locks GroupLock:
|
||||
// - the GC call to isStillBusy locks GroupLock, but BUSY flag is already set
|
||||
// - GC then avoids deletion of the group
|
||||
//
|
||||
// 3. In any further place up to the exit of the API implementation function,
|
||||
// the BUSY flag is still set.
|
||||
//
|
||||
// 4. After exit of GroupKeeper destructor and unlock of GroupLock
|
||||
// - the group is no longer being accessed and can be freely deleted.
|
||||
// - the group also can no longer be found by ID.
|
||||
|
||||
bool isStillBusy()
|
||||
{
|
||||
sync::ScopedLock glk(m_GroupLock);
|
||||
return m_iBusy || !m_Group.empty();
|
||||
}
|
||||
|
||||
struct BufferedMessageStorage
|
||||
{
|
||||
size_t blocksize;
|
||||
size_t maxstorage;
|
||||
std::vector<char*> storage;
|
||||
|
||||
BufferedMessageStorage(size_t blk, size_t max = 0)
|
||||
: blocksize(blk)
|
||||
, maxstorage(max)
|
||||
, storage()
|
||||
{
|
||||
}
|
||||
|
||||
char* get()
|
||||
{
|
||||
if (storage.empty())
|
||||
return new char[blocksize];
|
||||
|
||||
// Get the element from the end
|
||||
char* block = storage.back();
|
||||
storage.pop_back();
|
||||
return block;
|
||||
}
|
||||
|
||||
void put(char* block)
|
||||
{
|
||||
if (storage.size() >= maxstorage)
|
||||
{
|
||||
// Simply delete
|
||||
delete[] block;
|
||||
return;
|
||||
}
|
||||
|
||||
// Put the block into the spare buffer
|
||||
storage.push_back(block);
|
||||
}
|
||||
|
||||
~BufferedMessageStorage()
|
||||
{
|
||||
for (size_t i = 0; i < storage.size(); ++i)
|
||||
delete[] storage[i];
|
||||
}
|
||||
};
|
||||
|
||||
struct BufferedMessage
|
||||
{
|
||||
static BufferedMessageStorage storage;
|
||||
|
||||
SRT_MSGCTRL mc;
|
||||
mutable char* data;
|
||||
size_t size;
|
||||
|
||||
BufferedMessage()
|
||||
: data()
|
||||
, size()
|
||||
{
|
||||
}
|
||||
~BufferedMessage()
|
||||
{
|
||||
if (data)
|
||||
storage.put(data);
|
||||
}
|
||||
|
||||
// NOTE: size 's' must be checked against SRT_LIVE_MAX_PLSIZE
|
||||
// before calling
|
||||
void copy(const char* buf, size_t s)
|
||||
{
|
||||
size = s;
|
||||
data = storage.get();
|
||||
memcpy(data, buf, s);
|
||||
}
|
||||
|
||||
BufferedMessage(const BufferedMessage& foreign)
|
||||
: mc(foreign.mc)
|
||||
, data(foreign.data)
|
||||
, size(foreign.size)
|
||||
{
|
||||
foreign.data = 0;
|
||||
}
|
||||
|
||||
BufferedMessage& operator=(const BufferedMessage& foreign)
|
||||
{
|
||||
data = foreign.data;
|
||||
size = foreign.size;
|
||||
mc = foreign.mc;
|
||||
|
||||
foreign.data = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
void swap_with(BufferedMessage& b)
|
||||
{
|
||||
std::swap(this->mc, b.mc);
|
||||
std::swap(this->data, b.data);
|
||||
std::swap(this->size, b.size);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::deque<BufferedMessage> senderBuffer_t;
|
||||
// typedef StaticBuffer<BufferedMessage, 1000> senderBuffer_t;
|
||||
|
||||
private:
|
||||
// Fields required for SRT_GTYPE_BACKUP groups.
|
||||
senderBuffer_t m_SenderBuffer;
|
||||
int32_t m_iSndOldestMsgNo; // oldest position in the sender buffer
|
||||
sync::atomic<int32_t> m_iSndAckedMsgNo;
|
||||
uint32_t m_uOPT_MinStabilityTimeout_us;
|
||||
|
||||
// THIS function must be called only in a function for a group type
|
||||
// that does use sender buffer.
|
||||
int32_t addMessageToBuffer(const char* buf, size_t len, SRT_MSGCTRL& w_mc);
|
||||
|
||||
std::set<int> m_sPollID; // set of epoll ID to trigger
|
||||
int m_iMaxPayloadSize;
|
||||
int m_iAvgPayloadSize;
|
||||
bool m_bSynRecving;
|
||||
bool m_bSynSending;
|
||||
bool m_bTsbPd;
|
||||
bool m_bTLPktDrop;
|
||||
int64_t m_iTsbPdDelay_us;
|
||||
int m_RcvEID;
|
||||
class CEPollDesc* m_RcvEpolld;
|
||||
int m_SndEID;
|
||||
class CEPollDesc* m_SndEpolld;
|
||||
|
||||
int m_iSndTimeOut; // sending timeout in milliseconds
|
||||
int m_iRcvTimeOut; // receiving timeout in milliseconds
|
||||
|
||||
// Start times for TsbPd. These times shall be synchronized
|
||||
// between all sockets in the group. The first connected one
|
||||
// defines it, others shall derive it. The value 0 decides if
|
||||
// this has been already set.
|
||||
time_point m_tsStartTime;
|
||||
time_point m_tsRcvPeerStartTime;
|
||||
|
||||
struct ReadPos
|
||||
{
|
||||
std::vector<char> packet;
|
||||
SRT_MSGCTRL mctrl;
|
||||
ReadPos(int32_t s)
|
||||
: mctrl(srt_msgctrl_default)
|
||||
{
|
||||
mctrl.pktseq = s;
|
||||
}
|
||||
};
|
||||
std::map<SRTSOCKET, ReadPos> m_Positions;
|
||||
|
||||
ReadPos* checkPacketAhead();
|
||||
|
||||
void recv_CollectAliveAndBroken(std::vector<srt::CUDTSocket*>& w_alive, std::set<srt::CUDTSocket*>& w_broken);
|
||||
|
||||
/// The function polls alive member sockets and retrieves a list of read-ready.
|
||||
/// [acquires lock for CUDT::uglobal()->m_GlobControlLock]
|
||||
/// [[using locked(m_GroupLock)]] temporally unlocks-locks internally
|
||||
///
|
||||
/// @returns list of read-ready sockets
|
||||
/// @throws CUDTException(MJ_CONNECTION, MN_NOCONN, 0)
|
||||
/// @throws CUDTException(MJ_AGAIN, MN_RDAVAIL, 0)
|
||||
std::vector<srt::CUDTSocket*> recv_WaitForReadReady(const std::vector<srt::CUDTSocket*>& aliveMembers, std::set<srt::CUDTSocket*>& w_broken);
|
||||
|
||||
// This is the sequence number of a packet that has been previously
|
||||
// delivered. Initially it should be set to SRT_SEQNO_NONE so that the sequence read
|
||||
// from the first delivering socket will be taken as a good deal.
|
||||
sync::atomic<int32_t> m_RcvBaseSeqNo;
|
||||
|
||||
bool m_bOpened; // Set to true when at least one link is at least pending
|
||||
bool m_bConnected; // Set to true on first link confirmed connected
|
||||
bool m_bClosing;
|
||||
|
||||
// There's no simple way of transforming config
|
||||
// items that are predicted to be used on socket.
|
||||
// Use some options for yourself, store the others
|
||||
// for setting later on a socket.
|
||||
std::vector<ConfigItem> m_config;
|
||||
|
||||
// Signal for the blocking user thread that the packet
|
||||
// is ready to deliver.
|
||||
sync::Condition m_RcvDataCond;
|
||||
sync::Mutex m_RcvDataLock;
|
||||
sync::atomic<int32_t> m_iLastSchedSeqNo; // represetnts the value of CUDT::m_iSndNextSeqNo for each running socket
|
||||
sync::atomic<int32_t> m_iLastSchedMsgNo;
|
||||
// Statistics
|
||||
|
||||
struct Stats
|
||||
{
|
||||
// Stats state
|
||||
time_point tsActivateTime; // Time when this group sent or received the first data packet
|
||||
time_point tsLastSampleTime; // Time reset when clearing stats
|
||||
|
||||
stats::Metric<stats::BytesPackets> sent; // number of packets sent from the application
|
||||
stats::Metric<stats::BytesPackets> recv; // number of packets delivered from the group to the application
|
||||
stats::Metric<stats::BytesPackets> recvDrop; // number of packets dropped by the group receiver (not received from any member)
|
||||
stats::Metric<stats::BytesPackets> recvDiscard; // number of packets discarded as already delivered
|
||||
|
||||
void init()
|
||||
{
|
||||
tsActivateTime = srt::sync::steady_clock::time_point();
|
||||
tsLastSampleTime = srt::sync::steady_clock::now();
|
||||
sent.reset();
|
||||
recv.reset();
|
||||
recvDrop.reset();
|
||||
recvDiscard.reset();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
tsLastSampleTime = srt::sync::steady_clock::now();
|
||||
|
||||
sent.resetTrace();
|
||||
recv.resetTrace();
|
||||
recvDrop.resetTrace();
|
||||
recvDiscard.resetTrace();
|
||||
}
|
||||
} m_stats;
|
||||
|
||||
void updateAvgPayloadSize(int size)
|
||||
{
|
||||
if (m_iAvgPayloadSize == -1)
|
||||
m_iAvgPayloadSize = size;
|
||||
else
|
||||
m_iAvgPayloadSize = avg_iir<4>(m_iAvgPayloadSize, size);
|
||||
}
|
||||
|
||||
int avgRcvPacketSize()
|
||||
{
|
||||
// In case when no packet has been received yet, but already notified
|
||||
// a dropped packet, its size will be SRT_LIVE_DEF_PLSIZE. It will be
|
||||
// the value most matching in the typical uses, although no matter what
|
||||
// value would be used here, each one would be wrong from some points
|
||||
// of view. This one is simply the best choice for typical uses of groups
|
||||
// provided that they are to be ued only for live mode.
|
||||
return m_iAvgPayloadSize == -1 ? SRT_LIVE_DEF_PLSIZE : m_iAvgPayloadSize;
|
||||
}
|
||||
|
||||
public:
|
||||
void bstatsSocket(CBytePerfMon* perf, bool clear);
|
||||
|
||||
// Required after the call on newGroup on the listener side.
|
||||
// On the listener side the group is lazily created just before
|
||||
// accepting a new socket and therefore always open.
|
||||
void setOpen() { m_bOpened = true; }
|
||||
|
||||
std::string CONID() const
|
||||
{
|
||||
#if ENABLE_LOGGING
|
||||
std::ostringstream os;
|
||||
os << "@" << m_GroupID << ":";
|
||||
return os.str();
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
void resetInitialRxSequence()
|
||||
{
|
||||
// The app-reader doesn't care about the real sequence number.
|
||||
// The first provided one will be taken as a good deal; even if
|
||||
// this is going to be past the ISN, at worst it will be caused
|
||||
// by TLPKTDROP.
|
||||
m_RcvBaseSeqNo = SRT_SEQNO_NONE;
|
||||
}
|
||||
|
||||
bool applyGroupTime(time_point& w_start_time, time_point& w_peer_start_time)
|
||||
{
|
||||
using srt::sync::is_zero;
|
||||
using srt_logging::gmlog;
|
||||
|
||||
if (is_zero(m_tsStartTime))
|
||||
{
|
||||
// The first socket, defines the group time for the whole group.
|
||||
m_tsStartTime = w_start_time;
|
||||
m_tsRcvPeerStartTime = w_peer_start_time;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sanity check. This should never happen, fix the bug if found!
|
||||
if (is_zero(m_tsRcvPeerStartTime))
|
||||
{
|
||||
LOGC(gmlog.Error, log << "IPE: only StartTime is set, RcvPeerStartTime still 0!");
|
||||
// Kinda fallback, but that's not too safe.
|
||||
m_tsRcvPeerStartTime = w_peer_start_time;
|
||||
}
|
||||
|
||||
// The redundant connection, derive the times
|
||||
w_start_time = m_tsStartTime;
|
||||
w_peer_start_time = m_tsRcvPeerStartTime;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Live state synchronization
|
||||
bool getBufferTimeBase(srt::CUDT* forthesakeof, time_point& w_tb, bool& w_wp, duration& w_dr);
|
||||
bool applyGroupSequences(SRTSOCKET, int32_t& w_snd_isn, int32_t& w_rcv_isn);
|
||||
|
||||
/// @brief Synchronize TSBPD base time and clock drift among members using the @a srcMember as a reference.
|
||||
/// @param srcMember a reference for synchronization.
|
||||
void synchronizeDrift(const srt::CUDT* srcMember);
|
||||
|
||||
void updateLatestRcv(srt::CUDTSocket*);
|
||||
|
||||
// Property accessors
|
||||
SRTU_PROPERTY_RW_CHAIN(CUDTGroup, SRTSOCKET, id, m_GroupID);
|
||||
SRTU_PROPERTY_RW_CHAIN(CUDTGroup, SRTSOCKET, peerid, m_PeerGroupID);
|
||||
SRTU_PROPERTY_RW_CHAIN(CUDTGroup, SRT_GROUP_TYPE, type, m_type);
|
||||
SRTU_PROPERTY_RW_CHAIN(CUDTGroup, int32_t, currentSchedSequence, m_iLastSchedSeqNo);
|
||||
SRTU_PROPERTY_RRW(std::set<int>&, epollset, m_sPollID);
|
||||
SRTU_PROPERTY_RW_CHAIN(CUDTGroup, int64_t, latency, m_iTsbPdDelay_us);
|
||||
SRTU_PROPERTY_RO(bool, synconmsgno, m_bSyncOnMsgNo);
|
||||
SRTU_PROPERTY_RO(bool, closing, m_bClosing);
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif // INC_SRT_GROUP_H
|
159
trunk/3rdparty/srt-1-fit/srtcore/group_backup.cpp
vendored
Normal file
159
trunk/3rdparty/srt-1-fit/srtcore/group_backup.cpp
vendored
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2021 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
Written by
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "platform_sys.h"
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "group_backup.h"
|
||||
|
||||
|
||||
namespace srt
|
||||
{
|
||||
namespace groups
|
||||
{
|
||||
|
||||
using namespace std;
|
||||
using namespace srt_logging;
|
||||
|
||||
const char* stateToStr(BackupMemberState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case srt::groups::BKUPST_UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
case srt::groups::BKUPST_PENDING:
|
||||
return "PENDING";
|
||||
case srt::groups::BKUPST_STANDBY:
|
||||
return "STANDBY";
|
||||
case srt::groups::BKUPST_ACTIVE_FRESH:
|
||||
return "ACTIVE_FRESH";
|
||||
case srt::groups::BKUPST_ACTIVE_STABLE:
|
||||
return "ACTIVE_STABLE";
|
||||
case srt::groups::BKUPST_ACTIVE_UNSTABLE:
|
||||
return "ACTIVE_UNSTABLE";
|
||||
case srt::groups::BKUPST_ACTIVE_UNSTABLE_WARY:
|
||||
return "ACTIVE_UNSTABLE_WARY";
|
||||
case srt::groups::BKUPST_BROKEN:
|
||||
return "BROKEN";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "WRONG_STATE";
|
||||
}
|
||||
|
||||
/// @brief Compares group members by their weight (higher weight comes first), then state.
|
||||
/// Higher weight comes first, same weight: stable, then fresh active.
|
||||
struct FCompareByWeight
|
||||
{
|
||||
/// @returns true if the first argument is less than (i.e. is ordered before) the second.
|
||||
bool operator()(const BackupMemberStateEntry& a, const BackupMemberStateEntry& b)
|
||||
{
|
||||
if (a.pSocketData != NULL && b.pSocketData != NULL
|
||||
&& (a.pSocketData->weight != b.pSocketData->weight))
|
||||
return a.pSocketData->weight > b.pSocketData->weight;
|
||||
|
||||
if (a.state != b.state)
|
||||
{
|
||||
SRT_STATIC_ASSERT(BKUPST_ACTIVE_STABLE > BKUPST_ACTIVE_FRESH, "Wrong ordering");
|
||||
return a.state > b.state;
|
||||
}
|
||||
|
||||
// the order does not matter, but comparator must return a different value for not equal a and b
|
||||
return a.socketID < b.socketID;
|
||||
}
|
||||
};
|
||||
|
||||
void SendBackupCtx::recordMemberState(SocketData* pSockData, BackupMemberState st)
|
||||
{
|
||||
m_memberStates.push_back(BackupMemberStateEntry(pSockData, st));
|
||||
++m_stateCounter[st];
|
||||
|
||||
if (st == BKUPST_STANDBY)
|
||||
{
|
||||
m_standbyMaxWeight = max(m_standbyMaxWeight, pSockData->weight);
|
||||
}
|
||||
else if (isStateActive(st))
|
||||
{
|
||||
m_activeMaxWeight = max(m_activeMaxWeight, pSockData->weight);
|
||||
}
|
||||
}
|
||||
|
||||
void SendBackupCtx::updateMemberState(const SocketData* pSockData, BackupMemberState st)
|
||||
{
|
||||
typedef vector<BackupMemberStateEntry>::iterator iter_t;
|
||||
for (iter_t i = m_memberStates.begin(); i != m_memberStates.end(); ++i)
|
||||
{
|
||||
if (i->pSocketData == NULL)
|
||||
continue;
|
||||
|
||||
if (i->pSocketData != pSockData)
|
||||
continue;
|
||||
|
||||
if (i->state == st)
|
||||
return;
|
||||
|
||||
--m_stateCounter[i->state];
|
||||
++m_stateCounter[st];
|
||||
i->state = st;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
LOGC(gslog.Error,
|
||||
log << "IPE: SendBackupCtx::updateMemberState failed to locate member");
|
||||
}
|
||||
|
||||
void SendBackupCtx::sortByWeightAndState()
|
||||
{
|
||||
sort(m_memberStates.begin(), m_memberStates.end(), FCompareByWeight());
|
||||
}
|
||||
|
||||
BackupMemberState SendBackupCtx::getMemberState(const SocketData* pSockData) const
|
||||
{
|
||||
typedef vector<BackupMemberStateEntry>::const_iterator const_iter_t;
|
||||
for (const_iter_t i = m_memberStates.begin(); i != m_memberStates.end(); ++i)
|
||||
{
|
||||
if (i->pSocketData != pSockData)
|
||||
continue;
|
||||
|
||||
return i->state;
|
||||
}
|
||||
|
||||
// The entry was not found
|
||||
// TODO: Maybe throw an exception here?
|
||||
return BKUPST_UNKNOWN;
|
||||
}
|
||||
|
||||
unsigned SendBackupCtx::countMembersByState(BackupMemberState st) const
|
||||
{
|
||||
return m_stateCounter[st];
|
||||
}
|
||||
|
||||
std::string SendBackupCtx::printMembers() const
|
||||
{
|
||||
stringstream ss;
|
||||
typedef vector<BackupMemberStateEntry>::const_iterator const_iter_t;
|
||||
for (const_iter_t i = m_memberStates.begin(); i != m_memberStates.end(); ++i)
|
||||
{
|
||||
ss << "@" << i->socketID << " w " << i->pSocketData->weight << " state " << stateToStr(i->state) << ", ";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace groups
|
||||
} // namespace srt
|
128
trunk/3rdparty/srt-1-fit/srtcore/group_backup.h
vendored
Normal file
128
trunk/3rdparty/srt-1-fit/srtcore/group_backup.h
vendored
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2021 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
Written by
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC_SRT_GROUP_BACKUP_H
|
||||
#define INC_SRT_GROUP_BACKUP_H
|
||||
|
||||
#include "srt.h"
|
||||
#include "common.h"
|
||||
#include "group_common.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace srt
|
||||
{
|
||||
namespace groups
|
||||
{
|
||||
enum BackupMemberState
|
||||
{
|
||||
BKUPST_UNKNOWN = -1,
|
||||
|
||||
BKUPST_PENDING = 0,
|
||||
BKUPST_STANDBY = 1,
|
||||
BKUPST_BROKEN = 2,
|
||||
|
||||
BKUPST_ACTIVE_UNSTABLE = 3,
|
||||
BKUPST_ACTIVE_UNSTABLE_WARY = 4,
|
||||
BKUPST_ACTIVE_FRESH = 5,
|
||||
BKUPST_ACTIVE_STABLE = 6,
|
||||
|
||||
BKUPST_E_SIZE = 7
|
||||
};
|
||||
|
||||
const char* stateToStr(BackupMemberState state);
|
||||
|
||||
inline bool isStateActive(BackupMemberState state)
|
||||
{
|
||||
if (state == BKUPST_ACTIVE_FRESH
|
||||
|| state == BKUPST_ACTIVE_STABLE
|
||||
|| state == BKUPST_ACTIVE_UNSTABLE
|
||||
|| state == BKUPST_ACTIVE_UNSTABLE_WARY)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct BackupMemberStateEntry
|
||||
{
|
||||
BackupMemberStateEntry(SocketData* psock, BackupMemberState st)
|
||||
: pSocketData(psock)
|
||||
, socketID(psock->id)
|
||||
, state(st)
|
||||
{}
|
||||
|
||||
SocketData* pSocketData; // accessing pSocketDataIt requires m_GroupLock
|
||||
SRTSOCKET socketID; // therefore socketID is saved separately (needed to close broken sockets)
|
||||
BackupMemberState state;
|
||||
};
|
||||
|
||||
/// @brief A context needed for main/backup sending function.
|
||||
/// @todo Using gli_t here does not allow to safely store the context outside of the sendBackup calls.
|
||||
class SendBackupCtx
|
||||
{
|
||||
public:
|
||||
SendBackupCtx()
|
||||
: m_stateCounter() // default init with zeros
|
||||
, m_activeMaxWeight()
|
||||
, m_standbyMaxWeight()
|
||||
{
|
||||
}
|
||||
|
||||
/// @brief Adds or updates a record of the member socket state.
|
||||
/// @param pSocketDataIt Iterator to a socket
|
||||
/// @param st State of the memmber socket
|
||||
/// @todo Implement updating member state
|
||||
void recordMemberState(SocketData* pSocketDataIt, BackupMemberState st);
|
||||
|
||||
/// @brief Updates a record of the member socket state.
|
||||
/// @param pSocketDataIt Iterator to a socket
|
||||
/// @param st State of the memmber socket
|
||||
/// @todo To be replaced by recordMemberState
|
||||
/// @todo Update max weights?
|
||||
void updateMemberState(const SocketData* pSocketDataIt, BackupMemberState st);
|
||||
|
||||
/// @brief sorts members in order
|
||||
/// Higher weight comes first, same weight: stable first, then fresh active.
|
||||
void sortByWeightAndState();
|
||||
|
||||
BackupMemberState getMemberState(const SocketData* pSocketDataIt) const;
|
||||
|
||||
unsigned countMembersByState(BackupMemberState st) const;
|
||||
|
||||
const std::vector<BackupMemberStateEntry>& memberStates() const { return m_memberStates; }
|
||||
|
||||
uint16_t maxStandbyWeight() const { return m_standbyMaxWeight; }
|
||||
uint16_t maxActiveWeight() const { return m_activeMaxWeight; }
|
||||
|
||||
std::string printMembers() const;
|
||||
|
||||
void setRateEstimate(const CRateEstimator& rate) { m_rateEstimate = rate; }
|
||||
|
||||
const CRateEstimator& getRateEstimate() const { return m_rateEstimate; }
|
||||
|
||||
private:
|
||||
std::vector<BackupMemberStateEntry> m_memberStates; // TODO: consider std::map here?
|
||||
unsigned m_stateCounter[BKUPST_E_SIZE];
|
||||
uint16_t m_activeMaxWeight;
|
||||
uint16_t m_standbyMaxWeight;
|
||||
CRateEstimator m_rateEstimate; // The rate estimator state of the active link to copy to a backup on activation.
|
||||
};
|
||||
|
||||
} // namespace groups
|
||||
} // namespace srt
|
||||
|
||||
#endif // INC_SRT_GROUP_BACKUP_H
|
63
trunk/3rdparty/srt-1-fit/srtcore/group_common.cpp
vendored
Normal file
63
trunk/3rdparty/srt-1-fit/srtcore/group_common.cpp
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2021 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
Written by
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include "group_common.h"
|
||||
#include "api.h"
|
||||
|
||||
namespace srt
|
||||
{
|
||||
namespace groups
|
||||
{
|
||||
|
||||
SocketData prepareSocketData(CUDTSocket* s)
|
||||
{
|
||||
// This uses default SRT_GST_BROKEN because when the group operation is done,
|
||||
// then the SRT_GST_IDLE state automatically turns into SRT_GST_RUNNING. This is
|
||||
// recognized as an initial state of the fresh added socket to the group,
|
||||
// so some "initial configuration" must be done on it, after which it's
|
||||
// turned into SRT_GST_RUNNING, that is, it's treated as all others. When
|
||||
// set to SRT_GST_BROKEN, this socket is disregarded. This socket isn't cleaned
|
||||
// up, however, unless the status is simultaneously SRTS_BROKEN.
|
||||
|
||||
// The order of operations is then:
|
||||
// - add the socket to the group in this "broken" initial state
|
||||
// - connect the socket (or get it extracted from accept)
|
||||
// - update the socket state (should be SRTS_CONNECTED)
|
||||
// - once the connection is established (may take time with connect), set SRT_GST_IDLE
|
||||
// - the next operation of send/recv will automatically turn it into SRT_GST_RUNNING
|
||||
SocketData sd = {
|
||||
s->m_SocketID,
|
||||
s,
|
||||
-1,
|
||||
SRTS_INIT,
|
||||
SRT_GST_BROKEN,
|
||||
SRT_GST_BROKEN,
|
||||
-1,
|
||||
-1,
|
||||
sockaddr_any(),
|
||||
sockaddr_any(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0, // weight
|
||||
0 // pktSndDropTotal
|
||||
};
|
||||
return sd;
|
||||
}
|
||||
|
||||
} // namespace groups
|
||||
} // namespace srt
|
62
trunk/3rdparty/srt-1-fit/srtcore/group_common.h
vendored
Normal file
62
trunk/3rdparty/srt-1-fit/srtcore/group_common.h
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2021 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
Written by
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC_SRT_GROUP_COMMON_H
|
||||
#define INC_SRT_GROUP_COMMON_H
|
||||
|
||||
#include "srt.h"
|
||||
#include "common.h"
|
||||
#include "core.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace srt
|
||||
{
|
||||
namespace groups
|
||||
{
|
||||
typedef SRT_MEMBERSTATUS GroupState;
|
||||
|
||||
struct SocketData
|
||||
{
|
||||
SRTSOCKET id; // same as ps->m_SocketID
|
||||
CUDTSocket* ps;
|
||||
int token;
|
||||
SRT_SOCKSTATUS laststatus;
|
||||
GroupState sndstate;
|
||||
GroupState rcvstate;
|
||||
int sndresult;
|
||||
int rcvresult;
|
||||
sockaddr_any agent;
|
||||
sockaddr_any peer;
|
||||
bool ready_read;
|
||||
bool ready_write;
|
||||
bool ready_error;
|
||||
|
||||
// Configuration
|
||||
uint16_t weight;
|
||||
|
||||
// Stats
|
||||
int64_t pktSndDropTotal;
|
||||
};
|
||||
|
||||
SocketData prepareSocketData(CUDTSocket* s);
|
||||
|
||||
typedef std::list<SocketData> group_t;
|
||||
typedef group_t::iterator gli_t;
|
||||
|
||||
} // namespace groups
|
||||
} // namespace srt
|
||||
|
||||
#endif // INC_SRT_GROUP_COMMON_H
|
125
trunk/3rdparty/srt-1-fit/srtcore/handshake.cpp
vendored
125
trunk/3rdparty/srt-1-fit/srtcore/handshake.cpp
vendored
|
@ -43,6 +43,8 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
@ -50,32 +52,33 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <algorithm>
|
||||
|
||||
#include "udt.h"
|
||||
#include "api.h"
|
||||
#include "core.h"
|
||||
#include "handshake.h"
|
||||
#include "utilities.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace srt;
|
||||
|
||||
|
||||
CHandShake::CHandShake():
|
||||
m_iVersion(0),
|
||||
m_iType(0), // Universal: UDT_UNDEFINED or no flags
|
||||
m_iISN(0),
|
||||
m_iMSS(0),
|
||||
m_iFlightFlagSize(0),
|
||||
m_iReqType(URQ_WAVEAHAND),
|
||||
m_iID(0),
|
||||
m_iCookie(0),
|
||||
m_extension(false)
|
||||
srt::CHandShake::CHandShake()
|
||||
: m_iVersion(0)
|
||||
, m_iType(0) // Universal: UDT_UNDEFINED or no flags
|
||||
, m_iISN(0)
|
||||
, m_iMSS(0)
|
||||
, m_iFlightFlagSize(0)
|
||||
, m_iReqType(URQ_WAVEAHAND)
|
||||
, m_iID(0)
|
||||
, m_iCookie(0)
|
||||
, m_extension(false)
|
||||
{
|
||||
for (int i = 0; i < 4; ++ i)
|
||||
m_piPeerIP[i] = 0;
|
||||
}
|
||||
|
||||
int CHandShake::store_to(char* buf, ref_t<size_t> r_size)
|
||||
int srt::CHandShake::store_to(char* buf, size_t& w_size)
|
||||
{
|
||||
size_t& size = *r_size;
|
||||
if (size < m_iContentSize)
|
||||
if (w_size < m_iContentSize)
|
||||
return -1;
|
||||
|
||||
int32_t* p = reinterpret_cast<int32_t*>(buf);
|
||||
|
@ -90,12 +93,12 @@ int CHandShake::store_to(char* buf, ref_t<size_t> r_size)
|
|||
for (int i = 0; i < 4; ++ i)
|
||||
*p++ = m_piPeerIP[i];
|
||||
|
||||
size = m_iContentSize;
|
||||
w_size = m_iContentSize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CHandShake::load_from(const char* buf, size_t size)
|
||||
int srt::CHandShake::load_from(const char* buf, size_t size)
|
||||
{
|
||||
if (size < m_iContentSize)
|
||||
return -1;
|
||||
|
@ -118,6 +121,8 @@ int CHandShake::load_from(const char* buf, size_t size)
|
|||
|
||||
#ifdef ENABLE_LOGGING
|
||||
|
||||
namespace srt
|
||||
{
|
||||
const char* srt_rejectreason_name [] = {
|
||||
"UNKNOWN",
|
||||
"SYSTEM",
|
||||
|
@ -134,15 +139,31 @@ const char* srt_rejectreason_name [] = {
|
|||
"MESSAGEAPI",
|
||||
"CONGESTION",
|
||||
"FILTER",
|
||||
"GROUP",
|
||||
"TIMEOUT"
|
||||
};
|
||||
}
|
||||
|
||||
std::string RequestTypeStr(UDTRequestType rq)
|
||||
std::string srt::RequestTypeStr(UDTRequestType rq)
|
||||
{
|
||||
if (rq >= URQ_FAILURE_TYPES)
|
||||
{
|
||||
SRT_REJECT_REASON rej = RejectReasonForURQ(rq);
|
||||
int id = rej;
|
||||
return std::string("ERROR:") + srt_rejectreason_name[id];
|
||||
std::ostringstream rt;
|
||||
rt << "ERROR:";
|
||||
int id = RejectReasonForURQ(rq);
|
||||
if (id < (int) Size(srt_rejectreason_name))
|
||||
rt << srt_rejectreason_name[id];
|
||||
else if (id < SRT_REJC_USERDEFINED)
|
||||
{
|
||||
if (id < SRT_REJC_PREDEFINED)
|
||||
rt << "UNKNOWN:" << id;
|
||||
else
|
||||
rt << "PREDEFINED:" << (id - SRT_REJC_PREDEFINED);
|
||||
}
|
||||
else
|
||||
rt << "USERDEFINED:" << (id - SRT_REJC_USERDEFINED);
|
||||
|
||||
return rt.str();
|
||||
}
|
||||
|
||||
switch ( rq )
|
||||
|
@ -156,7 +177,7 @@ std::string RequestTypeStr(UDTRequestType rq)
|
|||
}
|
||||
}
|
||||
|
||||
string CHandShake::RdvStateStr(CHandShake::RendezvousState s)
|
||||
string srt::CHandShake::RdvStateStr(CHandShake::RendezvousState s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
|
@ -172,11 +193,22 @@ string CHandShake::RdvStateStr(CHandShake::RendezvousState s)
|
|||
}
|
||||
#endif
|
||||
|
||||
string CHandShake::show()
|
||||
bool srt::CHandShake::valid()
|
||||
{
|
||||
if (m_iVersion < CUDT::HS_VERSION_UDT4
|
||||
|| m_iISN < 0 || m_iISN >= CSeqNo::m_iMaxSeqNo
|
||||
|| m_iMSS < 32
|
||||
|| m_iFlightFlagSize < 2)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string srt::CHandShake::show()
|
||||
{
|
||||
ostringstream so;
|
||||
|
||||
so << "version=" << m_iVersion << " type=" << hex << m_iType << dec
|
||||
so << "version=" << m_iVersion << " type=0x" << hex << m_iType << dec
|
||||
<< " ISN=" << m_iISN << " MSS=" << m_iMSS << " FLW=" << m_iFlightFlagSize
|
||||
<< " reqtype=" << RequestTypeStr(m_iReqType) << " srcID=" << m_iID
|
||||
<< " cookie=" << hex << m_iCookie << dec
|
||||
|
@ -191,9 +223,12 @@ string CHandShake::show()
|
|||
// CHandShake, not CUDT.
|
||||
if ( m_iVersion > CUDT::HS_VERSION_UDT4 )
|
||||
{
|
||||
so << "EXT: ";
|
||||
if (m_iType == 0) // no flags at all
|
||||
so << "none";
|
||||
const int flags = SrtHSRequest::SRT_HSTYPE_HSFLAGS::unwrap(m_iType);
|
||||
so << "FLAGS: ";
|
||||
if (flags == SrtHSRequest::SRT_MAGIC_CODE)
|
||||
so << "MAGIC";
|
||||
else if (m_iType == 0)
|
||||
so << "NONE"; // no flags and no advertised pbkeylen
|
||||
else
|
||||
so << ExtensionFlagStr(m_iType);
|
||||
}
|
||||
|
@ -201,7 +236,7 @@ string CHandShake::show()
|
|||
return so.str();
|
||||
}
|
||||
|
||||
string CHandShake::ExtensionFlagStr(int32_t fl)
|
||||
string srt::CHandShake::ExtensionFlagStr(int32_t fl)
|
||||
{
|
||||
std::ostringstream out;
|
||||
if ( fl & HS_EXT_HSREQ )
|
||||
|
@ -211,7 +246,7 @@ string CHandShake::ExtensionFlagStr(int32_t fl)
|
|||
if ( fl & HS_EXT_CONFIG )
|
||||
out << " config";
|
||||
|
||||
int kl = SrtHSRequest::SRT_HSTYPE_ENCFLAGS::unwrap(fl) << 6;
|
||||
const int kl = SrtHSRequest::SRT_HSTYPE_ENCFLAGS::unwrap(fl) << 6;
|
||||
if (kl != 0)
|
||||
{
|
||||
out << " AES-" << kl;
|
||||
|
@ -228,7 +263,7 @@ string CHandShake::ExtensionFlagStr(int32_t fl)
|
|||
// XXX This code isn't currently used. Left here because it can
|
||||
// be used in future, should any refactoring for the "manual word placement"
|
||||
// code be done.
|
||||
bool SrtHSRequest::serialize(char* buf, size_t size) const
|
||||
bool srt::SrtHSRequest::serialize(char* buf, size_t size) const
|
||||
{
|
||||
if (size < SRT_HS_SIZE)
|
||||
return false;
|
||||
|
@ -243,7 +278,7 @@ bool SrtHSRequest::serialize(char* buf, size_t size) const
|
|||
}
|
||||
|
||||
|
||||
bool SrtHSRequest::deserialize(const char* buf, size_t size)
|
||||
bool srt::SrtHSRequest::deserialize(const char* buf, size_t size)
|
||||
{
|
||||
m_iSrtVersion = 0; // just to let users recognize if it succeeded or not.
|
||||
|
||||
|
@ -258,3 +293,35 @@ bool SrtHSRequest::deserialize(const char* buf, size_t size)
|
|||
m_iSrtReserved = (*p++);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string srt::SrtFlagString(int32_t flags)
|
||||
{
|
||||
#define LEN(arr) (sizeof (arr)/(sizeof ((arr)[0])))
|
||||
|
||||
std::string output;
|
||||
static std::string namera[] = { "TSBPD-snd", "TSBPD-rcv", "haicrypt", "TLPktDrop", "NAKReport", "ReXmitFlag", "StreamAPI" };
|
||||
|
||||
size_t i = 0;
|
||||
for (; i < LEN(namera); ++i)
|
||||
{
|
||||
if ((flags & 1) == 1)
|
||||
{
|
||||
output += "+" + namera[i] + " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
output += "-" + namera[i] + " ";
|
||||
}
|
||||
|
||||
flags >>= 1;
|
||||
}
|
||||
|
||||
#undef LEN
|
||||
|
||||
if (flags != 0)
|
||||
{
|
||||
output += "+unknown";
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
178
trunk/3rdparty/srt-1-fit/srtcore/handshake.h
vendored
178
trunk/3rdparty/srt-1-fit/srtcore/handshake.h
vendored
|
@ -43,12 +43,17 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC__HANDSHAKE_H
|
||||
#define INC__HANDSHAKE_H
|
||||
#ifndef INC_SRT_HANDSHAKE_H
|
||||
#define INC_SRT_HANDSHAKE_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "crypto.h"
|
||||
#include "utilities.h"
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
typedef Bits<31, 16> HS_CMDSPEC_CMD;
|
||||
typedef Bits<15, 0> HS_CMDSPEC_SIZE;
|
||||
|
||||
|
@ -93,6 +98,7 @@ const int SRT_CMD_REJECT = 0, // REJECT is only a symbol for return type
|
|||
SRT_CMD_SID = 5,
|
||||
SRT_CMD_CONGESTION = 6,
|
||||
SRT_CMD_FILTER = 7,
|
||||
SRT_CMD_GROUP = 8,
|
||||
SRT_CMD_NONE = -1; // for cases when {no pong for ping is required} | {no extension block found}
|
||||
|
||||
enum SrtDataStruct
|
||||
|
@ -102,7 +108,7 @@ enum SrtDataStruct
|
|||
SRT_HS_LATENCY,
|
||||
|
||||
// Keep it always last
|
||||
SRT_HS__SIZE
|
||||
SRT_HS_E_SIZE
|
||||
};
|
||||
|
||||
// For HSv5 the lo and hi part is used for particular side's latency
|
||||
|
@ -112,30 +118,21 @@ typedef Bits<15, 0> SRT_HS_LATENCY_SND;
|
|||
typedef Bits<15, 0> SRT_HS_LATENCY_LEG;
|
||||
|
||||
|
||||
// XXX These structures are currently unused. The code can be changed
|
||||
// so that these are used instead of manual tailoring of the messages.
|
||||
struct SrtHandshakeExtension
|
||||
{
|
||||
protected:
|
||||
|
||||
uint32_t m_SrtCommand; // Used only in extension
|
||||
|
||||
public:
|
||||
SrtHandshakeExtension(int cmd)
|
||||
{
|
||||
m_SrtCommand = cmd;
|
||||
}
|
||||
|
||||
void setCommand(int cmd)
|
||||
{
|
||||
m_SrtCommand = cmd;
|
||||
}
|
||||
int16_t type;
|
||||
std::vector<uint32_t> contents;
|
||||
|
||||
SrtHandshakeExtension(int16_t cmd): type(cmd) {}
|
||||
};
|
||||
|
||||
// Implemented in core.cpp, so far
|
||||
void SrtExtractHandshakeExtensions(const char* bufbegin, size_t size,
|
||||
std::vector<SrtHandshakeExtension>& w_output);
|
||||
|
||||
|
||||
struct SrtHSRequest: public SrtHandshakeExtension
|
||||
{
|
||||
|
||||
typedef Bits<31, 16> SRT_HSTYPE_ENCFLAGS;
|
||||
typedef Bits<15, 0> SRT_HSTYPE_HSFLAGS;
|
||||
|
||||
|
@ -154,6 +151,19 @@ struct SrtHSRequest: public SrtHandshakeExtension
|
|||
return base | SRT_HSTYPE_ENCFLAGS::wrap( SRT_PBKEYLEN_BITS::unwrap(crypto_keylen) );
|
||||
}
|
||||
|
||||
// Group handshake extension layout
|
||||
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Group ID |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Group Type | Group's Flags | Group's Weight |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
typedef Bits<31, 24> HS_GROUP_TYPE;
|
||||
typedef Bits<23, 16> HS_GROUP_FLAGS;
|
||||
typedef Bits<15, 0> HS_GROUP_WEIGHT;
|
||||
|
||||
private:
|
||||
friend class CHandShake;
|
||||
|
||||
|
@ -229,25 +239,37 @@ enum UDTRequestType
|
|||
// --> CONCLUSION (with response extensions, if RESPONDER)
|
||||
// <-- AGREEMENT (sent exclusively by INITIATOR upon reception of CONCLUSIOn with response extensions)
|
||||
|
||||
// Errors reported by the peer, also used as useless error codes
|
||||
// in handshake processing functions.
|
||||
URQ_FAILURE_TYPES = 1000
|
||||
// This marks the beginning of values that are error codes.
|
||||
URQ_FAILURE_TYPES = 1000,
|
||||
|
||||
// NOTE: codes above 1000 are reserved for failure codes for
|
||||
// rejection reason, as per `SRT_REJECT_REASON` enum. DO NOT
|
||||
// add any new values here.
|
||||
// rejection reason, as per `SRT_REJECT_REASON` enum. The
|
||||
// actual rejection code is the value of the request type
|
||||
// minus URQ_FAILURE_TYPES.
|
||||
|
||||
// This is in order to return standard error codes for server
|
||||
// data retrieval failures.
|
||||
URQ_SERVER_FAILURE_TYPES = URQ_FAILURE_TYPES + SRT_REJC_PREDEFINED,
|
||||
|
||||
// This is for a completely user-defined reject reasons.
|
||||
URQ_USER_FAILURE_TYPES = URQ_FAILURE_TYPES + SRT_REJC_USERDEFINED
|
||||
};
|
||||
|
||||
inline UDTRequestType URQFailure(SRT_REJECT_REASON reason)
|
||||
inline UDTRequestType URQFailure(int reason)
|
||||
{
|
||||
return UDTRequestType(URQ_FAILURE_TYPES + int(reason));
|
||||
}
|
||||
|
||||
inline SRT_REJECT_REASON RejectReasonForURQ(UDTRequestType req)
|
||||
inline int RejectReasonForURQ(UDTRequestType req)
|
||||
{
|
||||
if (req < URQ_FAILURE_TYPES || req - URQ_FAILURE_TYPES >= SRT_REJ__SIZE)
|
||||
if (req < URQ_FAILURE_TYPES)
|
||||
return SRT_REJ_UNKNOWN;
|
||||
return SRT_REJECT_REASON(req - URQ_FAILURE_TYPES);
|
||||
|
||||
int reason = req - URQ_FAILURE_TYPES;
|
||||
if (reason < SRT_REJC_PREDEFINED && reason >= SRT_REJ_E_SIZE)
|
||||
return SRT_REJ_UNKNOWN;
|
||||
|
||||
return reason;
|
||||
}
|
||||
|
||||
// DEPRECATED values. Use URQFailure(SRT_REJECT_REASON).
|
||||
|
@ -265,20 +287,20 @@ inline std::string RequestTypeStr(UDTRequestType) { return ""; }
|
|||
class CHandShake
|
||||
{
|
||||
public:
|
||||
CHandShake();
|
||||
CHandShake();
|
||||
|
||||
int store_to(char* buf, ref_t<size_t> size);
|
||||
int load_from(const char* buf, size_t size);
|
||||
int store_to(char* buf, size_t& size);
|
||||
int load_from(const char* buf, size_t size);
|
||||
|
||||
public:
|
||||
// This is the size of SERIALIZED handshake.
|
||||
// Might be defined as simply sizeof(CHandShake), but the
|
||||
// enum values would have to be forced as int32_t, which is only
|
||||
// available in C++11. Theoretically they are all 32-bit, but
|
||||
// such a statement is not reliable and not portable.
|
||||
static const size_t m_iContentSize = 48; // Size of hand shake data
|
||||
// This is the size of SERIALIZED handshake.
|
||||
// Might be defined as simply sizeof(CHandShake), but the
|
||||
// enum values would have to be forced as int32_t, which is only
|
||||
// available in C++11. Theoretically they are all 32-bit, but
|
||||
// such a statement is not reliable and not portable.
|
||||
static const size_t m_iContentSize = 48; // Size of hand shake data
|
||||
|
||||
// Extension flags
|
||||
// Extension flags
|
||||
|
||||
static const int32_t HS_EXT_HSREQ = BIT(0);
|
||||
static const int32_t HS_EXT_KMREQ = BIT(1);
|
||||
|
@ -290,53 +312,55 @@ public:
|
|||
int32_t flags() { return m_iType; }
|
||||
|
||||
public:
|
||||
int32_t m_iVersion; // UDT version (HS_VERSION_* symbols)
|
||||
int32_t m_iType; // UDT4: socket type (only UDT_DGRAM is valid); SRT1: extension flags
|
||||
int32_t m_iISN; // random initial sequence number
|
||||
int32_t m_iMSS; // maximum segment size
|
||||
int32_t m_iFlightFlagSize; // flow control window size
|
||||
UDTRequestType m_iReqType; // handshake stage
|
||||
int32_t m_iID; // socket ID
|
||||
int32_t m_iCookie; // cookie
|
||||
uint32_t m_piPeerIP[4]; // The IP address that the peer's UDP port is bound to
|
||||
int32_t m_iVersion; // UDT version (HS_VERSION_* symbols)
|
||||
int32_t m_iType; // UDT4: socket type (only UDT_DGRAM is valid); SRT1: extension flags
|
||||
int32_t m_iISN; // random initial sequence number
|
||||
int32_t m_iMSS; // maximum segment size
|
||||
int32_t m_iFlightFlagSize; // flow control window size
|
||||
UDTRequestType m_iReqType; // handshake stage
|
||||
int32_t m_iID; // SRT socket ID of HS sender
|
||||
int32_t m_iCookie; // cookie
|
||||
uint32_t m_piPeerIP[4]; // The IP address that the peer's UDP port is bound to
|
||||
|
||||
bool m_extension;
|
||||
bool m_extension;
|
||||
|
||||
std::string show();
|
||||
bool valid();
|
||||
std::string show();
|
||||
|
||||
// The rendezvous state machine used in HSv5 only (in HSv4 everything is happening the old way).
|
||||
//
|
||||
// The WAVING state is the very initial state of the rendezvous connection and restored after the
|
||||
// connection is closed.
|
||||
// The ATTENTION and FINE are two alternative states that are transited to from WAVING. The possible
|
||||
// situations are:
|
||||
// - "serial arrangement": one party transits to ATTENTION and the other party transits to FINE
|
||||
// - "parallel arrangement" both parties transit to ATTENTION
|
||||
//
|
||||
// Parallel arrangement is a "virtually impossible" case, in which both parties must send the first
|
||||
// URQ_WAVEAHAND message in a perfect time synchronization, when they are started at exactly the same
|
||||
// time, on machines with exactly the same performance and all things preceding the message sending
|
||||
// have taken perfectly identical amount of time. This isn't anyhow possible otherwise because if
|
||||
// the clients have started at different times, the one who started first sends a message and the
|
||||
// system of the receiver buffers this message even before the client binds the port for enough long
|
||||
// time so that it outlasts also the possible second, repeated waveahand.
|
||||
enum RendezvousState
|
||||
{
|
||||
RDV_INVALID, //< This socket wasn't prepared for rendezvous process. Reject any events.
|
||||
RDV_WAVING, //< Initial state for rendezvous. No contact seen from the peer.
|
||||
RDV_ATTENTION, //< When received URQ_WAVEAHAND. [WAVING]:URQ_WAVEAHAND --> [ATTENTION].
|
||||
RDV_FINE, //< When received URQ_CONCLUSION. [WAVING]:URQ_CONCLUSION --> [FINE].
|
||||
RDV_INITIATED, //< When received URQ_CONCLUSION+HSREQ extension in ATTENTION state.
|
||||
RDV_CONNECTED //< Final connected state. [ATTENTION]:URQ_CONCLUSION --> [CONNECTED] <-- [FINE]:URQ_AGREEMENT.
|
||||
};
|
||||
// The rendezvous state machine used in HSv5 only (in HSv4 everything is happening the old way).
|
||||
//
|
||||
// The WAVING state is the very initial state of the rendezvous connection and restored after the
|
||||
// connection is closed.
|
||||
// The ATTENTION and FINE are two alternative states that are transited to from WAVING. The possible
|
||||
// situations are:
|
||||
// - "serial arrangement": one party transits to ATTENTION and the other party transits to FINE
|
||||
// - "parallel arrangement" both parties transit to ATTENTION
|
||||
//
|
||||
// Parallel arrangement is a "virtually impossible" case, in which both parties must send the first
|
||||
// URQ_WAVEAHAND message in a perfect time synchronization, when they are started at exactly the same
|
||||
// time, on machines with exactly the same performance and all things preceding the message sending
|
||||
// have taken perfectly identical amount of time. This isn't anyhow possible otherwise because if
|
||||
// the clients have started at different times, the one who started first sends a message and the
|
||||
// system of the receiver buffers this message even before the client binds the port for enough long
|
||||
// time so that it outlasts also the possible second, repeated waveahand.
|
||||
enum RendezvousState
|
||||
{
|
||||
RDV_INVALID, //< This socket wasn't prepared for rendezvous process. Reject any events.
|
||||
RDV_WAVING, //< Initial state for rendezvous. No contact seen from the peer.
|
||||
RDV_ATTENTION, //< When received URQ_WAVEAHAND. [WAVING]:URQ_WAVEAHAND --> [ATTENTION].
|
||||
RDV_FINE, //< When received URQ_CONCLUSION. [WAVING]:URQ_CONCLUSION --> [FINE].
|
||||
RDV_INITIATED, //< When received URQ_CONCLUSION+HSREQ extension in ATTENTION state.
|
||||
RDV_CONNECTED //< Final connected state. [ATTENTION]:URQ_CONCLUSION --> [CONNECTED] <-- [FINE]:URQ_AGREEMENT.
|
||||
};
|
||||
|
||||
#if ENABLE_LOGGING
|
||||
static std::string RdvStateStr(RendezvousState s);
|
||||
static std::string RdvStateStr(RendezvousState s);
|
||||
#else
|
||||
static std::string RdvStateStr(RendezvousState) { return ""; }
|
||||
static std::string RdvStateStr(RendezvousState) { return ""; }
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
1125
trunk/3rdparty/srt-1-fit/srtcore/list.cpp
vendored
1125
trunk/3rdparty/srt-1-fit/srtcore/list.cpp
vendored
File diff suppressed because it is too large
Load diff
271
trunk/3rdparty/srt-1-fit/srtcore/list.h
vendored
271
trunk/3rdparty/srt-1-fit/srtcore/list.h
vendored
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -50,60 +50,77 @@ modified by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_LIST_H__
|
||||
#define __UDT_LIST_H__
|
||||
|
||||
#ifndef INC_SRT_LIST_H
|
||||
#define INC_SRT_LIST_H
|
||||
|
||||
#include "udt.h"
|
||||
#include "common.h"
|
||||
|
||||
namespace srt {
|
||||
|
||||
class CSndLossList
|
||||
{
|
||||
public:
|
||||
CSndLossList(int size = 1024);
|
||||
~CSndLossList();
|
||||
CSndLossList(int size = 1024);
|
||||
~CSndLossList();
|
||||
|
||||
/// Insert a seq. no. into the sender loss list.
|
||||
/// @param [in] seqno1 sequence number starts.
|
||||
/// @param [in] seqno2 sequence number ends.
|
||||
/// @return number of packets that are not in the list previously.
|
||||
/// Insert a seq. no. into the sender loss list.
|
||||
/// @param [in] seqno1 sequence number starts.
|
||||
/// @param [in] seqno2 sequence number ends.
|
||||
/// @return number of packets that are not in the list previously.
|
||||
int insert(int32_t seqno1, int32_t seqno2);
|
||||
|
||||
int insert(int32_t seqno1, int32_t seqno2);
|
||||
/// Remove the given sequence number and all numbers that precede it.
|
||||
/// @param [in] seqno sequence number.
|
||||
void removeUpTo(int32_t seqno);
|
||||
|
||||
/// Remove ALL the seq. no. that are not greater than the parameter.
|
||||
/// @param [in] seqno sequence number.
|
||||
/// Read the loss length.∏
|
||||
/// @return The length of the list.
|
||||
int getLossLength() const;
|
||||
|
||||
void remove(int32_t seqno);
|
||||
/// Read the first (smallest) loss seq. no. in the list and remove it.
|
||||
/// @return The seq. no. or -1 if the list is empty.
|
||||
int32_t popLostSeq();
|
||||
|
||||
/// Read the loss length.
|
||||
/// @return The length of the list.
|
||||
|
||||
int getLossLength() const;
|
||||
|
||||
/// Read the first (smallest) loss seq. no. in the list and remove it.
|
||||
/// @return The seq. no. or -1 if the list is empty.
|
||||
|
||||
int32_t popLostSeq();
|
||||
void traceState() const;
|
||||
|
||||
private:
|
||||
struct Seq
|
||||
{
|
||||
int32_t data1; // sequence number starts
|
||||
int32_t data2; // seqnence number ends
|
||||
int next; // next node in the list
|
||||
}* m_caSeq;
|
||||
struct Seq
|
||||
{
|
||||
int32_t seqstart; // sequence number starts
|
||||
int32_t seqend; // sequence number ends
|
||||
int inext; // index of the next node in the list
|
||||
} * m_caSeq;
|
||||
|
||||
int m_iHead; // first node
|
||||
int m_iLength; // loss length
|
||||
int m_iSize; // size of the static array
|
||||
int m_iLastInsertPos; // position of last insert node
|
||||
int m_iHead; // first node
|
||||
int m_iLength; // loss length
|
||||
const int m_iSize; // size of the static array
|
||||
int m_iLastInsertPos; // position of last insert node
|
||||
|
||||
mutable pthread_mutex_t m_ListLock; // used to synchronize list operation
|
||||
mutable srt::sync::Mutex m_ListLock; // used to synchronize list operation
|
||||
|
||||
private:
|
||||
CSndLossList(const CSndLossList&);
|
||||
CSndLossList& operator=(const CSndLossList&);
|
||||
/// Inserts an element to the beginning and updates head pointer.
|
||||
/// No lock.
|
||||
void insertHead(int pos, int32_t seqno1, int32_t seqno2);
|
||||
|
||||
/// Inserts an element after previous element.
|
||||
/// No lock.
|
||||
void insertAfter(int pos, int pos_after, int32_t seqno1, int32_t seqno2);
|
||||
|
||||
/// Check if it is possible to coalesce element at loc with further elements.
|
||||
/// @param loc - last changed location
|
||||
void coalesce(int loc);
|
||||
|
||||
/// Update existing element with the new range (increase only)
|
||||
/// @param pos position of the element being updated
|
||||
/// @param seqno1 first sequence number in range
|
||||
/// @param seqno2 last sequence number in range (SRT_SEQNO_NONE if no range)
|
||||
bool updateElement(int pos, int32_t seqno1, int32_t seqno2);
|
||||
|
||||
private:
|
||||
CSndLossList(const CSndLossList&);
|
||||
CSndLossList& operator=(const CSndLossList&);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -111,123 +128,124 @@ private:
|
|||
class CRcvLossList
|
||||
{
|
||||
public:
|
||||
CRcvLossList(int size = 1024);
|
||||
~CRcvLossList();
|
||||
CRcvLossList(int size = 1024);
|
||||
~CRcvLossList();
|
||||
|
||||
/// Insert a series of loss seq. no. between "seqno1" and "seqno2" into the receiver's loss list.
|
||||
/// @param [in] seqno1 sequence number starts.
|
||||
/// @param [in] seqno2 seqeunce number ends.
|
||||
/// Insert a series of loss seq. no. between "seqno1" and "seqno2" into the receiver's loss list.
|
||||
/// @param [in] seqno1 sequence number starts.
|
||||
/// @param [in] seqno2 seqeunce number ends.
|
||||
|
||||
void insert(int32_t seqno1, int32_t seqno2);
|
||||
void insert(int32_t seqno1, int32_t seqno2);
|
||||
|
||||
/// Remove a loss seq. no. from the receiver's loss list.
|
||||
/// @param [in] seqno sequence number.
|
||||
/// @return if the packet is removed (true) or no such lost packet is found (false).
|
||||
/// Remove a loss seq. no. from the receiver's loss list.
|
||||
/// @param [in] seqno sequence number.
|
||||
/// @return if the packet is removed (true) or no such lost packet is found (false).
|
||||
|
||||
bool remove(int32_t seqno);
|
||||
bool remove(int32_t seqno);
|
||||
|
||||
/// Remove all packets between seqno1 and seqno2.
|
||||
/// @param [in] seqno1 start sequence number.
|
||||
/// @param [in] seqno2 end sequence number.
|
||||
/// @return if the packet is removed (true) or no such lost packet is found (false).
|
||||
/// Remove all packets between seqno1 and seqno2.
|
||||
/// @param [in] seqno1 start sequence number.
|
||||
/// @param [in] seqno2 end sequence number.
|
||||
/// @return if the packet is removed (true) or no such lost packet is found (false).
|
||||
|
||||
bool remove(int32_t seqno1, int32_t seqno2);
|
||||
bool remove(int32_t seqno1, int32_t seqno2);
|
||||
|
||||
/// Find if there is any lost packets whose sequence number falling seqno1 and seqno2.
|
||||
/// @param [in] seqno1 start sequence number.
|
||||
/// @param [in] seqno2 end sequence number.
|
||||
/// @return True if found; otherwise false.
|
||||
/// Find if there is any lost packets whose sequence number falling seqno1 and seqno2.
|
||||
/// @param [in] seqno1 start sequence number.
|
||||
/// @param [in] seqno2 end sequence number.
|
||||
/// @return True if found; otherwise false.
|
||||
|
||||
bool find(int32_t seqno1, int32_t seqno2) const;
|
||||
bool find(int32_t seqno1, int32_t seqno2) const;
|
||||
|
||||
/// Read the loss length.
|
||||
/// @return the length of the list.
|
||||
/// Read the loss length.
|
||||
/// @return the length of the list.
|
||||
|
||||
int getLossLength() const;
|
||||
int getLossLength() const;
|
||||
|
||||
/// Read the first (smallest) seq. no. in the list.
|
||||
/// @return the sequence number or -1 if the list is empty.
|
||||
/// Read the first (smallest) seq. no. in the list.
|
||||
/// @return the sequence number or -1 if the list is empty.
|
||||
|
||||
int getFirstLostSeq() const;
|
||||
int32_t getFirstLostSeq() const;
|
||||
|
||||
/// Get a encoded loss array for NAK report.
|
||||
/// @param [out] array the result list of seq. no. to be included in NAK.
|
||||
/// @param [out] len physical length of the result array.
|
||||
/// @param [in] limit maximum length of the array.
|
||||
/// Get a encoded loss array for NAK report.
|
||||
/// @param [out] array the result list of seq. no. to be included in NAK.
|
||||
/// @param [out] len physical length of the result array.
|
||||
/// @param [in] limit maximum length of the array.
|
||||
|
||||
void getLossArray(int32_t* array, int& len, int limit);
|
||||
void getLossArray(int32_t* array, int& len, int limit);
|
||||
|
||||
private:
|
||||
struct Seq
|
||||
{
|
||||
int32_t data1; // sequence number starts
|
||||
int32_t data2; // sequence number ends
|
||||
int next; // next node in the list
|
||||
int prior; // prior node in the list;
|
||||
}* m_caSeq;
|
||||
struct Seq
|
||||
{
|
||||
int32_t seqstart; // sequence number starts
|
||||
int32_t seqend; // sequence number ends
|
||||
int inext; // index of the next node in the list
|
||||
int iprior; // index of the previous node in the list
|
||||
} * m_caSeq;
|
||||
|
||||
int m_iHead; // first node in the list
|
||||
int m_iTail; // last node in the list;
|
||||
int m_iLength; // loss length
|
||||
int m_iSize; // size of the static array
|
||||
int m_iHead; // first node in the list
|
||||
int m_iTail; // last node in the list;
|
||||
int m_iLength; // loss length
|
||||
int m_iSize; // size of the static array
|
||||
int m_iLargestSeq; // largest seq ever seen
|
||||
|
||||
private:
|
||||
CRcvLossList(const CRcvLossList&);
|
||||
CRcvLossList& operator=(const CRcvLossList&);
|
||||
CRcvLossList(const CRcvLossList&);
|
||||
CRcvLossList& operator=(const CRcvLossList&);
|
||||
|
||||
public:
|
||||
struct iterator
|
||||
{
|
||||
int32_t head;
|
||||
Seq* seq;
|
||||
|
||||
struct iterator
|
||||
{
|
||||
int32_t head;
|
||||
Seq* seq;
|
||||
iterator(Seq* str, int32_t v)
|
||||
: head(v)
|
||||
, seq(str)
|
||||
{
|
||||
}
|
||||
|
||||
iterator(Seq* str, int32_t v): head(v), seq(str) {}
|
||||
iterator next() const
|
||||
{
|
||||
if (head == -1)
|
||||
return *this; // should report error, but we can only throw exception, so simply ignore it.
|
||||
|
||||
iterator next() const
|
||||
{
|
||||
if ( head == -1 )
|
||||
return *this; // should report error, but we can only throw exception, so simply ignore it.
|
||||
return iterator(seq, seq[head].inext);
|
||||
}
|
||||
|
||||
return iterator(seq, seq[head].next);
|
||||
}
|
||||
iterator& operator++()
|
||||
{
|
||||
*this = next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator& operator++()
|
||||
{
|
||||
*this = next();
|
||||
return *this;
|
||||
}
|
||||
iterator operator++(int)
|
||||
{
|
||||
iterator old(seq, head);
|
||||
*this = next();
|
||||
return old;
|
||||
}
|
||||
|
||||
iterator operator++(int)
|
||||
{
|
||||
iterator old (seq, head);
|
||||
*this = next();
|
||||
return old;
|
||||
}
|
||||
bool operator==(const iterator& second) const
|
||||
{
|
||||
// Ignore seq - should be the same and this is only a sanity check.
|
||||
return head == second.head;
|
||||
}
|
||||
|
||||
bool operator==(const iterator& second) const
|
||||
{
|
||||
// Ignore seq - should be the same and this is only a sanity check.
|
||||
return head == second.head;
|
||||
}
|
||||
bool operator!=(const iterator& second) const { return !(*this == second); }
|
||||
|
||||
bool operator!=(const iterator& second) const { return !(*this == second); }
|
||||
|
||||
std::pair<int32_t, int32_t> operator*()
|
||||
{
|
||||
return std::make_pair(seq[head].data1, seq[head].data2);
|
||||
}
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(m_caSeq, m_iHead); }
|
||||
iterator end() { return iterator(m_caSeq, -1); }
|
||||
std::pair<int32_t, int32_t> operator*() { return std::make_pair(seq[head].seqstart, seq[head].seqend); }
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(m_caSeq, m_iHead); }
|
||||
iterator end() { return iterator(m_caSeq, -1); }
|
||||
};
|
||||
|
||||
struct CRcvFreshLoss
|
||||
{
|
||||
int32_t seq[2];
|
||||
int ttl;
|
||||
uint64_t timestamp;
|
||||
int32_t seq[2];
|
||||
int ttl;
|
||||
srt::sync::steady_clock::time_point timestamp;
|
||||
|
||||
CRcvFreshLoss(int32_t seqlo, int32_t seqhi, int initial_ttl);
|
||||
|
||||
|
@ -236,15 +254,18 @@ struct CRcvFreshLoss
|
|||
#ifdef DELETE
|
||||
#undef DELETE
|
||||
#endif
|
||||
enum Emod {
|
||||
NONE, //< the given sequence was not found in this range
|
||||
enum Emod
|
||||
{
|
||||
NONE, //< the given sequence was not found in this range
|
||||
STRIPPED, //< it was equal to first or last, already taken care of
|
||||
SPLIT, //< found in the middle, you have to split this range into two
|
||||
DELETE //< This was a range of one element exactly equal to sequence. Simply delete it.
|
||||
SPLIT, //< found in the middle, you have to split this range into two
|
||||
DELETE //< This was a range of one element exactly equal to sequence. Simply delete it.
|
||||
};
|
||||
|
||||
Emod revoke(int32_t sequence);
|
||||
Emod revoke(int32_t lo, int32_t hi);
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
53
trunk/3rdparty/srt-1-fit/srtcore/logger_default.cpp
vendored
Normal file
53
trunk/3rdparty/srt-1-fit/srtcore/logger_default.cpp
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
WARNING: Generated from ../scripts/generate-logging-defs.tcl
|
||||
|
||||
DO NOT MODIFY.
|
||||
|
||||
Copyright applies as per the generator script.
|
||||
*/
|
||||
|
||||
|
||||
#include "srt.h"
|
||||
#include "logging.h"
|
||||
#include "logger_defs.h"
|
||||
|
||||
namespace srt_logging
|
||||
{
|
||||
AllFaOn::AllFaOn()
|
||||
{
|
||||
allfa.set(SRT_LOGFA_GENERAL, true);
|
||||
allfa.set(SRT_LOGFA_SOCKMGMT, true);
|
||||
allfa.set(SRT_LOGFA_CONN, true);
|
||||
allfa.set(SRT_LOGFA_XTIMER, true);
|
||||
allfa.set(SRT_LOGFA_TSBPD, true);
|
||||
allfa.set(SRT_LOGFA_RSRC, true);
|
||||
|
||||
allfa.set(SRT_LOGFA_CONGEST, true);
|
||||
allfa.set(SRT_LOGFA_PFILTER, true);
|
||||
|
||||
allfa.set(SRT_LOGFA_API_CTRL, true);
|
||||
|
||||
allfa.set(SRT_LOGFA_QUE_CTRL, true);
|
||||
|
||||
allfa.set(SRT_LOGFA_EPOLL_UPD, true);
|
||||
|
||||
allfa.set(SRT_LOGFA_API_RECV, true);
|
||||
allfa.set(SRT_LOGFA_BUF_RECV, true);
|
||||
allfa.set(SRT_LOGFA_QUE_RECV, true);
|
||||
allfa.set(SRT_LOGFA_CHN_RECV, true);
|
||||
allfa.set(SRT_LOGFA_GRP_RECV, true);
|
||||
|
||||
allfa.set(SRT_LOGFA_API_SEND, true);
|
||||
allfa.set(SRT_LOGFA_BUF_SEND, true);
|
||||
allfa.set(SRT_LOGFA_QUE_SEND, true);
|
||||
allfa.set(SRT_LOGFA_CHN_SEND, true);
|
||||
allfa.set(SRT_LOGFA_GRP_SEND, true);
|
||||
|
||||
allfa.set(SRT_LOGFA_INTERNAL, true);
|
||||
|
||||
allfa.set(SRT_LOGFA_QUE_MGMT, true);
|
||||
allfa.set(SRT_LOGFA_CHN_MGMT, true);
|
||||
allfa.set(SRT_LOGFA_GRP_MGMT, true);
|
||||
allfa.set(SRT_LOGFA_EPOLL_API, true);
|
||||
}
|
||||
} // namespace srt_logging
|
55
trunk/3rdparty/srt-1-fit/srtcore/logger_defs.cpp
vendored
Normal file
55
trunk/3rdparty/srt-1-fit/srtcore/logger_defs.cpp
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
WARNING: Generated from ../scripts/generate-logging-defs.tcl
|
||||
|
||||
DO NOT MODIFY.
|
||||
|
||||
Copyright applies as per the generator script.
|
||||
*/
|
||||
|
||||
|
||||
#include "srt.h"
|
||||
#include "logging.h"
|
||||
#include "logger_defs.h"
|
||||
|
||||
namespace srt_logging { AllFaOn logger_fa_all; }
|
||||
// We need it outside the namespace to preserve the global name.
|
||||
// It's a part of "hidden API" (used by applications)
|
||||
SRT_API srt_logging::LogConfig srt_logger_config(srt_logging::logger_fa_all.allfa);
|
||||
|
||||
namespace srt_logging
|
||||
{
|
||||
Logger gglog(SRT_LOGFA_GENERAL, srt_logger_config, "SRT.gg");
|
||||
Logger smlog(SRT_LOGFA_SOCKMGMT, srt_logger_config, "SRT.sm");
|
||||
Logger cnlog(SRT_LOGFA_CONN, srt_logger_config, "SRT.cn");
|
||||
Logger xtlog(SRT_LOGFA_XTIMER, srt_logger_config, "SRT.xt");
|
||||
Logger tslog(SRT_LOGFA_TSBPD, srt_logger_config, "SRT.ts");
|
||||
Logger rslog(SRT_LOGFA_RSRC, srt_logger_config, "SRT.rs");
|
||||
|
||||
Logger cclog(SRT_LOGFA_CONGEST, srt_logger_config, "SRT.cc");
|
||||
Logger pflog(SRT_LOGFA_PFILTER, srt_logger_config, "SRT.pf");
|
||||
|
||||
Logger aclog(SRT_LOGFA_API_CTRL, srt_logger_config, "SRT.ac");
|
||||
|
||||
Logger qclog(SRT_LOGFA_QUE_CTRL, srt_logger_config, "SRT.qc");
|
||||
|
||||
Logger eilog(SRT_LOGFA_EPOLL_UPD, srt_logger_config, "SRT.ei");
|
||||
|
||||
Logger arlog(SRT_LOGFA_API_RECV, srt_logger_config, "SRT.ar");
|
||||
Logger brlog(SRT_LOGFA_BUF_RECV, srt_logger_config, "SRT.br");
|
||||
Logger qrlog(SRT_LOGFA_QUE_RECV, srt_logger_config, "SRT.qr");
|
||||
Logger krlog(SRT_LOGFA_CHN_RECV, srt_logger_config, "SRT.kr");
|
||||
Logger grlog(SRT_LOGFA_GRP_RECV, srt_logger_config, "SRT.gr");
|
||||
|
||||
Logger aslog(SRT_LOGFA_API_SEND, srt_logger_config, "SRT.as");
|
||||
Logger bslog(SRT_LOGFA_BUF_SEND, srt_logger_config, "SRT.bs");
|
||||
Logger qslog(SRT_LOGFA_QUE_SEND, srt_logger_config, "SRT.qs");
|
||||
Logger kslog(SRT_LOGFA_CHN_SEND, srt_logger_config, "SRT.ks");
|
||||
Logger gslog(SRT_LOGFA_GRP_SEND, srt_logger_config, "SRT.gs");
|
||||
|
||||
Logger inlog(SRT_LOGFA_INTERNAL, srt_logger_config, "SRT.in");
|
||||
|
||||
Logger qmlog(SRT_LOGFA_QUE_MGMT, srt_logger_config, "SRT.qm");
|
||||
Logger kmlog(SRT_LOGFA_CHN_MGMT, srt_logger_config, "SRT.km");
|
||||
Logger gmlog(SRT_LOGFA_GRP_MGMT, srt_logger_config, "SRT.gm");
|
||||
Logger ealog(SRT_LOGFA_EPOLL_API, srt_logger_config, "SRT.ea");
|
||||
} // namespace srt_logging
|
61
trunk/3rdparty/srt-1-fit/srtcore/logger_defs.h
vendored
Normal file
61
trunk/3rdparty/srt-1-fit/srtcore/logger_defs.h
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
WARNING: Generated from ../scripts/generate-logging-defs.tcl
|
||||
|
||||
DO NOT MODIFY.
|
||||
|
||||
Copyright applies as per the generator script.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INC_SRT_LOGGER_DEFS_H
|
||||
#define INC_SRT_LOGGER_DEFS_H
|
||||
|
||||
#include "srt.h"
|
||||
#include "logging.h"
|
||||
|
||||
namespace srt_logging
|
||||
{
|
||||
struct AllFaOn
|
||||
{
|
||||
LogConfig::fa_bitset_t allfa;
|
||||
AllFaOn();
|
||||
};
|
||||
|
||||
extern Logger gglog;
|
||||
extern Logger smlog;
|
||||
extern Logger cnlog;
|
||||
extern Logger xtlog;
|
||||
extern Logger tslog;
|
||||
extern Logger rslog;
|
||||
|
||||
extern Logger cclog;
|
||||
extern Logger pflog;
|
||||
|
||||
extern Logger aclog;
|
||||
|
||||
extern Logger qclog;
|
||||
|
||||
extern Logger eilog;
|
||||
|
||||
extern Logger arlog;
|
||||
extern Logger brlog;
|
||||
extern Logger qrlog;
|
||||
extern Logger krlog;
|
||||
extern Logger grlog;
|
||||
|
||||
extern Logger aslog;
|
||||
extern Logger bslog;
|
||||
extern Logger qslog;
|
||||
extern Logger kslog;
|
||||
extern Logger gslog;
|
||||
|
||||
extern Logger inlog;
|
||||
|
||||
extern Logger qmlog;
|
||||
extern Logger kmlog;
|
||||
extern Logger gmlog;
|
||||
extern Logger ealog;
|
||||
|
||||
} // namespace srt_logging
|
||||
|
||||
#endif
|
69
trunk/3rdparty/srt-1-fit/srtcore/logging.h
vendored
69
trunk/3rdparty/srt-1-fit/srtcore/logging.h
vendored
|
@ -13,8 +13,8 @@ written by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC__SRT_LOGGING_H
|
||||
#define INC__SRT_LOGGING_H
|
||||
#ifndef INC_SRT_LOGGING_H
|
||||
#define INC_SRT_LOGGING_H
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
@ -28,16 +28,13 @@ written by
|
|||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#if HAVE_CXX11
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
#include "srt.h"
|
||||
#include "utilities.h"
|
||||
#include "threadname.h"
|
||||
#include "logging_api.h"
|
||||
#include "srt_compat.h"
|
||||
#include "sync.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define PRINTF_LIKE __attribute__((format(printf,2,3)))
|
||||
|
@ -53,17 +50,24 @@ written by
|
|||
|
||||
// LOGC uses an iostream-like syntax, using the special 'log' symbol.
|
||||
// This symbol isn't visible outside the log macro parameters.
|
||||
// Usage: LOGC(mglog.Debug, log << param1 << param2 << param3);
|
||||
#define LOGC(logdes, args) if (logdes.CheckEnabled()) { srt_logging::LogDispatcher::Proxy log(logdes); log.setloc(__FILE__, __LINE__, __FUNCTION__); args; }
|
||||
// Usage: LOGC(gglog.Debug, log << param1 << param2 << param3);
|
||||
#define LOGC(logdes, args) if (logdes.CheckEnabled()) \
|
||||
{ \
|
||||
srt_logging::LogDispatcher::Proxy log(logdes); \
|
||||
log.setloc(__FILE__, __LINE__, __FUNCTION__); \
|
||||
const srt_logging::LogDispatcher::Proxy& log_prox SRT_ATR_UNUSED = args; \
|
||||
}
|
||||
|
||||
// LOGF uses printf-like style formatting.
|
||||
// Usage: LOGF(mglog.Debug, "%s: %d", param1.c_str(), int(param2));
|
||||
// Usage: LOGF(gglog.Debug, "%s: %d", param1.c_str(), int(param2));
|
||||
#define LOGF(logdes, ...) if (logdes.CheckEnabled()) logdes().setloc(__FILE__, __LINE__, __FUNCTION__).form(__VA_ARGS__)
|
||||
|
||||
// LOGP is C++11 only OR with only one string argument.
|
||||
// Usage: LOGP(mglog.Debug, param1, param2, param3);
|
||||
// Usage: LOGP(gglog.Debug, param1, param2, param3);
|
||||
#define LOGP(logdes, ...) if (logdes.CheckEnabled()) logdes.printloc(__FILE__, __LINE__, __FUNCTION__,##__VA_ARGS__)
|
||||
|
||||
#define IF_LOGGING(instr) instr
|
||||
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
|
||||
#define HLOGC LOGC
|
||||
|
@ -93,6 +97,7 @@ written by
|
|||
#define HLOGP(...)
|
||||
|
||||
#define IF_HEAVY_LOGGING(instr) (void)0
|
||||
#define IF_LOGGING(instr) (void)0
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -107,29 +112,30 @@ struct LogConfig
|
|||
std::ostream* log_stream;
|
||||
SRT_LOG_HANDLER_FN* loghandler_fn;
|
||||
void* loghandler_opaque;
|
||||
pthread_mutex_t mutex;
|
||||
srt::sync::Mutex mutex;
|
||||
int flags;
|
||||
|
||||
LogConfig(const fa_bitset_t& initial_fa):
|
||||
enabled_fa(initial_fa),
|
||||
max_level(LogLevel::warning),
|
||||
log_stream(&std::cerr)
|
||||
LogConfig(const fa_bitset_t& efa,
|
||||
LogLevel::type l = LogLevel::warning,
|
||||
std::ostream* ls = &std::cerr)
|
||||
: enabled_fa(efa)
|
||||
, max_level(l)
|
||||
, log_stream(ls)
|
||||
, loghandler_fn()
|
||||
, loghandler_opaque()
|
||||
, flags()
|
||||
{
|
||||
pthread_mutex_init(&mutex, 0);
|
||||
}
|
||||
LogConfig(const fa_bitset_t& efa, LogLevel::type l, std::ostream* ls):
|
||||
enabled_fa(efa), max_level(l), log_stream(ls)
|
||||
{
|
||||
pthread_mutex_init(&mutex, 0);
|
||||
}
|
||||
|
||||
~LogConfig()
|
||||
{
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
|
||||
void lock() { pthread_mutex_lock(&mutex); }
|
||||
void unlock() { pthread_mutex_unlock(&mutex); }
|
||||
SRT_ATTR_ACQUIRE(mutex)
|
||||
void lock() { mutex.lock(); }
|
||||
|
||||
SRT_ATTR_RELEASE(mutex)
|
||||
void unlock() { mutex.unlock(); }
|
||||
};
|
||||
|
||||
// The LogDispatcher class represents the object that is responsible for
|
||||
|
@ -142,7 +148,6 @@ private:
|
|||
static const size_t MAX_PREFIX_SIZE = 32;
|
||||
char prefix[MAX_PREFIX_SIZE+1];
|
||||
LogConfig* src_config;
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
bool isset(int flg) { return (src_config->flags & flg) != 0; }
|
||||
|
||||
|
@ -169,12 +174,10 @@ public:
|
|||
strcat(prefix, ":");
|
||||
strcat(prefix, logger_pfx);
|
||||
}
|
||||
pthread_mutex_init(&mutex, 0);
|
||||
}
|
||||
|
||||
~LogDispatcher()
|
||||
{
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
|
||||
bool CheckEnabled();
|
||||
|
@ -244,6 +247,11 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
DummyProxy& vform(const char*, va_list)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
DummyProxy& setloc(const char* , int , std::string)
|
||||
{
|
||||
return *this;
|
||||
|
@ -292,7 +300,7 @@ struct LogDispatcher::Proxy
|
|||
// or better __func__.
|
||||
std::string ExtractName(std::string pretty_function);
|
||||
|
||||
Proxy(LogDispatcher& guy);
|
||||
Proxy(LogDispatcher& guy);
|
||||
|
||||
// Copy constructor is needed due to noncopyable ostringstream.
|
||||
// This is used only in creation of the default object, so just
|
||||
|
@ -407,7 +415,6 @@ inline bool LogDispatcher::CheckEnabled()
|
|||
return configured_enabled_fa && level <= configured_maxlevel;
|
||||
}
|
||||
|
||||
SRT_API std::string FormatTime(uint64_t time);
|
||||
|
||||
#if HAVE_CXX11
|
||||
|
||||
|
@ -423,7 +430,7 @@ inline void PrintArgs(std::ostream& serr, Arg1&& arg1, Args&&... args)
|
|||
}
|
||||
|
||||
template <class... Args>
|
||||
inline void LogDispatcher::PrintLogLine(const char* file ATR_UNUSED, int line ATR_UNUSED, const std::string& area ATR_UNUSED, Args&&... args ATR_UNUSED)
|
||||
inline void LogDispatcher::PrintLogLine(const char* file SRT_ATR_UNUSED, int line SRT_ATR_UNUSED, const std::string& area SRT_ATR_UNUSED, Args&&... args SRT_ATR_UNUSED)
|
||||
{
|
||||
#ifdef ENABLE_LOGGING
|
||||
std::ostringstream serr;
|
||||
|
@ -441,7 +448,7 @@ inline void LogDispatcher::PrintLogLine(const char* file ATR_UNUSED, int line AT
|
|||
#else
|
||||
|
||||
template <class Arg>
|
||||
inline void LogDispatcher::PrintLogLine(const char* file ATR_UNUSED, int line ATR_UNUSED, const std::string& area ATR_UNUSED, const Arg& arg ATR_UNUSED)
|
||||
inline void LogDispatcher::PrintLogLine(const char* file SRT_ATR_UNUSED, int line SRT_ATR_UNUSED, const std::string& area SRT_ATR_UNUSED, const Arg& arg SRT_ATR_UNUSED)
|
||||
{
|
||||
#ifdef ENABLE_LOGGING
|
||||
std::ostringstream serr;
|
||||
|
|
|
@ -13,8 +13,8 @@ written by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC__SRT_LOGGING_API_H
|
||||
#define INC__SRT_LOGGING_API_H
|
||||
#ifndef INC_SRT_LOGGING_API_H
|
||||
#define INC_SRT_LOGGING_API_H
|
||||
|
||||
// These are required for access functions:
|
||||
// - adding FA (requires set)
|
||||
|
@ -24,7 +24,6 @@ written by
|
|||
#include <iostream>
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
#ifdef _WIN32
|
||||
#include "win/syslog_defs.h"
|
||||
#else
|
||||
|
|
14
trunk/3rdparty/srt-1-fit/srtcore/md5.cpp
vendored
14
trunk/3rdparty/srt-1-fit/srtcore/md5.cpp
vendored
|
@ -54,6 +54,12 @@
|
|||
#include "md5.h"
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* All symbols have been put under the srt namespace
|
||||
* to avoid potential linkage conflicts.
|
||||
*/
|
||||
namespace srt {
|
||||
|
||||
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
|
||||
#ifdef ARCH_IS_BIG_ENDIAN
|
||||
# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
|
||||
|
@ -166,7 +172,7 @@ md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
|
|||
X = (const md5_word_t *)data;
|
||||
} else {
|
||||
/* not aligned */
|
||||
memcpy(xbuf, data, 64);
|
||||
memcpy((xbuf), data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
}
|
||||
|
@ -340,7 +346,7 @@ md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
|
|||
if (offset) {
|
||||
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
||||
|
||||
memcpy(pms->buf + offset, p, copy);
|
||||
memcpy((pms->buf + offset), p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
p += copy;
|
||||
|
@ -354,7 +360,7 @@ md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
|
|||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
memcpy(pms->buf, p, left);
|
||||
memcpy((pms->buf), p, left);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -379,3 +385,5 @@ md5_finish(md5_state_t *pms, md5_byte_t digest[16])
|
|||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
||||
|
||||
} // namespace srt
|
||||
|
|
15
trunk/3rdparty/srt-1-fit/srtcore/md5.h
vendored
15
trunk/3rdparty/srt-1-fit/srtcore/md5.h
vendored
|
@ -50,6 +50,12 @@
|
|||
#ifndef md5_INCLUDED
|
||||
# define md5_INCLUDED
|
||||
|
||||
/*
|
||||
* All symbols have been put under the srt namespace
|
||||
* to avoid potential linkage conflicts.
|
||||
*/
|
||||
namespace srt {
|
||||
|
||||
/*
|
||||
* This package supports both compile-time and run-time determination of CPU
|
||||
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
|
||||
|
@ -70,11 +76,6 @@ typedef struct md5_state_s {
|
|||
md5_byte_t buf[64]; /* accumulate block */
|
||||
} md5_state_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Initialize the algorithm. */
|
||||
void md5_init(md5_state_t *pms);
|
||||
|
||||
|
@ -84,8 +85,6 @@ void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
|
|||
/* Finish the message and return the digest. */
|
||||
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end extern "C" */
|
||||
#endif
|
||||
} // namespace srt
|
||||
|
||||
#endif /* md5_INCLUDED */
|
||||
|
|
327
trunk/3rdparty/srt-1-fit/srtcore/netinet_any.h
vendored
327
trunk/3rdparty/srt-1-fit/srtcore/netinet_any.h
vendored
|
@ -13,10 +13,12 @@ written by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC__NETINET_ANY_H
|
||||
#define INC__NETINET_ANY_H
|
||||
#ifndef INC_SRT_NETINET_ANY_H
|
||||
#define INC_SRT_NETINET_ANY_H
|
||||
|
||||
#include <cstring>
|
||||
#include <cstring> // memcmp
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "platform_sys.h"
|
||||
|
||||
// This structure should replace every use of sockaddr and its currently
|
||||
|
@ -25,6 +27,9 @@ written by
|
|||
// You can use the instances of sockaddr_any in every place where sockaddr is
|
||||
// required.
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
struct sockaddr_any
|
||||
{
|
||||
union
|
||||
|
@ -33,27 +38,234 @@ struct sockaddr_any
|
|||
sockaddr_in6 sin6;
|
||||
sockaddr sa;
|
||||
};
|
||||
socklen_t len;
|
||||
|
||||
sockaddr_any(int domain = AF_INET)
|
||||
// The type is intended to be the same as the length
|
||||
// parameter in ::accept, ::bind and ::connect functions.
|
||||
|
||||
// This is the type used by SRT.
|
||||
typedef int len_t;
|
||||
|
||||
// This is the type used by system functions
|
||||
#ifdef _WIN32
|
||||
typedef int syslen_t;
|
||||
#else
|
||||
typedef socklen_t syslen_t;
|
||||
#endif
|
||||
|
||||
// Note: by having `len_t` type here the usage in
|
||||
// API functions is here limited to SRT. For system
|
||||
// functions you can pass the address here as (socklen_t*)&sa.len,
|
||||
// but just do it on your own risk, as there's no guarantee
|
||||
// that sizes of `int` and `socklen_t` do not differ. The safest
|
||||
// way seems to be using an intermediate proxy to be written
|
||||
// back here from the value of `syslen_t`.
|
||||
len_t len;
|
||||
|
||||
struct SysLenWrapper
|
||||
{
|
||||
memset(this, 0, sizeof *this);
|
||||
sa.sa_family = domain;
|
||||
len = size();
|
||||
syslen_t syslen;
|
||||
len_t& backwriter;
|
||||
syslen_t* operator&() { return &syslen; }
|
||||
|
||||
SysLenWrapper(len_t& source): syslen(source), backwriter(source)
|
||||
{
|
||||
}
|
||||
|
||||
~SysLenWrapper()
|
||||
{
|
||||
backwriter = syslen;
|
||||
}
|
||||
};
|
||||
|
||||
// Usage:
|
||||
// ::accept(lsn_sock, sa.get(), &sa.syslen());
|
||||
SysLenWrapper syslen()
|
||||
{
|
||||
return SysLenWrapper(len);
|
||||
}
|
||||
|
||||
socklen_t size() const
|
||||
static size_t storage_size()
|
||||
{
|
||||
switch (sa.sa_family)
|
||||
typedef union
|
||||
{
|
||||
case AF_INET: return socklen_t(sizeof sin);
|
||||
case AF_INET6: return socklen_t(sizeof sin6);
|
||||
sockaddr_in sin;
|
||||
sockaddr_in6 sin6;
|
||||
sockaddr sa;
|
||||
} ucopy;
|
||||
return sizeof (ucopy);
|
||||
}
|
||||
|
||||
default: return 0; // fallback, impossible
|
||||
void reset()
|
||||
{
|
||||
// sin6 is the largest field
|
||||
memset((&sin6), 0, sizeof sin6);
|
||||
len = 0;
|
||||
}
|
||||
|
||||
// Default domain is unspecified, and
|
||||
// in this case the size is 0.
|
||||
// Note that AF_* (and alias PF_*) types have
|
||||
// many various values, of which only
|
||||
// AF_INET and AF_INET6 are handled here.
|
||||
// Others make the same effect as unspecified.
|
||||
explicit sockaddr_any(int domain = AF_UNSPEC)
|
||||
{
|
||||
// Default domain is "unspecified", 0
|
||||
reset();
|
||||
|
||||
// Overriding family as required in the parameters
|
||||
// and the size then accordingly.
|
||||
sa.sa_family = domain == AF_INET || domain == AF_INET6 ? domain : AF_UNSPEC;
|
||||
switch (domain)
|
||||
{
|
||||
case AF_INET:
|
||||
len = len_t(sizeof (sockaddr_in));
|
||||
break;
|
||||
|
||||
// Use size of sin6 as the default size
|
||||
// len must be properly set so that the
|
||||
// family-less sockaddr is passed to bind/accept
|
||||
default:
|
||||
len = len_t(sizeof (sockaddr_in6));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sockaddr_any(const sockaddr_storage& stor)
|
||||
{
|
||||
// Here the length isn't passed, so just rely on family.
|
||||
set((const sockaddr*)&stor);
|
||||
}
|
||||
|
||||
sockaddr_any(const sockaddr* source, len_t namelen = 0)
|
||||
{
|
||||
if (namelen == 0)
|
||||
set(source);
|
||||
else
|
||||
set(source, namelen);
|
||||
}
|
||||
|
||||
void set(const sockaddr* source)
|
||||
{
|
||||
// Less safe version, simply trust the caller that the
|
||||
// memory at 'source' is also large enough to contain
|
||||
// all data required for particular family.
|
||||
if (source->sa_family == AF_INET)
|
||||
{
|
||||
memcpy((&sin), source, sizeof sin);
|
||||
len = sizeof sin;
|
||||
}
|
||||
else if (source->sa_family == AF_INET6)
|
||||
{
|
||||
memcpy((&sin6), source, sizeof sin6);
|
||||
len = sizeof sin6;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error fallback: no other families than IP are regarded.
|
||||
// Note: socket set up this way isn't intended to be used
|
||||
// for bind/accept.
|
||||
sa.sa_family = AF_UNSPEC;
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void set(const sockaddr* source, syslen_t namelen)
|
||||
{
|
||||
// It's not safe to copy it directly, so check.
|
||||
if (source->sa_family == AF_INET && namelen >= syslen_t(sizeof sin))
|
||||
{
|
||||
memcpy((&sin), source, sizeof sin);
|
||||
len = sizeof sin;
|
||||
}
|
||||
else if (source->sa_family == AF_INET6 && namelen >= syslen_t(sizeof sin6))
|
||||
{
|
||||
// Note: this isn't too safe, may crash for stupid values
|
||||
// of source->sa_family or any other data
|
||||
// in the source structure, so make sure it's correct first.
|
||||
memcpy((&sin6), source, sizeof sin6);
|
||||
len = sizeof sin6;
|
||||
}
|
||||
else
|
||||
{
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
void set(const sockaddr_in& in4)
|
||||
{
|
||||
memcpy((&sin), &in4, sizeof in4);
|
||||
len = sizeof in4;
|
||||
}
|
||||
|
||||
void set(const sockaddr_in6& in6)
|
||||
{
|
||||
memcpy((&sin6), &in6, sizeof in6);
|
||||
len = sizeof in6;
|
||||
}
|
||||
|
||||
sockaddr_any(const in_addr& i4_adr, uint16_t port)
|
||||
{
|
||||
// Some cases require separately IPv4 address passed as in_addr,
|
||||
// so port is given separately.
|
||||
sa.sa_family = AF_INET;
|
||||
sin.sin_addr = i4_adr;
|
||||
sin.sin_port = htons(port);
|
||||
len = sizeof sin;
|
||||
}
|
||||
|
||||
sockaddr_any(const in6_addr& i6_adr, uint16_t port)
|
||||
{
|
||||
sa.sa_family = AF_INET6;
|
||||
sin6.sin6_addr = i6_adr;
|
||||
sin6.sin6_port = htons(port);
|
||||
len = sizeof sin6;
|
||||
}
|
||||
|
||||
static len_t size(int family)
|
||||
{
|
||||
switch (family)
|
||||
{
|
||||
case AF_INET:
|
||||
return len_t(sizeof (sockaddr_in));
|
||||
|
||||
case AF_INET6:
|
||||
return len_t(sizeof (sockaddr_in6));
|
||||
|
||||
default:
|
||||
return 0; // fallback
|
||||
}
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
bool isempty = true; // unspec-family address is always empty
|
||||
|
||||
if (sa.sa_family == AF_INET)
|
||||
{
|
||||
isempty = (sin.sin_port == 0
|
||||
&& sin.sin_addr.s_addr == 0);
|
||||
}
|
||||
else if (sa.sa_family == AF_INET6)
|
||||
{
|
||||
isempty = (sin6.sin6_port == 0
|
||||
&& memcmp(&sin6.sin6_addr, &in6addr_any, sizeof in6addr_any) == 0);
|
||||
}
|
||||
// otherwise isempty stays with default false
|
||||
return isempty;
|
||||
}
|
||||
|
||||
len_t size() const
|
||||
{
|
||||
return size(sa.sa_family);
|
||||
}
|
||||
|
||||
int family() const { return sa.sa_family; }
|
||||
void family(int val)
|
||||
{
|
||||
sa.sa_family = val;
|
||||
len = size();
|
||||
}
|
||||
|
||||
// port is in exactly the same location in both sin and sin6
|
||||
// and has the same size. This is actually yet another common
|
||||
|
@ -71,10 +283,26 @@ struct sockaddr_any
|
|||
}
|
||||
|
||||
sockaddr* get() { return &sa; }
|
||||
sockaddr* operator&() { return &sa; }
|
||||
|
||||
const sockaddr* get() const { return &sa; }
|
||||
const sockaddr* operator&() const { return &sa; }
|
||||
|
||||
// Sometimes you need to get the address
|
||||
// the way suitable for e.g. inet_ntop.
|
||||
const void* get_addr() const
|
||||
{
|
||||
if (sa.sa_family == AF_INET)
|
||||
return &sin.sin_addr.s_addr;
|
||||
|
||||
if (sa.sa_family == AF_INET6)
|
||||
return &sin6.sin6_addr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* get_addr()
|
||||
{
|
||||
const sockaddr_any* that = this;
|
||||
return (void*)that->get_addr();
|
||||
}
|
||||
|
||||
template <int> struct TypeMap;
|
||||
|
||||
|
@ -85,7 +313,26 @@ struct sockaddr_any
|
|||
{
|
||||
bool operator()(const sockaddr_any& c1, const sockaddr_any& c2)
|
||||
{
|
||||
return memcmp(&c1, &c2, sizeof(c1)) == 0;
|
||||
if (c1.family() != c2.family())
|
||||
return false;
|
||||
|
||||
// Cannot use memcmp due to having in some systems
|
||||
// another field like sockaddr_in::sin_len. This exists
|
||||
// in some BSD-derived systems, but is not required by POSIX.
|
||||
// Therefore sockaddr_any class cannot operate with it,
|
||||
// as in this situation it would be safest to state that
|
||||
// particular implementations may have additional fields
|
||||
// of different purpose beside those required by POSIX.
|
||||
//
|
||||
// The only reliable way to compare two underlying sockaddr
|
||||
// object is then to compare the port value and the address
|
||||
// value.
|
||||
//
|
||||
// Fortunately the port is 16-bit and located at the same
|
||||
// offset in both sockaddr_in and sockaddr_in6.
|
||||
|
||||
return c1.sin.sin_port == c2.sin.sin_port
|
||||
&& c1.equal_address(c2);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -120,6 +367,50 @@ struct sockaddr_any
|
|||
return memcmp(&c1, &c2, sizeof(c1)) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Tests if the current address is the "any" wildcard.
|
||||
bool isany() const
|
||||
{
|
||||
if (sa.sa_family == AF_INET)
|
||||
return sin.sin_addr.s_addr == INADDR_ANY;
|
||||
|
||||
if (sa.sa_family == AF_INET6)
|
||||
return memcmp(&sin6.sin6_addr, &in6addr_any, sizeof in6addr_any) == 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Debug support
|
||||
std::string str() const
|
||||
{
|
||||
if (family() != AF_INET && family() != AF_INET6)
|
||||
return "unknown:0";
|
||||
|
||||
std::ostringstream output;
|
||||
char hostbuf[1024];
|
||||
int flags;
|
||||
|
||||
#if ENABLE_GETNAMEINFO
|
||||
flags = NI_NAMEREQD;
|
||||
#else
|
||||
flags = NI_NUMERICHOST | NI_NUMERICSERV;
|
||||
#endif
|
||||
|
||||
if (!getnameinfo(get(), size(), hostbuf, 1024, NULL, 0, flags))
|
||||
{
|
||||
output << hostbuf;
|
||||
}
|
||||
|
||||
output << ":" << hport();
|
||||
return output.str();
|
||||
}
|
||||
|
||||
bool operator==(const sockaddr_any& other) const
|
||||
{
|
||||
return Equal()(*this, other);
|
||||
}
|
||||
|
||||
bool operator!=(const sockaddr_any& other) const { return !(*this == other); }
|
||||
};
|
||||
|
||||
template<> struct sockaddr_any::TypeMap<AF_INET> { typedef sockaddr_in type; };
|
||||
|
@ -130,4 +421,6 @@ inline sockaddr_any::TypeMap<AF_INET>::type& sockaddr_any::get<AF_INET>() { retu
|
|||
template <>
|
||||
inline sockaddr_any::TypeMap<AF_INET6>::type& sockaddr_any::get<AF_INET6>() { return sin6; }
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
456
trunk/3rdparty/srt-1-fit/srtcore/packet.cpp
vendored
456
trunk/3rdparty/srt-1-fit/srtcore/packet.cpp
vendored
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -50,7 +50,6 @@ modified by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
|
@ -137,9 +136,9 @@ modified by
|
|||
// Add. Info: Error code
|
||||
// Control Info: None
|
||||
// 0x7FFF: Explained by bits 16 - 31 (UMSG_EXT)
|
||||
//
|
||||
//
|
||||
// bit 16 - 31:
|
||||
// This space is used for future expansion or user defined control packets.
|
||||
// This space is used for future expansion or user defined control packets.
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
|
@ -159,26 +158,29 @@ modified by
|
|||
// For any single loss or consectutive loss less than 2 packets, use
|
||||
// the original sequence numbers in the field.
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <cstring>
|
||||
#include "packet.h"
|
||||
#include "handshake.h"
|
||||
#include "logging.h"
|
||||
#include "handshake.h"
|
||||
|
||||
namespace srt_logging
|
||||
{
|
||||
extern Logger mglog;
|
||||
extern Logger inlog;
|
||||
}
|
||||
using namespace srt_logging;
|
||||
|
||||
// Set up the aliases in the constructure
|
||||
CPacket::CPacket():
|
||||
__pad(),
|
||||
m_data_owned(false),
|
||||
m_iSeqNo((int32_t&)(m_nHeader[SRT_PH_SEQNO])),
|
||||
m_iMsgNo((int32_t&)(m_nHeader[SRT_PH_MSGNO])),
|
||||
m_iTimeStamp((int32_t&)(m_nHeader[SRT_PH_TIMESTAMP])),
|
||||
m_iID((int32_t&)(m_nHeader[SRT_PH_ID])),
|
||||
m_pcData((char*&)(m_PacketVector[PV_DATA].dataRef()))
|
||||
srt::CPacket::CPacket()
|
||||
: m_extra_pad()
|
||||
, m_data_owned(false)
|
||||
, m_iSeqNo((int32_t&)(m_nHeader[SRT_PH_SEQNO]))
|
||||
, m_iMsgNo((int32_t&)(m_nHeader[SRT_PH_MSGNO]))
|
||||
, m_iTimeStamp((int32_t&)(m_nHeader[SRT_PH_TIMESTAMP]))
|
||||
, m_iID((int32_t&)(m_nHeader[SRT_PH_ID]))
|
||||
, m_pcData((char*&)(m_PacketVector[PV_DATA].dataRef()))
|
||||
{
|
||||
m_nHeader.clear();
|
||||
|
||||
|
@ -192,166 +194,236 @@ m_pcData((char*&)(m_PacketVector[PV_DATA].dataRef()))
|
|||
m_PacketVector[PV_DATA].set(NULL, 0);
|
||||
}
|
||||
|
||||
void CPacket::allocate(size_t alloc_buffer_size)
|
||||
char* srt::CPacket::getData()
|
||||
{
|
||||
return (char*)m_PacketVector[PV_DATA].dataRef();
|
||||
}
|
||||
|
||||
void srt::CPacket::allocate(size_t alloc_buffer_size)
|
||||
{
|
||||
if (m_data_owned)
|
||||
{
|
||||
if (getLength() == alloc_buffer_size)
|
||||
return; // already allocated
|
||||
|
||||
// Would be nice to reallocate; for now just allocate again.
|
||||
delete[] m_pcData;
|
||||
}
|
||||
m_PacketVector[PV_DATA].set(new char[alloc_buffer_size], alloc_buffer_size);
|
||||
m_data_owned = true;
|
||||
}
|
||||
|
||||
void CPacket::deallocate()
|
||||
void srt::CPacket::deallocate()
|
||||
{
|
||||
if (m_data_owned)
|
||||
delete [] (char*)m_PacketVector[PV_DATA].data();
|
||||
delete[](char*) m_PacketVector[PV_DATA].data();
|
||||
m_PacketVector[PV_DATA].set(NULL, 0);
|
||||
}
|
||||
|
||||
CPacket::~CPacket()
|
||||
char* srt::CPacket::release()
|
||||
{
|
||||
// When not owned, release returns NULL.
|
||||
char* buffer = NULL;
|
||||
if (m_data_owned)
|
||||
{
|
||||
buffer = getData();
|
||||
m_data_owned = false;
|
||||
}
|
||||
|
||||
deallocate(); // won't delete because m_data_owned == false
|
||||
return buffer;
|
||||
}
|
||||
|
||||
srt::CPacket::~CPacket()
|
||||
{
|
||||
// PV_HEADER is always owned, PV_DATA may use a "borrowed" buffer.
|
||||
// Delete the internal buffer only if it was declared as owned.
|
||||
if (m_data_owned)
|
||||
delete[](char*)m_PacketVector[PV_DATA].data();
|
||||
delete[](char*) m_PacketVector[PV_DATA].data();
|
||||
}
|
||||
|
||||
|
||||
size_t CPacket::getLength() const
|
||||
size_t srt::CPacket::getLength() const
|
||||
{
|
||||
return m_PacketVector[PV_DATA].size();
|
||||
return m_PacketVector[PV_DATA].size();
|
||||
}
|
||||
|
||||
void CPacket::setLength(size_t len)
|
||||
void srt::CPacket::setLength(size_t len)
|
||||
{
|
||||
m_PacketVector[PV_DATA].setLength(len);
|
||||
m_PacketVector[PV_DATA].setLength(len);
|
||||
}
|
||||
|
||||
void CPacket::pack(UDTMessageType pkttype, const void* lparam, void* rparam, int size)
|
||||
void srt::CPacket::pack(UDTMessageType pkttype, const int32_t* lparam, void* rparam, size_t size)
|
||||
{
|
||||
// Set (bit-0 = 1) and (bit-1~15 = type)
|
||||
setControl(pkttype);
|
||||
HLOGC(inlog.Debug,
|
||||
log << "pack: type=" << MessageTypeStr(pkttype) << " ARG=" << (lparam ? Sprint(*lparam) : std::string("NULL"))
|
||||
<< " [ " << (rparam ? Sprint(*(int32_t*)rparam) : std::string()) << " ]");
|
||||
|
||||
// Set additional information and control information field
|
||||
switch (pkttype)
|
||||
{
|
||||
case UMSG_ACK: //0010 - Acknowledgement (ACK)
|
||||
// ACK packet seq. no.
|
||||
if (NULL != lparam)
|
||||
m_nHeader[SRT_PH_MSGNO] = *(int32_t *)lparam;
|
||||
// Set additional information and control information field
|
||||
switch (pkttype)
|
||||
{
|
||||
case UMSG_ACK: // 0010 - Acknowledgement (ACK)
|
||||
// ACK packet seq. no.
|
||||
if (NULL != lparam)
|
||||
m_nHeader[SRT_PH_MSGNO] = *lparam;
|
||||
|
||||
// data ACK seq. no.
|
||||
// optional: RTT (microsends), RTT variance (microseconds) advertised flow window size (packets), and estimated link capacity (packets per second)
|
||||
m_PacketVector[PV_DATA].set(rparam, size);
|
||||
// data ACK seq. no.
|
||||
// optional: RTT (microsends), RTT variance (microseconds) advertised flow window size (packets), and estimated
|
||||
// link capacity (packets per second)
|
||||
m_PacketVector[PV_DATA].set(rparam, size);
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case UMSG_ACKACK: //0110 - Acknowledgement of Acknowledgement (ACK-2)
|
||||
// ACK packet seq. no.
|
||||
m_nHeader[SRT_PH_MSGNO] = *(int32_t *)lparam;
|
||||
case UMSG_ACKACK: // 0110 - Acknowledgement of Acknowledgement (ACK-2)
|
||||
// ACK packet seq. no.
|
||||
m_nHeader[SRT_PH_MSGNO] = *lparam;
|
||||
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[PV_DATA].set((void *)&__pad, 4);
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[PV_DATA].set((void*)&m_extra_pad, 4);
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case UMSG_LOSSREPORT: //0011 - Loss Report (NAK)
|
||||
// loss list
|
||||
m_PacketVector[PV_DATA].set(rparam, size);
|
||||
case UMSG_LOSSREPORT: // 0011 - Loss Report (NAK)
|
||||
// loss list
|
||||
m_PacketVector[PV_DATA].set(rparam, size);
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case UMSG_CGWARNING: //0100 - Congestion Warning
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[PV_DATA].set((void *)&__pad, 4);
|
||||
|
||||
break;
|
||||
case UMSG_CGWARNING: // 0100 - Congestion Warning
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[PV_DATA].set((void*)&m_extra_pad, 4);
|
||||
|
||||
case UMSG_KEEPALIVE: //0001 - Keep-alive
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[PV_DATA].set((void *)&__pad, 4);
|
||||
break;
|
||||
|
||||
break;
|
||||
case UMSG_KEEPALIVE: // 0001 - Keep-alive
|
||||
if (lparam)
|
||||
{
|
||||
// XXX EXPERIMENTAL. Pass the 32-bit integer here.
|
||||
m_nHeader[SRT_PH_MSGNO] = *lparam;
|
||||
}
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[PV_DATA].set((void*)&m_extra_pad, 4);
|
||||
|
||||
case UMSG_HANDSHAKE: //0000 - Handshake
|
||||
// control info filed is handshake info
|
||||
m_PacketVector[PV_DATA].set(rparam, size);
|
||||
break;
|
||||
|
||||
break;
|
||||
case UMSG_HANDSHAKE: // 0000 - Handshake
|
||||
// control info filed is handshake info
|
||||
m_PacketVector[PV_DATA].set(rparam, size);
|
||||
|
||||
case UMSG_SHUTDOWN: //0101 - Shutdown
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[PV_DATA].set((void *)&__pad, 4);
|
||||
break;
|
||||
|
||||
break;
|
||||
case UMSG_SHUTDOWN: // 0101 - Shutdown
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[PV_DATA].set((void*)&m_extra_pad, 4);
|
||||
|
||||
case UMSG_DROPREQ: //0111 - Message Drop Request
|
||||
// msg id
|
||||
m_nHeader[SRT_PH_MSGNO] = *(int32_t *)lparam;
|
||||
break;
|
||||
|
||||
//first seq no, last seq no
|
||||
m_PacketVector[PV_DATA].set(rparam, size);
|
||||
case UMSG_DROPREQ: // 0111 - Message Drop Request
|
||||
// msg id
|
||||
m_nHeader[SRT_PH_MSGNO] = *lparam;
|
||||
|
||||
break;
|
||||
// first seq no, last seq no
|
||||
m_PacketVector[PV_DATA].set(rparam, size);
|
||||
|
||||
case UMSG_PEERERROR: //1000 - Error Signal from the Peer Side
|
||||
// Error type
|
||||
m_nHeader[SRT_PH_MSGNO] = *(int32_t *)lparam;
|
||||
break;
|
||||
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[PV_DATA].set((void *)&__pad, 4);
|
||||
case UMSG_PEERERROR: // 1000 - Error Signal from the Peer Side
|
||||
// Error type
|
||||
m_nHeader[SRT_PH_MSGNO] = *lparam;
|
||||
|
||||
break;
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[PV_DATA].set((void*)&m_extra_pad, 4);
|
||||
|
||||
case UMSG_EXT: //0x7FFF - Reserved for user defined control packets
|
||||
// for extended control packet
|
||||
// "lparam" contains the extended type information for bit 16 - 31
|
||||
// "rparam" is the control information
|
||||
m_nHeader[SRT_PH_SEQNO] |= *(int32_t *)lparam;
|
||||
break;
|
||||
|
||||
if (NULL != rparam)
|
||||
{
|
||||
m_PacketVector[PV_DATA].set(rparam, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PacketVector[PV_DATA].set((void *)&__pad, 4);
|
||||
}
|
||||
case UMSG_EXT: // 0x7FFF - Reserved for user defined control packets
|
||||
// for extended control packet
|
||||
// "lparam" contains the extended type information for bit 16 - 31
|
||||
// "rparam" is the control information
|
||||
m_nHeader[SRT_PH_SEQNO] |= *lparam;
|
||||
|
||||
break;
|
||||
if (NULL != rparam)
|
||||
{
|
||||
m_PacketVector[PV_DATA].set(rparam, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PacketVector[PV_DATA].set((void*)&m_extra_pad, 4);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IOVector* CPacket::getPacketVector()
|
||||
void srt::CPacket::toNL()
|
||||
{
|
||||
return m_PacketVector;
|
||||
// XXX USE HtoNLA!
|
||||
if (isControl())
|
||||
{
|
||||
for (ptrdiff_t i = 0, n = getLength() / 4; i < n; ++i)
|
||||
*((uint32_t*)m_pcData + i) = htonl(*((uint32_t*)m_pcData + i));
|
||||
}
|
||||
|
||||
// convert packet header into network order
|
||||
uint32_t* p = m_nHeader;
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
*p = htonl(*p);
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
UDTMessageType CPacket::getType() const
|
||||
void srt::CPacket::toHL()
|
||||
{
|
||||
// convert back into local host order
|
||||
uint32_t* p = m_nHeader;
|
||||
for (int k = 0; k < 4; ++k)
|
||||
{
|
||||
*p = ntohl(*p);
|
||||
++p;
|
||||
}
|
||||
|
||||
if (isControl())
|
||||
{
|
||||
for (ptrdiff_t l = 0, n = getLength() / 4; l < n; ++l)
|
||||
*((uint32_t*)m_pcData + l) = ntohl(*((uint32_t*)m_pcData + l));
|
||||
}
|
||||
}
|
||||
|
||||
srt::IOVector* srt::CPacket::getPacketVector()
|
||||
{
|
||||
return m_PacketVector;
|
||||
}
|
||||
|
||||
srt::UDTMessageType srt::CPacket::getType() const
|
||||
{
|
||||
return UDTMessageType(SEQNO_MSGTYPE::unwrap(m_nHeader[SRT_PH_SEQNO]));
|
||||
}
|
||||
|
||||
int CPacket::getExtendedType() const
|
||||
int srt::CPacket::getExtendedType() const
|
||||
{
|
||||
return SEQNO_EXTTYPE::unwrap(m_nHeader[SRT_PH_SEQNO]);
|
||||
}
|
||||
|
||||
int32_t CPacket::getAckSeqNo() const
|
||||
int32_t srt::CPacket::getAckSeqNo() const
|
||||
{
|
||||
// read additional information field
|
||||
// This field is used only in UMSG_ACK and UMSG_ACKACK,
|
||||
// so 'getAckSeqNo' symbolically defines the only use of it
|
||||
// in case of CONTROL PACKET.
|
||||
return m_nHeader[SRT_PH_MSGNO];
|
||||
// read additional information field
|
||||
// This field is used only in UMSG_ACK and UMSG_ACKACK,
|
||||
// so 'getAckSeqNo' symbolically defines the only use of it
|
||||
// in case of CONTROL PACKET.
|
||||
return m_nHeader[SRT_PH_MSGNO];
|
||||
}
|
||||
|
||||
uint16_t CPacket::getControlFlags() const
|
||||
uint16_t srt::CPacket::getControlFlags() const
|
||||
{
|
||||
// This returns exactly the "extended type" value,
|
||||
// which is not used at all in case when the standard
|
||||
|
@ -360,19 +432,19 @@ uint16_t CPacket::getControlFlags() const
|
|||
return SEQNO_EXTTYPE::unwrap(m_nHeader[SRT_PH_SEQNO]);
|
||||
}
|
||||
|
||||
PacketBoundary CPacket::getMsgBoundary() const
|
||||
srt::PacketBoundary srt::CPacket::getMsgBoundary() const
|
||||
{
|
||||
return PacketBoundary(MSGNO_PACKET_BOUNDARY::unwrap(m_nHeader[SRT_PH_MSGNO]));
|
||||
}
|
||||
|
||||
bool CPacket::getMsgOrderFlag() const
|
||||
bool srt::CPacket::getMsgOrderFlag() const
|
||||
{
|
||||
return 0!= MSGNO_PACKET_INORDER::unwrap(m_nHeader[SRT_PH_MSGNO]);
|
||||
return 0 != MSGNO_PACKET_INORDER::unwrap(m_nHeader[SRT_PH_MSGNO]);
|
||||
}
|
||||
|
||||
int32_t CPacket::getMsgSeq(bool has_rexmit) const
|
||||
int32_t srt::CPacket::getMsgSeq(bool has_rexmit) const
|
||||
{
|
||||
if ( has_rexmit )
|
||||
if (has_rexmit)
|
||||
{
|
||||
return MSGNO_SEQ::unwrap(m_nHeader[SRT_PH_MSGNO]);
|
||||
}
|
||||
|
@ -382,13 +454,13 @@ int32_t CPacket::getMsgSeq(bool has_rexmit) const
|
|||
}
|
||||
}
|
||||
|
||||
bool CPacket::getRexmitFlag() const
|
||||
bool srt::CPacket::getRexmitFlag() const
|
||||
{
|
||||
// return false; //
|
||||
return 0 != MSGNO_REXMIT::unwrap(m_nHeader[SRT_PH_MSGNO]);
|
||||
return 0 != MSGNO_REXMIT::unwrap(m_nHeader[SRT_PH_MSGNO]);
|
||||
}
|
||||
|
||||
EncryptionKeySpec CPacket::getMsgCryptoFlags() const
|
||||
srt::EncryptionKeySpec srt::CPacket::getMsgCryptoFlags() const
|
||||
{
|
||||
return EncryptionKeySpec(MSGNO_ENCKEYSPEC::unwrap(m_nHeader[SRT_PH_MSGNO]));
|
||||
}
|
||||
|
@ -396,82 +468,31 @@ EncryptionKeySpec CPacket::getMsgCryptoFlags() const
|
|||
// This is required as the encryption/decryption happens in place.
|
||||
// This is required to clear off the flags after decryption or set
|
||||
// crypto flags after encrypting a packet.
|
||||
void CPacket::setMsgCryptoFlags(EncryptionKeySpec spec)
|
||||
void srt::CPacket::setMsgCryptoFlags(EncryptionKeySpec spec)
|
||||
{
|
||||
int32_t clr_msgno = m_nHeader[SRT_PH_MSGNO] & ~MSGNO_ENCKEYSPEC::mask;
|
||||
int32_t clr_msgno = m_nHeader[SRT_PH_MSGNO] & ~MSGNO_ENCKEYSPEC::mask;
|
||||
m_nHeader[SRT_PH_MSGNO] = clr_msgno | EncryptionKeyBits(spec);
|
||||
}
|
||||
|
||||
/*
|
||||
Leaving old code for historical reasons. This is moved to CSRTCC.
|
||||
EncryptionStatus CPacket::encrypt(HaiCrypt_Handle hcrypto)
|
||||
uint32_t srt::CPacket::getMsgTimeStamp() const
|
||||
{
|
||||
if ( !hcrypto )
|
||||
{
|
||||
LOGC(mglog.Error, log << "IPE: NULL crypto passed to CPacket::encrypt!");
|
||||
return ENCS_FAILED;
|
||||
}
|
||||
|
||||
int rc = HaiCrypt_Tx_Data(hcrypto, (uint8_t *)m_nHeader.raw(), (uint8_t *)m_pcData, m_PacketVector[PV_DATA].iov_len);
|
||||
if ( rc < 0 )
|
||||
{
|
||||
// -1: encryption failure
|
||||
// 0: key not received yet
|
||||
return ENCS_FAILED;
|
||||
} else if (rc > 0) {
|
||||
m_PacketVector[PV_DATA].iov_len = rc;
|
||||
}
|
||||
return ENCS_CLEAR;
|
||||
// SRT_DEBUG_TSBPD_WRAP may enable smaller timestamp for faster wraparoud handling tests
|
||||
return (uint32_t)m_nHeader[SRT_PH_TIMESTAMP] & TIMESTAMP_MASK;
|
||||
}
|
||||
|
||||
EncryptionStatus CPacket::decrypt(HaiCrypt_Handle hcrypto)
|
||||
srt::CPacket* srt::CPacket::clone() const
|
||||
{
|
||||
if (getMsgCryptoFlags() == EK_NOENC)
|
||||
{
|
||||
//HLOGC(mglog.Debug, log << "CPacket::decrypt: packet not encrypted");
|
||||
return ENCS_CLEAR; // not encrypted, no need do decrypt, no flags to be modified
|
||||
}
|
||||
CPacket* pkt = new CPacket;
|
||||
memcpy((pkt->m_nHeader), m_nHeader, HDR_SIZE);
|
||||
pkt->m_pcData = new char[m_PacketVector[PV_DATA].size()];
|
||||
memcpy((pkt->m_pcData), m_pcData, m_PacketVector[PV_DATA].size());
|
||||
pkt->m_PacketVector[PV_DATA].setLength(m_PacketVector[PV_DATA].size());
|
||||
|
||||
if (!hcrypto)
|
||||
{
|
||||
LOGC(mglog.Error, log << "IPE: NULL crypto passed to CPacket::decrypt!");
|
||||
return ENCS_FAILED; // "invalid argument" (leave encryption flags untouched)
|
||||
}
|
||||
|
||||
int rc = HaiCrypt_Rx_Data(hcrypto, (uint8_t *)m_nHeader.raw(), (uint8_t *)m_pcData, m_PacketVector[PV_DATA].iov_len);
|
||||
if ( rc <= 0 )
|
||||
{
|
||||
// -1: decryption failure
|
||||
// 0: key not received yet
|
||||
return ENCS_FAILED;
|
||||
}
|
||||
// Otherwise: rc == decrypted text length.
|
||||
m_PacketVector[PV_DATA].iov_len = rc; // In case clr txt size is different from cipher txt
|
||||
|
||||
// Decryption succeeded. Update flags.
|
||||
m_nHeader[SRT_PH_MSGNO] &= ~MSGNO_ENCKEYSPEC::mask; // sets EK_NOENC to ENCKEYSPEC bits.
|
||||
|
||||
return ENCS_CLEAR;
|
||||
return pkt;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
uint32_t CPacket::getMsgTimeStamp() const
|
||||
namespace srt
|
||||
{
|
||||
// SRT_DEBUG_TSBPD_WRAP may enable smaller timestamp for faster wraparoud handling tests
|
||||
return (uint32_t)m_nHeader[SRT_PH_TIMESTAMP] & TIMESTAMP_MASK;
|
||||
}
|
||||
|
||||
CPacket* CPacket::clone() const
|
||||
{
|
||||
CPacket* pkt = new CPacket;
|
||||
memcpy(pkt->m_nHeader, m_nHeader, HDR_SIZE);
|
||||
pkt->m_pcData = new char[m_PacketVector[PV_DATA].size()];
|
||||
memcpy(pkt->m_pcData, m_pcData, m_PacketVector[PV_DATA].size());
|
||||
pkt->m_PacketVector[PV_DATA].setLength(m_PacketVector[PV_DATA].size());
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
// Useful for debugging
|
||||
std::string PacketMessageFlagStr(uint32_t msgno_field)
|
||||
|
@ -480,10 +501,10 @@ std::string PacketMessageFlagStr(uint32_t msgno_field)
|
|||
|
||||
stringstream out;
|
||||
|
||||
static const char* const boundary [] = { "PB_SUBSEQUENT", "PB_LAST", "PB_FIRST", "PB_SOLO" };
|
||||
static const char* const order [] = { "ORD_RELAXED", "ORD_REQUIRED" };
|
||||
static const char* const crypto [] = { "EK_NOENC", "EK_EVEN", "EK_ODD", "EK*ERROR" };
|
||||
static const char* const rexmit [] = { "SN_ORIGINAL", "SN_REXMIT" };
|
||||
static const char* const boundary[] = {"PB_SUBSEQUENT", "PB_LAST", "PB_FIRST", "PB_SOLO"};
|
||||
static const char* const order[] = {"ORD_RELAXED", "ORD_REQUIRED"};
|
||||
static const char* const crypto[] = {"EK_NOENC", "EK_EVEN", "EK_ODD", "EK*ERROR"};
|
||||
static const char* const rexmit[] = {"SN_ORIGINAL", "SN_REXMIT"};
|
||||
|
||||
out << boundary[MSGNO_PACKET_BOUNDARY::unwrap(msgno_field)] << " ";
|
||||
out << order[MSGNO_PACKET_INORDER::unwrap(msgno_field)] << " ";
|
||||
|
@ -492,3 +513,70 @@ std::string PacketMessageFlagStr(uint32_t msgno_field)
|
|||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
inline void SprintSpecialWord(std::ostream& os, int32_t val)
|
||||
{
|
||||
if (val & LOSSDATA_SEQNO_RANGE_FIRST)
|
||||
os << "<" << (val & (~LOSSDATA_SEQNO_RANGE_FIRST)) << ">";
|
||||
else
|
||||
os << val;
|
||||
}
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#if ENABLE_LOGGING
|
||||
std::string srt::CPacket::Info()
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "TARGET=@" << m_iID << " ";
|
||||
|
||||
if (isControl())
|
||||
{
|
||||
os << "CONTROL: size=" << getLength() << " type=" << MessageTypeStr(getType(), getExtendedType());
|
||||
|
||||
if (getType() == UMSG_HANDSHAKE)
|
||||
{
|
||||
os << " HS: ";
|
||||
// For handshake we already have a parsing method
|
||||
CHandShake hs;
|
||||
hs.load_from(m_pcData, getLength());
|
||||
os << hs.show();
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a value that some messages use for some purposes.
|
||||
// The "ack seq no" is one of the purposes, used by UMSG_ACK and UMSG_ACKACK.
|
||||
// This is simply the SRT_PH_MSGNO field used as a message number in data packets.
|
||||
os << " ARG: 0x";
|
||||
os << std::hex << getAckSeqNo() << " ";
|
||||
os << std::dec << getAckSeqNo();
|
||||
|
||||
// It would be nice to see the extended packet data, but this
|
||||
// requires strictly a message-dependent interpreter. So let's simply
|
||||
// display all numbers in the array with the following restrictions:
|
||||
// - all data contained in the buffer are considered 32-bit integer
|
||||
// - sign flag will be cleared before displaying, with additional mark
|
||||
size_t wordlen = getLength() / 4; // drop any remainder if present
|
||||
int32_t* array = (int32_t*)m_pcData;
|
||||
os << " [ ";
|
||||
for (size_t i = 0; i < wordlen; ++i)
|
||||
{
|
||||
SprintSpecialWord(os, array[i]);
|
||||
os << " ";
|
||||
}
|
||||
os << "]";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's hard to extract the information about peer's supported rexmit flag.
|
||||
// This is only a log, nothing crucial, so we can risk displaying incorrect message number.
|
||||
// Declaring that the peer supports rexmit flag cuts off the highest bit from
|
||||
// the displayed number.
|
||||
os << "DATA: size=" << getLength() << " " << BufferStamp(m_pcData, getLength()) << " #" << getMsgSeq(true)
|
||||
<< " %" << getSeqNo() << " " << MessageFlagStr();
|
||||
}
|
||||
|
||||
return os.str();
|
||||
}
|
||||
#endif
|
||||
|
|
383
trunk/3rdparty/srt-1-fit/srtcore/packet.h
vendored
383
trunk/3rdparty/srt-1-fit/srtcore/packet.h
vendored
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* SRT - Secure Reliable Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -50,86 +50,85 @@ modified by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_PACKET_H__
|
||||
#define __UDT_PACKET_H__
|
||||
#ifndef INC_SRT_PACKET_H
|
||||
#define INC_SRT_PACKET_H
|
||||
|
||||
#include "udt.h"
|
||||
#include "common.h"
|
||||
#include "utilities.h"
|
||||
#include "netinet_any.h"
|
||||
#include "packetfilter_api.h"
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// The purpose of the IOVector class is to proide a platform-independet interface
|
||||
// to the WSABUF on Windows and iovec on Linux, that can be easilly converted
|
||||
// to the native structure for use in WSARecvFrom() and recvmsg(...) functions
|
||||
// to the native structure for use in WSARecvFrom() and recvmsg(...) functions
|
||||
class IOVector
|
||||
#ifdef _WIN32
|
||||
: public WSABUF
|
||||
: public WSABUF
|
||||
#else
|
||||
: public iovec
|
||||
: public iovec
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
|
||||
inline void set(void *buffer, size_t length)
|
||||
{
|
||||
inline void set(void* buffer, size_t length)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
len = (ULONG)length;
|
||||
buf = (CHAR*)buffer;
|
||||
len = (ULONG)length;
|
||||
buf = (CHAR*)buffer;
|
||||
#else
|
||||
iov_base = (void*)buffer;
|
||||
iov_len = length;
|
||||
iov_base = (void*)buffer;
|
||||
iov_len = length;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline char*& dataRef()
|
||||
{
|
||||
inline char*& dataRef()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return buf;
|
||||
return buf;
|
||||
#else
|
||||
return (char*&) iov_base;
|
||||
return (char*&)iov_base;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline char* data()
|
||||
{
|
||||
inline char* data()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return buf;
|
||||
return buf;
|
||||
#else
|
||||
return (char*)iov_base;
|
||||
return (char*)iov_base;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline size_t size() const
|
||||
{
|
||||
inline size_t size() const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (size_t) len;
|
||||
return (size_t)len;
|
||||
#else
|
||||
return iov_len;
|
||||
return iov_len;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline void setLength(size_t length)
|
||||
{
|
||||
inline void setLength(size_t length)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
len = length;
|
||||
len = (ULONG)length;
|
||||
#else
|
||||
iov_len = length;
|
||||
iov_len = length;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// To define packets in order in the buffer. This is public due to being used in buffer.
|
||||
enum PacketBoundary
|
||||
{
|
||||
PB_SUBSEQUENT = 0, // 00
|
||||
/// 01: last packet of a message
|
||||
PB_LAST = 1, // 01
|
||||
/// 10: first packet of a message
|
||||
PB_FIRST = 2, // 10
|
||||
/// 11: solo message packet
|
||||
PB_SOLO = 3, // 11
|
||||
PB_SUBSEQUENT = 0, // 00: a packet in the middle of a message, neither the first, not the last.
|
||||
PB_LAST = 1, // 01: last packet of a message
|
||||
PB_FIRST = 2, // 10: first packet of a message
|
||||
PB_SOLO = 3, // 11: solo message packet
|
||||
};
|
||||
|
||||
// Breakdown of the PM_SEQNO field in the header:
|
||||
|
@ -137,7 +136,7 @@ enum PacketBoundary
|
|||
typedef Bits<31> SEQNO_CONTROL;
|
||||
// 1|T T T T T T T T T T T T T T T|E E...E
|
||||
typedef Bits<30, 16> SEQNO_MSGTYPE;
|
||||
typedef Bits<15, 0> SEQNO_EXTTYPE;
|
||||
typedef Bits<15, 0> SEQNO_EXTTYPE;
|
||||
// 0|S S ... S
|
||||
typedef Bits<30, 0> SEQNO_VALUE;
|
||||
|
||||
|
@ -161,11 +160,11 @@ inline int32_t CreateControlExtSeqNo(int exttype)
|
|||
|
||||
// MSGNO breakdown: B B|O|K K|R|M M M M M M M M M M...M
|
||||
typedef Bits<31, 30> MSGNO_PACKET_BOUNDARY;
|
||||
typedef Bits<29> MSGNO_PACKET_INORDER;
|
||||
typedef Bits<29> MSGNO_PACKET_INORDER;
|
||||
typedef Bits<28, 27> MSGNO_ENCKEYSPEC;
|
||||
#if 1 // can block rexmit flag
|
||||
// New bit breakdown - rexmit flag supported.
|
||||
typedef Bits<26> MSGNO_REXMIT;
|
||||
typedef Bits<26> MSGNO_REXMIT;
|
||||
typedef Bits<25, 0> MSGNO_SEQ;
|
||||
// Old bit breakdown - no rexmit flag
|
||||
typedef Bits<26, 0> MSGNO_SEQ_OLD;
|
||||
|
@ -173,32 +172,36 @@ typedef Bits<26, 0> MSGNO_SEQ_OLD;
|
|||
// The message should be extracted as PMASK_MSGNO_SEQ, if REXMIT is supported, and PMASK_MSGNO_SEQ_OLD otherwise.
|
||||
|
||||
const uint32_t PACKET_SND_NORMAL = 0, PACKET_SND_REXMIT = MSGNO_REXMIT::mask;
|
||||
const int MSGNO_SEQ_MAX = MSGNO_SEQ::mask;
|
||||
|
||||
#else
|
||||
// Old bit breakdown - no rexmit flag
|
||||
typedef Bits<26, 0> MSGNO_SEQ;
|
||||
#endif
|
||||
|
||||
typedef RollNumber<MSGNO_SEQ::size - 1, 1> MsgNo;
|
||||
|
||||
// constexpr in C++11 !
|
||||
inline int32_t PacketBoundaryBits(PacketBoundary o) { return MSGNO_PACKET_BOUNDARY::wrap(int32_t(o)); }
|
||||
|
||||
inline int32_t PacketBoundaryBits(PacketBoundary o)
|
||||
{
|
||||
return MSGNO_PACKET_BOUNDARY::wrap(int32_t(o));
|
||||
}
|
||||
|
||||
enum EncryptionKeySpec
|
||||
{
|
||||
EK_NOENC = 0,
|
||||
EK_EVEN = 1,
|
||||
EK_ODD = 2
|
||||
EK_EVEN = 1,
|
||||
EK_ODD = 2
|
||||
};
|
||||
|
||||
enum EncryptionStatus
|
||||
{
|
||||
ENCS_CLEAR = 0,
|
||||
ENCS_CLEAR = 0,
|
||||
ENCS_FAILED = -1,
|
||||
ENCS_NOTSUP = -2
|
||||
};
|
||||
|
||||
const int32_t PMASK_MSGNO_ENCKEYSPEC = MSGNO_ENCKEYSPEC::mask;
|
||||
const int32_t PMASK_MSGNO_ENCKEYSPEC = MSGNO_ENCKEYSPEC::mask;
|
||||
inline int32_t EncryptionKeyBits(EncryptionKeySpec f)
|
||||
{
|
||||
return MSGNO_ENCKEYSPEC::wrap(int32_t(f));
|
||||
|
@ -212,210 +215,170 @@ const int32_t PUMASK_SEQNO_PROBE = 0xF;
|
|||
|
||||
std::string PacketMessageFlagStr(uint32_t msgno_field);
|
||||
|
||||
class CChannel;
|
||||
|
||||
class CPacket
|
||||
{
|
||||
friend class CChannel;
|
||||
friend class CSndQueue;
|
||||
friend class CRcvQueue;
|
||||
friend class CChannel;
|
||||
friend class CSndQueue;
|
||||
friend class CRcvQueue;
|
||||
|
||||
public:
|
||||
CPacket();
|
||||
~CPacket();
|
||||
CPacket();
|
||||
~CPacket();
|
||||
|
||||
void allocate(size_t size);
|
||||
void deallocate();
|
||||
void allocate(size_t size);
|
||||
void deallocate();
|
||||
|
||||
/// Get the payload or the control information field length.
|
||||
/// @return the payload or the control information field length.
|
||||
/// Get the payload or the control information field length.
|
||||
/// @return the payload or the control information field length.
|
||||
size_t getLength() const;
|
||||
|
||||
size_t getLength() const;
|
||||
/// Set the payload or the control information field length.
|
||||
/// @param len [in] the payload or the control information field length.
|
||||
void setLength(size_t len);
|
||||
|
||||
/// Set the payload or the control information field length.
|
||||
/// @param len [in] the payload or the control information field length.
|
||||
/// Pack a Control packet.
|
||||
/// @param pkttype [in] packet type filed.
|
||||
/// @param lparam [in] pointer to the first data structure, explained by the packet type.
|
||||
/// @param rparam [in] pointer to the second data structure, explained by the packet type.
|
||||
/// @param size [in] size of rparam, in number of bytes;
|
||||
void pack(UDTMessageType pkttype, const int32_t* lparam = NULL, void* rparam = NULL, size_t size = 0);
|
||||
|
||||
void setLength(size_t len);
|
||||
/// Read the packet vector.
|
||||
/// @return Pointer to the packet vector.
|
||||
IOVector* getPacketVector();
|
||||
|
||||
/// Pack a Control packet.
|
||||
/// @param pkttype [in] packet type filed.
|
||||
/// @param lparam [in] pointer to the first data structure, explained by the packet type.
|
||||
/// @param rparam [in] pointer to the second data structure, explained by the packet type.
|
||||
/// @param size [in] size of rparam, in number of bytes;
|
||||
uint32_t* getHeader() { return m_nHeader; }
|
||||
|
||||
void pack(UDTMessageType pkttype, const void* lparam = NULL, void* rparam = NULL, int size = 0);
|
||||
/// Read the packet type.
|
||||
/// @return packet type filed (000 ~ 111).
|
||||
UDTMessageType getType() const;
|
||||
|
||||
/// Read the packet vector.
|
||||
/// @return Pointer to the packet vector.
|
||||
bool isControl(UDTMessageType type) const { return isControl() && type == getType(); }
|
||||
|
||||
IOVector* getPacketVector();
|
||||
bool isControl() const { return 0 != SEQNO_CONTROL::unwrap(m_nHeader[SRT_PH_SEQNO]); }
|
||||
|
||||
uint32_t* getHeader() { return m_nHeader; }
|
||||
void setControl(UDTMessageType type) { m_nHeader[SRT_PH_SEQNO] = SEQNO_CONTROL::mask | SEQNO_MSGTYPE::wrap(type); }
|
||||
|
||||
/// Read the packet flag.
|
||||
/// @return packet flag (0 or 1).
|
||||
/// Read the extended packet type.
|
||||
/// @return extended packet type filed (0x000 ~ 0xFFF).
|
||||
int getExtendedType() const;
|
||||
|
||||
// XXX DEPRECATED. Use isControl() instead
|
||||
ATR_DEPRECATED
|
||||
int getFlag() const
|
||||
{
|
||||
return isControl() ? 1 : 0;
|
||||
}
|
||||
/// Read the ACK-2 seq. no.
|
||||
/// @return packet header field (bit 16~31).
|
||||
int32_t getAckSeqNo() const;
|
||||
|
||||
/// Read the packet type.
|
||||
/// @return packet type filed (000 ~ 111).
|
||||
uint16_t getControlFlags() const;
|
||||
|
||||
UDTMessageType getType() const;
|
||||
// Note: this will return a "singular" value, if the packet
|
||||
// contains the control message
|
||||
int32_t getSeqNo() const { return m_nHeader[SRT_PH_SEQNO]; }
|
||||
|
||||
bool isControl(UDTMessageType type) const
|
||||
{
|
||||
return isControl() && type == getType();
|
||||
}
|
||||
/// Read the message boundary flag bit.
|
||||
/// @return packet header field [1] (bit 0~1).
|
||||
PacketBoundary getMsgBoundary() const;
|
||||
|
||||
bool isControl() const
|
||||
{
|
||||
// read bit 0
|
||||
return 0!= SEQNO_CONTROL::unwrap(m_nHeader[SRT_PH_SEQNO]);
|
||||
}
|
||||
/// Read the message inorder delivery flag bit.
|
||||
/// @return packet header field [1] (bit 2).
|
||||
bool getMsgOrderFlag() const;
|
||||
|
||||
void setControl(UDTMessageType type)
|
||||
{
|
||||
m_nHeader[SRT_PH_SEQNO] = SEQNO_CONTROL::mask | SEQNO_MSGTYPE::wrap(type);
|
||||
}
|
||||
/// Read the rexmit flag (true if the packet was sent due to retransmission).
|
||||
/// If the peer does not support retransmission flag, the current agent cannot use it as well
|
||||
/// (because the peer will understand this bit as a part of MSGNO field).
|
||||
bool getRexmitFlag() const;
|
||||
|
||||
/// Read the extended packet type.
|
||||
/// @return extended packet type filed (0x000 ~ 0xFFF).
|
||||
/// Read the message sequence number.
|
||||
/// @return packet header field [1]
|
||||
int32_t getMsgSeq(bool has_rexmit = true) const;
|
||||
|
||||
int getExtendedType() const;
|
||||
/// Read the message crypto key bits.
|
||||
/// @return packet header field [1] (bit 3~4).
|
||||
EncryptionKeySpec getMsgCryptoFlags() const;
|
||||
|
||||
/// Read the ACK-2 seq. no.
|
||||
/// @return packet header field (bit 16~31).
|
||||
void setMsgCryptoFlags(EncryptionKeySpec spec);
|
||||
|
||||
int32_t getAckSeqNo() const;
|
||||
uint16_t getControlFlags() const;
|
||||
/// Read the message time stamp.
|
||||
/// @return packet header field [2] (bit 0~31, bit 0-26 if SRT_DEBUG_TSBPD_WRAP).
|
||||
uint32_t getMsgTimeStamp() const;
|
||||
|
||||
// Note: this will return a "singular" value, if the packet
|
||||
// contains the control message
|
||||
int32_t getSeqNo() const
|
||||
{
|
||||
return m_nHeader[SRT_PH_SEQNO];
|
||||
}
|
||||
|
||||
/// Read the message boundary flag bit.
|
||||
/// @return packet header field [1] (bit 0~1).
|
||||
|
||||
PacketBoundary getMsgBoundary() const;
|
||||
|
||||
/// Read the message inorder delivery flag bit.
|
||||
/// @return packet header field [1] (bit 2).
|
||||
|
||||
bool getMsgOrderFlag() const;
|
||||
|
||||
/// Read the rexmit flag (true if the packet was sent due to retransmission).
|
||||
/// If the peer does not support retransmission flag, the current agent cannot use it as well
|
||||
/// (because the peer will understand this bit as a part of MSGNO field).
|
||||
|
||||
bool getRexmitFlag() const;
|
||||
|
||||
/// Read the message sequence number.
|
||||
/// @return packet header field [1]
|
||||
|
||||
int32_t getMsgSeq(bool has_rexmit = true) const;
|
||||
|
||||
/// Read the message crypto key bits.
|
||||
/// @return packet header field [1] (bit 3~4).
|
||||
|
||||
EncryptionKeySpec getMsgCryptoFlags() const;
|
||||
void setMsgCryptoFlags(EncryptionKeySpec spec);
|
||||
|
||||
/// Read the message time stamp.
|
||||
/// @return packet header field [2] (bit 0~31, bit 0-26 if SRT_DEBUG_TSBPD_WRAP).
|
||||
|
||||
uint32_t getMsgTimeStamp() const;
|
||||
|
||||
#ifdef SRT_DEBUG_TSBPD_WRAP //Receiver
|
||||
static const uint32_t MAX_TIMESTAMP = 0x07FFFFFF; //27 bit fast wraparound for tests (~2m15s)
|
||||
#ifdef SRT_DEBUG_TSBPD_WRAP // Receiver
|
||||
static const uint32_t MAX_TIMESTAMP = 0x07FFFFFF; // 27 bit fast wraparound for tests (~2m15s)
|
||||
#else
|
||||
static const uint32_t MAX_TIMESTAMP = 0xFFFFFFFF; //Full 32 bit (01h11m35s)
|
||||
static const uint32_t MAX_TIMESTAMP = 0xFFFFFFFF; // Full 32 bit (01h11m35s)
|
||||
#endif
|
||||
|
||||
protected:
|
||||
static const uint32_t TIMESTAMP_MASK = MAX_TIMESTAMP; // this value to be also used as a mask
|
||||
static const uint32_t TIMESTAMP_MASK = MAX_TIMESTAMP; // this value to be also used as a mask
|
||||
public:
|
||||
/// Clone this packet.
|
||||
/// @return Pointer to the new packet.
|
||||
CPacket* clone() const;
|
||||
|
||||
/// Clone this packet.
|
||||
/// @return Pointer to the new packet.
|
||||
enum PacketVectorFields
|
||||
{
|
||||
PV_HEADER = 0,
|
||||
PV_DATA = 1,
|
||||
|
||||
CPacket* clone() const;
|
||||
|
||||
enum PacketVectorFields
|
||||
{
|
||||
PV_HEADER = 0,
|
||||
PV_DATA = 1,
|
||||
|
||||
PV_SIZE = 2
|
||||
};
|
||||
|
||||
protected:
|
||||
// Length in bytes
|
||||
|
||||
// DynamicStruct is the same as array of given type and size, just it
|
||||
// enforces that you index it using a symbol from symbolic enum type, not by a bare integer.
|
||||
|
||||
typedef DynamicStruct<uint32_t, SRT_PH__SIZE, SrtPktHeaderFields> HEADER_TYPE;
|
||||
HEADER_TYPE m_nHeader; //< The 128-bit header field
|
||||
|
||||
// XXX NOTE: iovec here is not portable. On Windows there's a different
|
||||
// (although similar) structure defined, which means that this way the
|
||||
// Windows function that is an equivalent of `recvmsg` cannot be used.
|
||||
// For example, something like that:
|
||||
// class IoVector: public iovec { public: size_t size() { return iov_len; } char* data() { return iov_base; } };
|
||||
// class IoVector: public WSAMSG { public: size_t size() { return len; } char* data() { return buf; } };
|
||||
IOVector m_PacketVector[PV_SIZE]; //< The 2-demension vector of UDT packet [header, data]
|
||||
|
||||
int32_t __pad;
|
||||
bool m_data_owned;
|
||||
|
||||
protected:
|
||||
CPacket& operator=(const CPacket&);
|
||||
CPacket (const CPacket&);
|
||||
PV_SIZE = 2
|
||||
};
|
||||
|
||||
public:
|
||||
void toNL();
|
||||
void toHL();
|
||||
|
||||
int32_t& m_iSeqNo; // alias: sequence number
|
||||
int32_t& m_iMsgNo; // alias: message number
|
||||
int32_t& m_iTimeStamp; // alias: timestamp
|
||||
int32_t& m_iID; // alias: socket ID
|
||||
char*& m_pcData; // alias: data/control information
|
||||
protected:
|
||||
// DynamicStruct is the same as array of given type and size, just it
|
||||
// enforces that you index it using a symbol from symbolic enum type, not by a bare integer.
|
||||
typedef DynamicStruct<uint32_t, SRT_PH_E_SIZE, SrtPktHeaderFields> HEADER_TYPE;
|
||||
HEADER_TYPE m_nHeader; //< The 128-bit header field
|
||||
|
||||
//static const int m_iPktHdrSize; // packet header size
|
||||
static const size_t HDR_SIZE = sizeof(HEADER_TYPE); // packet header size = SRT_PH__SIZE * sizeof(uint32_t)
|
||||
IOVector m_PacketVector[PV_SIZE]; //< The two-dimensional vector of an SRT packet [header, data]
|
||||
|
||||
// Used in many computations
|
||||
// Actually this can be also calculated as: sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr).
|
||||
static const size_t UDP_HDR_SIZE = 28; // 20 bytes IPv4 + 8 bytes of UDP { u16 sport, dport, len, csum }.
|
||||
int32_t m_extra_pad;
|
||||
bool m_data_owned;
|
||||
|
||||
static const size_t SRT_DATA_HDR_SIZE = UDP_HDR_SIZE + HDR_SIZE;
|
||||
protected:
|
||||
CPacket& operator=(const CPacket&);
|
||||
CPacket(const CPacket&);
|
||||
|
||||
// Some well known data
|
||||
static const size_t ETH_MAX_MTU_SIZE = 1500;
|
||||
public:
|
||||
int32_t& m_iSeqNo; // alias: sequence number
|
||||
int32_t& m_iMsgNo; // alias: message number
|
||||
int32_t& m_iTimeStamp; // alias: timestamp
|
||||
int32_t& m_iID; // alias: destination SRT socket ID
|
||||
char*& m_pcData; // alias: payload (data packet) / control information fields (control packet)
|
||||
|
||||
// And derived
|
||||
static const size_t SRT_MAX_PAYLOAD_SIZE = ETH_MAX_MTU_SIZE - SRT_DATA_HDR_SIZE;
|
||||
// Experimental: sometimes these references don't work!
|
||||
char* getData();
|
||||
char* release();
|
||||
|
||||
// Packet interface
|
||||
char* data() { return m_pcData; }
|
||||
const char* data() const { return m_pcData; }
|
||||
size_t size() const { return getLength(); }
|
||||
uint32_t header(SrtPktHeaderFields field) const { return m_nHeader[field]; }
|
||||
static const size_t HDR_SIZE = sizeof(HEADER_TYPE); // packet header size = SRT_PH_E_SIZE * sizeof(uint32_t)
|
||||
|
||||
// Can also be calculated as: sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr).
|
||||
static const size_t UDP_HDR_SIZE = 28; // 20 bytes IPv4 + 8 bytes of UDP { u16 sport, dport, len, csum }.
|
||||
|
||||
static const size_t SRT_DATA_HDR_SIZE = UDP_HDR_SIZE + HDR_SIZE;
|
||||
|
||||
// Maximum transmission unit size. 1500 in case of Ethernet II (RFC 1191).
|
||||
static const size_t ETH_MAX_MTU_SIZE = 1500;
|
||||
|
||||
// Maximum payload size of an SRT packet.
|
||||
static const size_t SRT_MAX_PAYLOAD_SIZE = ETH_MAX_MTU_SIZE - SRT_DATA_HDR_SIZE;
|
||||
|
||||
// Packet interface
|
||||
char* data() { return m_pcData; }
|
||||
const char* data() const { return m_pcData; }
|
||||
size_t size() const { return getLength(); }
|
||||
uint32_t header(SrtPktHeaderFields field) const { return m_nHeader[field]; }
|
||||
|
||||
std::string MessageFlagStr()
|
||||
#if ENABLE_LOGGING
|
||||
{ return PacketMessageFlagStr(m_nHeader[SRT_PH_MSGNO]); }
|
||||
std::string MessageFlagStr() { return PacketMessageFlagStr(m_nHeader[SRT_PH_MSGNO]); }
|
||||
std::string Info();
|
||||
#else
|
||||
{ return ""; }
|
||||
std::string MessageFlagStr() { return std::string(); }
|
||||
std::string Info() { return std::string(); }
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
188
trunk/3rdparty/srt-1-fit/srtcore/packetfilter.cpp
vendored
188
trunk/3rdparty/srt-1-fit/srtcore/packetfilter.cpp
vendored
|
@ -8,6 +8,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
@ -23,79 +24,138 @@
|
|||
|
||||
using namespace std;
|
||||
using namespace srt_logging;
|
||||
using namespace srt::sync;
|
||||
|
||||
bool ParseFilterConfig(std::string s, SrtFilterConfig& out)
|
||||
bool srt::ParseFilterConfig(string s, SrtFilterConfig& w_config, PacketFilter::Factory** ppf)
|
||||
{
|
||||
vector<string> parts;
|
||||
Split(s, ',', back_inserter(parts));
|
||||
if (!SrtParseConfig(s, (w_config)))
|
||||
return false;
|
||||
|
||||
out.type = parts[0];
|
||||
PacketFilter::Factory* fac = PacketFilter::find(out.type);
|
||||
PacketFilter::Factory* fac = PacketFilter::find(w_config.type);
|
||||
if (!fac)
|
||||
return false;
|
||||
|
||||
for (vector<string>::iterator i = parts.begin()+1; i != parts.end(); ++i)
|
||||
{
|
||||
vector<string> keyval;
|
||||
Split(*i, ':', back_inserter(keyval));
|
||||
if (keyval.size() != 2)
|
||||
return false;
|
||||
out.parameters[keyval[0]] = keyval[1];
|
||||
}
|
||||
|
||||
if (ppf)
|
||||
*ppf = fac;
|
||||
// Extract characteristic data
|
||||
out.extra_size = fac->ExtraSize();
|
||||
w_config.extra_size = fac->ExtraSize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SortBySequence
|
||||
bool srt::ParseFilterConfig(string s, SrtFilterConfig& w_config)
|
||||
{
|
||||
bool operator()(const CUnit* u1, const CUnit* u2)
|
||||
return ParseFilterConfig(s, (w_config), NULL);
|
||||
}
|
||||
|
||||
// Parameters are passed by value because they need to be potentially modicied inside.
|
||||
bool srt::CheckFilterCompat(SrtFilterConfig& w_agent, SrtFilterConfig peer)
|
||||
{
|
||||
PacketFilter::Factory* fac = PacketFilter::find(w_agent.type);
|
||||
if (!fac)
|
||||
return false;
|
||||
|
||||
SrtFilterConfig defaults;
|
||||
if (!ParseFilterConfig(fac->defaultConfig(), (defaults)))
|
||||
{
|
||||
int32_t s1 = u1->m_Packet.getSeqNo();
|
||||
int32_t s2 = u2->m_Packet.getSeqNo();
|
||||
|
||||
return CSeqNo::seqcmp(s1, s2) < 0;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void PacketFilter::receive(CUnit* unit, ref_t< std::vector<CUnit*> > r_incoming, ref_t<loss_seqs_t> r_loss_seqs)
|
||||
set<string> keys;
|
||||
// Extract all keys to identify also unspecified parameters on both sides
|
||||
// Note that theoretically for FEC it could simply check for the "cols" parameter
|
||||
// that is the only mandatory one, but this is a procedure for packet filters in
|
||||
// general and every filter may define its own set of parameters and mandatory rules.
|
||||
for (map<string, string>::iterator x = w_agent.parameters.begin(); x != w_agent.parameters.end(); ++x)
|
||||
{
|
||||
keys.insert(x->first);
|
||||
if (peer.parameters.count(x->first) == 0)
|
||||
peer.parameters[x->first] = x->second;
|
||||
}
|
||||
for (map<string, string>::iterator x = peer.parameters.begin(); x != peer.parameters.end(); ++x)
|
||||
{
|
||||
keys.insert(x->first);
|
||||
if (w_agent.parameters.count(x->first) == 0)
|
||||
w_agent.parameters[x->first] = x->second;
|
||||
}
|
||||
|
||||
HLOGC(cnlog.Debug, log << "CheckFilterCompat: re-filled: AGENT:" << Printable(w_agent.parameters)
|
||||
<< " PEER:" << Printable(peer.parameters));
|
||||
|
||||
// Complete nonexistent keys with default values
|
||||
for (map<string, string>::iterator x = defaults.parameters.begin(); x != defaults.parameters.end(); ++x)
|
||||
{
|
||||
if (!w_agent.parameters.count(x->first))
|
||||
w_agent.parameters[x->first] = x->second;
|
||||
if (!peer.parameters.count(x->first))
|
||||
peer.parameters[x->first] = x->second;
|
||||
}
|
||||
|
||||
for (set<string>::iterator x = keys.begin(); x != keys.end(); ++x)
|
||||
{
|
||||
// Note: operator[] will insert an element with default value
|
||||
// if it doesn't exist. This will inject the empty string as value,
|
||||
// which is acceptable.
|
||||
if (w_agent.parameters[*x] != peer.parameters[*x])
|
||||
{
|
||||
LOGC(cnlog.Error, log << "Packet Filter (" << defaults.type << "): collision on '" << (*x)
|
||||
<< "' parameter (agent:" << w_agent.parameters[*x] << " peer:" << (peer.parameters[*x]) << ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Mandatory parameters will be checked when trying to create the filter object.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace srt {
|
||||
struct SortBySequence
|
||||
{
|
||||
bool operator()(const CUnit* u1, const CUnit* u2)
|
||||
{
|
||||
int32_t s1 = u1->m_Packet.getSeqNo();
|
||||
int32_t s2 = u2->m_Packet.getSeqNo();
|
||||
|
||||
return CSeqNo::seqcmp(s1, s2) < 0;
|
||||
}
|
||||
};
|
||||
} // namespace srt
|
||||
|
||||
void srt::PacketFilter::receive(CUnit* unit, std::vector<CUnit*>& w_incoming, loss_seqs_t& w_loss_seqs)
|
||||
{
|
||||
const CPacket& rpkt = unit->m_Packet;
|
||||
|
||||
if (m_filter->receive(rpkt, *r_loss_seqs))
|
||||
if (m_filter->receive(rpkt, w_loss_seqs))
|
||||
{
|
||||
// For the sake of rebuilding MARK THIS UNIT GOOD, otherwise the
|
||||
// unit factory will supply it from getNextAvailUnit() as if it were not in use.
|
||||
unit->m_iFlag = CUnit::GOOD;
|
||||
HLOGC(mglog.Debug, log << "FILTER: PASSTHRU current packet %" << unit->m_Packet.getSeqNo());
|
||||
r_incoming.get().push_back(unit);
|
||||
HLOGC(pflog.Debug, log << "FILTER: PASSTHRU current packet %" << unit->m_Packet.getSeqNo());
|
||||
w_incoming.push_back(unit);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Packet not to be passthru, update stats
|
||||
CGuard lg(m_parent->m_StatsLock);
|
||||
++m_parent->m_stats.rcvFilterExtra;
|
||||
++m_parent->m_stats.rcvFilterExtraTotal;
|
||||
ScopedLock lg(m_parent->m_StatsLock);
|
||||
m_parent->m_stats.rcvr.recvdFilterExtra.count(1);
|
||||
}
|
||||
|
||||
// r_loss_seqs enters empty into this function and can be only filled here.
|
||||
for (loss_seqs_t::iterator i = r_loss_seqs.get().begin();
|
||||
i != r_loss_seqs.get().end(); ++i)
|
||||
// w_loss_seqs enters empty into this function and can be only filled here. XXX ASSERT?
|
||||
for (loss_seqs_t::iterator i = w_loss_seqs.begin();
|
||||
i != w_loss_seqs.end(); ++i)
|
||||
{
|
||||
// Sequences here are low-high, if there happens any negative distance
|
||||
// here, simply skip and report IPE.
|
||||
int dist = CSeqNo::seqoff(i->first, i->second) + 1;
|
||||
if (dist > 0)
|
||||
{
|
||||
CGuard lg(m_parent->m_StatsLock);
|
||||
m_parent->m_stats.rcvFilterLoss += dist;
|
||||
m_parent->m_stats.rcvFilterLossTotal += dist;
|
||||
ScopedLock lg(m_parent->m_StatsLock);
|
||||
m_parent->m_stats.rcvr.lossFilter.count(dist);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGC(mglog.Error, log << "FILTER: IPE: loss record: invalid loss: %"
|
||||
LOGC(pflog.Error, log << "FILTER: IPE: loss record: invalid loss: %"
|
||||
<< i->first << " - %" << i->second);
|
||||
}
|
||||
}
|
||||
|
@ -103,14 +163,13 @@ void PacketFilter::receive(CUnit* unit, ref_t< std::vector<CUnit*> > r_incoming,
|
|||
// Pack first recovered packets, if any.
|
||||
if (!m_provided.empty())
|
||||
{
|
||||
HLOGC(mglog.Debug, log << "FILTER: inserting REBUILT packets (" << m_provided.size() << "):");
|
||||
HLOGC(pflog.Debug, log << "FILTER: inserting REBUILT packets (" << m_provided.size() << "):");
|
||||
|
||||
size_t nsupply = m_provided.size();
|
||||
InsertRebuilt(*r_incoming, m_unitq);
|
||||
InsertRebuilt(w_incoming, m_unitq);
|
||||
|
||||
CGuard lg(m_parent->m_StatsLock);
|
||||
m_parent->m_stats.rcvFilterSupply += nsupply;
|
||||
m_parent->m_stats.rcvFilterSupplyTotal += nsupply;
|
||||
ScopedLock lg(m_parent->m_StatsLock);
|
||||
m_parent->m_stats.rcvr.suppliedByFilter.count(nsupply);
|
||||
}
|
||||
|
||||
// Now that all units have been filled as they should be,
|
||||
|
@ -120,8 +179,7 @@ void PacketFilter::receive(CUnit* unit, ref_t< std::vector<CUnit*> > r_incoming,
|
|||
// with FREE and therefore will be returned at the next
|
||||
// call to getNextAvailUnit().
|
||||
unit->m_iFlag = CUnit::FREE;
|
||||
vector<CUnit*>& inco = *r_incoming;
|
||||
for (vector<CUnit*>::iterator i = inco.begin(); i != inco.end(); ++i)
|
||||
for (vector<CUnit*>::iterator i = w_incoming.begin(); i != w_incoming.end(); ++i)
|
||||
{
|
||||
CUnit* u = *i;
|
||||
u->m_iFlag = CUnit::FREE;
|
||||
|
@ -129,7 +187,7 @@ void PacketFilter::receive(CUnit* unit, ref_t< std::vector<CUnit*> > r_incoming,
|
|||
|
||||
// Packets must be sorted by sequence number, ascending, in order
|
||||
// not to challenge the SRT's contiguity checker.
|
||||
sort(inco.begin(), inco.end(), SortBySequence());
|
||||
sort(w_incoming.begin(), w_incoming.end(), SortBySequence());
|
||||
|
||||
// For now, report immediately the irrecoverable packets
|
||||
// from the row.
|
||||
|
@ -147,7 +205,7 @@ void PacketFilter::receive(CUnit* unit, ref_t< std::vector<CUnit*> > r_incoming,
|
|||
|
||||
}
|
||||
|
||||
bool PacketFilter::packControlPacket(ref_t<CPacket> r_packet, int32_t seq, int kflg)
|
||||
bool srt::PacketFilter::packControlPacket(int32_t seq, int kflg, CPacket& w_packet)
|
||||
{
|
||||
bool have = m_filter->packControlPacket(m_sndctlpkt, seq);
|
||||
if (!have)
|
||||
|
@ -155,12 +213,12 @@ bool PacketFilter::packControlPacket(ref_t<CPacket> r_packet, int32_t seq, int k
|
|||
|
||||
// Now this should be repacked back to CPacket.
|
||||
// The header must be copied, it's always part of CPacket.
|
||||
uint32_t* hdr = r_packet.get().getHeader();
|
||||
memcpy(hdr, m_sndctlpkt.hdr, SRT_PH__SIZE * sizeof(*hdr));
|
||||
uint32_t* hdr = w_packet.getHeader();
|
||||
memcpy((hdr), m_sndctlpkt.hdr, SRT_PH_E_SIZE * sizeof(*hdr));
|
||||
|
||||
// The buffer can be assigned.
|
||||
r_packet.get().m_pcData = m_sndctlpkt.buffer;
|
||||
r_packet.get().setLength(m_sndctlpkt.length);
|
||||
w_packet.m_pcData = m_sndctlpkt.buffer;
|
||||
w_packet.setLength(m_sndctlpkt.length);
|
||||
|
||||
// This sets only the Packet Boundary flags, while all other things:
|
||||
// - Order
|
||||
|
@ -168,10 +226,10 @@ bool PacketFilter::packControlPacket(ref_t<CPacket> r_packet, int32_t seq, int k
|
|||
// - Crypto
|
||||
// - Message Number
|
||||
// will be set to 0/false
|
||||
r_packet.get().m_iMsgNo = MSGNO_PACKET_BOUNDARY::wrap(PB_SOLO);
|
||||
w_packet.m_iMsgNo = SRT_MSGNO_CONTROL | MSGNO_PACKET_BOUNDARY::wrap(PB_SOLO);
|
||||
|
||||
// ... and then fix only the Crypto flags
|
||||
r_packet.get().setMsgCryptoFlags(EncryptionKeySpec(kflg));
|
||||
w_packet.setMsgCryptoFlags(EncryptionKeySpec(kflg));
|
||||
|
||||
// Don't set the ID, it will be later set for any kind of packet.
|
||||
// Write the timestamp clip into the timestamp field.
|
||||
|
@ -179,7 +237,7 @@ bool PacketFilter::packControlPacket(ref_t<CPacket> r_packet, int32_t seq, int k
|
|||
}
|
||||
|
||||
|
||||
void PacketFilter::InsertRebuilt(vector<CUnit*>& incoming, CUnitQueue* uq)
|
||||
void srt::PacketFilter::InsertRebuilt(vector<CUnit*>& incoming, CUnitQueue* uq)
|
||||
{
|
||||
if (m_provided.empty())
|
||||
return;
|
||||
|
@ -189,7 +247,7 @@ void PacketFilter::InsertRebuilt(vector<CUnit*>& incoming, CUnitQueue* uq)
|
|||
CUnit* u = uq->getNextAvailUnit();
|
||||
if (!u)
|
||||
{
|
||||
LOGC(mglog.Error, log << "FILTER: LOCAL STORAGE DEPLETED. Can't return rebuilt packets.");
|
||||
LOGC(pflog.Error, log << "FILTER: LOCAL STORAGE DEPLETED. Can't return rebuilt packets.");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -202,11 +260,11 @@ void PacketFilter::InsertRebuilt(vector<CUnit*>& incoming, CUnitQueue* uq)
|
|||
|
||||
CPacket& packet = u->m_Packet;
|
||||
|
||||
memcpy(packet.getHeader(), i->hdr, CPacket::HDR_SIZE);
|
||||
memcpy(packet.m_pcData, i->buffer, i->length);
|
||||
memcpy((packet.getHeader()), i->hdr, CPacket::HDR_SIZE);
|
||||
memcpy((packet.m_pcData), i->buffer, i->length);
|
||||
packet.setLength(i->length);
|
||||
|
||||
HLOGC(mglog.Debug, log << "FILTER: PROVIDING rebuilt packet %" << packet.getSeqNo());
|
||||
HLOGC(pflog.Debug, log << "FILTER: PROVIDING rebuilt packet %" << packet.getSeqNo());
|
||||
|
||||
incoming.push_back(u);
|
||||
}
|
||||
|
@ -214,19 +272,21 @@ void PacketFilter::InsertRebuilt(vector<CUnit*>& incoming, CUnitQueue* uq)
|
|||
m_provided.clear();
|
||||
}
|
||||
|
||||
bool PacketFilter::IsBuiltin(const string& s)
|
||||
bool srt::PacketFilter::IsBuiltin(const string& s)
|
||||
{
|
||||
return builtin_filters.count(s);
|
||||
}
|
||||
|
||||
namespace srt {
|
||||
std::set<std::string> PacketFilter::builtin_filters;
|
||||
PacketFilter::filters_map_t PacketFilter::filters;
|
||||
}
|
||||
|
||||
PacketFilter::Factory::~Factory()
|
||||
srt::PacketFilter::Factory::~Factory()
|
||||
{
|
||||
}
|
||||
|
||||
void PacketFilter::globalInit()
|
||||
void srt::PacketFilter::globalInit()
|
||||
{
|
||||
// Add here builtin packet filters and mark them
|
||||
// as builtin. This will disallow users to register
|
||||
|
@ -236,12 +296,12 @@ void PacketFilter::globalInit()
|
|||
builtin_filters.insert("fec");
|
||||
}
|
||||
|
||||
bool PacketFilter::configure(CUDT* parent, CUnitQueue* uq, const std::string& confstr)
|
||||
bool srt::PacketFilter::configure(CUDT* parent, CUnitQueue* uq, const std::string& confstr)
|
||||
{
|
||||
m_parent = parent;
|
||||
|
||||
SrtFilterConfig cfg;
|
||||
if (!ParseFilterConfig(confstr, cfg))
|
||||
if (!ParseFilterConfig(confstr, (cfg)))
|
||||
return false;
|
||||
|
||||
// Extract the "type" key from parameters, or use
|
||||
|
@ -255,7 +315,7 @@ bool PacketFilter::configure(CUDT* parent, CUnitQueue* uq, const std::string& co
|
|||
init.snd_isn = parent->sndSeqNo();
|
||||
init.rcv_isn = parent->rcvSeqNo();
|
||||
init.payload_size = parent->OPT_PayloadSize();
|
||||
|
||||
init.rcvbuf_size = parent->m_config.iRcvBufSize;
|
||||
|
||||
// Found a filter, so call the creation function
|
||||
m_filter = selector->second->Create(init, m_provided, confstr);
|
||||
|
@ -270,7 +330,7 @@ bool PacketFilter::configure(CUDT* parent, CUnitQueue* uq, const std::string& co
|
|||
return true;
|
||||
}
|
||||
|
||||
bool PacketFilter::correctConfig(const SrtFilterConfig& conf)
|
||||
bool srt::PacketFilter::correctConfig(const SrtFilterConfig& conf)
|
||||
{
|
||||
const string* pname = map_getp(conf.parameters, "type");
|
||||
|
||||
|
@ -287,7 +347,7 @@ bool PacketFilter::correctConfig(const SrtFilterConfig& conf)
|
|||
return true;
|
||||
}
|
||||
|
||||
PacketFilter::~PacketFilter()
|
||||
srt::PacketFilter::~PacketFilter()
|
||||
{
|
||||
delete m_filter;
|
||||
}
|
||||
|
|
47
trunk/3rdparty/srt-1-fit/srtcore/packetfilter.h
vendored
47
trunk/3rdparty/srt-1-fit/srtcore/packetfilter.h
vendored
|
@ -8,40 +8,50 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef INC__PACKETFILTER_H
|
||||
#define INC__PACKETFILTER_H
|
||||
#ifndef INC_SRT_PACKETFILTER_H
|
||||
#define INC_SRT_PACKETFILTER_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "packet.h"
|
||||
#include "queue.h"
|
||||
#include "utilities.h"
|
||||
#include "packetfilter_api.h"
|
||||
|
||||
namespace srt {
|
||||
|
||||
class CUnitQueue;
|
||||
struct CUnit;
|
||||
class CUDT;
|
||||
|
||||
class PacketFilter
|
||||
{
|
||||
friend class SrtPacketFilterBase;
|
||||
|
||||
public:
|
||||
|
||||
typedef std::vector< std::pair<int32_t, int32_t> > loss_seqs_t;
|
||||
|
||||
typedef SrtPacketFilterBase* filter_create_t(const SrtFilterInitializer& init, std::vector<SrtPacket>&, const std::string& config);
|
||||
|
||||
private:
|
||||
friend bool ParseFilterConfig(std::string s, SrtFilterConfig& out);
|
||||
class Factory
|
||||
{
|
||||
public:
|
||||
virtual SrtPacketFilterBase* Create(const SrtFilterInitializer& init, std::vector<SrtPacket>& provided, const std::string& confstr) = 0;
|
||||
|
||||
// Characteristic data
|
||||
virtual size_t ExtraSize() = 0;
|
||||
virtual size_t ExtraSize() const = 0;
|
||||
|
||||
// Represent default parameters. This is for completing and comparing
|
||||
// filter configurations from both parties. Possible values to return:
|
||||
// - an empty string (all parameters are mandatory)
|
||||
// - a form of: "<filter-name>,<param1>:<value1>,..."
|
||||
virtual std::string defaultConfig() const = 0;
|
||||
virtual bool verifyConfig(const SrtFilterConfig& config, std::string& w_errormsg) const = 0;
|
||||
virtual ~Factory();
|
||||
};
|
||||
private:
|
||||
friend bool ParseFilterConfig(std::string s, SrtFilterConfig& out, PacketFilter::Factory** ppf);
|
||||
|
||||
template <class Target>
|
||||
class Creator: public Factory
|
||||
|
@ -52,7 +62,12 @@ private:
|
|||
{ return new Target(init, provided, confstr); }
|
||||
|
||||
// Import the extra size data
|
||||
virtual size_t ExtraSize() ATR_OVERRIDE { return Target::EXTRA_SIZE; }
|
||||
virtual size_t ExtraSize() const ATR_OVERRIDE { return Target::EXTRA_SIZE; }
|
||||
virtual std::string defaultConfig() const ATR_OVERRIDE { return Target::defaultConfig; }
|
||||
virtual bool verifyConfig(const SrtFilterConfig& config, std::string& w_errormsg) const ATR_OVERRIDE
|
||||
{
|
||||
return Target::verifyConfig(config, (w_errormsg));
|
||||
}
|
||||
|
||||
public:
|
||||
Creator() {}
|
||||
|
@ -157,7 +172,7 @@ public:
|
|||
// Things being done:
|
||||
// 1. The filter is individual, so don't copy it. Set NULL.
|
||||
// 2. This will be configued anyway basing on possibly a new rule set.
|
||||
PacketFilter(const PacketFilter& source SRT_ATR_UNUSED): m_filter(), m_sndctlpkt(0), m_unitq() {}
|
||||
PacketFilter(const PacketFilter& source SRT_ATR_UNUSED): m_filter(), m_parent(), m_sndctlpkt(0), m_unitq() {}
|
||||
|
||||
// This function will be called by the parent CUDT
|
||||
// in appropriate time. It should select appropriate
|
||||
|
@ -173,12 +188,13 @@ public:
|
|||
~PacketFilter();
|
||||
|
||||
// Simple wrappers
|
||||
void feedSource(ref_t<CPacket> r_packet);
|
||||
void feedSource(CPacket& w_packet);
|
||||
SRT_ARQLevel arqLevel();
|
||||
bool packControlPacket(ref_t<CPacket> r_packet, int32_t seq, int kflg);
|
||||
void receive(CUnit* unit, ref_t< std::vector<CUnit*> > r_incoming, ref_t<loss_seqs_t> r_loss_seqs);
|
||||
bool packControlPacket(int32_t seq, int kflg, CPacket& w_packet);
|
||||
void receive(CUnit* unit, std::vector<CUnit*>& w_incoming, loss_seqs_t& w_loss_seqs);
|
||||
|
||||
protected:
|
||||
PacketFilter& operator=(const PacketFilter& p);
|
||||
void InsertRebuilt(std::vector<CUnit*>& incoming, CUnitQueue* uq);
|
||||
|
||||
CUDT* m_parent;
|
||||
|
@ -191,8 +207,13 @@ protected:
|
|||
std::vector<SrtPacket> m_provided;
|
||||
};
|
||||
|
||||
bool CheckFilterCompat(SrtFilterConfig& w_agent, SrtFilterConfig peer);
|
||||
|
||||
inline void PacketFilter::feedSource(ref_t<CPacket> r_packet) { SRT_ASSERT(m_filter); return m_filter->feedSource(*r_packet); }
|
||||
inline void PacketFilter::feedSource(CPacket& w_packet) { SRT_ASSERT(m_filter); return m_filter->feedSource((w_packet)); }
|
||||
inline SRT_ARQLevel PacketFilter::arqLevel() { SRT_ASSERT(m_filter); return m_filter->arqLevel(); }
|
||||
|
||||
bool ParseFilterConfig(std::string s, SrtFilterConfig& out, PacketFilter::Factory** ppf);
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,8 +8,20 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef INC__PACKETFILTER_API_H
|
||||
#define INC__PACKETFILTER_API_H
|
||||
#ifndef INC_SRT_PACKETFILTER_API_H
|
||||
#define INC_SRT_PACKETFILTER_API_H
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
namespace srt {
|
||||
|
||||
class CPacket;
|
||||
|
||||
enum SrtPktHeaderFields
|
||||
{
|
||||
|
@ -19,7 +31,7 @@ enum SrtPktHeaderFields
|
|||
SRT_PH_ID = 3, //< socket ID
|
||||
|
||||
// Must be the last value - this is size of all, not a field id
|
||||
SRT_PH__SIZE
|
||||
SRT_PH_E_SIZE
|
||||
};
|
||||
|
||||
|
||||
|
@ -30,11 +42,15 @@ enum SRT_ARQLevel
|
|||
SRT_ARQ_ALWAYS, //< always send LOSSREPORT immediately after detecting a loss
|
||||
};
|
||||
|
||||
|
||||
struct SrtFilterConfig
|
||||
struct SrtConfig
|
||||
{
|
||||
std::string type;
|
||||
std::map<std::string, std::string> parameters;
|
||||
typedef std::map<std::string, std::string> par_t;
|
||||
par_t parameters;
|
||||
};
|
||||
|
||||
struct SrtFilterConfig: SrtConfig
|
||||
{
|
||||
size_t extra_size; // needed for filter option check against payload size
|
||||
};
|
||||
|
||||
|
@ -44,11 +60,12 @@ struct SrtFilterInitializer
|
|||
int32_t snd_isn;
|
||||
int32_t rcv_isn;
|
||||
size_t payload_size;
|
||||
size_t rcvbuf_size;
|
||||
};
|
||||
|
||||
struct SrtPacket
|
||||
{
|
||||
uint32_t hdr[SRT_PH__SIZE];
|
||||
uint32_t hdr[SRT_PH_E_SIZE];
|
||||
char buffer[SRT_LIVE_MAX_PLSIZE];
|
||||
size_t length;
|
||||
|
||||
|
@ -64,7 +81,7 @@ struct SrtPacket
|
|||
};
|
||||
|
||||
|
||||
bool ParseFilterConfig(std::string s, SrtFilterConfig& out);
|
||||
bool ParseFilterConfig(std::string s, SrtFilterConfig& w_config);
|
||||
|
||||
|
||||
class SrtPacketFilterBase
|
||||
|
@ -77,6 +94,7 @@ protected:
|
|||
int32_t sndISN() const { return initParams.snd_isn; }
|
||||
int32_t rcvISN() const { return initParams.rcv_isn; }
|
||||
size_t payloadSize() const { return initParams.payload_size; }
|
||||
size_t rcvBufferSize() const { return initParams.rcvbuf_size; }
|
||||
|
||||
friend class PacketFilter;
|
||||
|
||||
|
@ -135,6 +153,6 @@ protected:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef INC__PACKETFILTER_BUILTIN_H
|
||||
#define INC__PACKETFILTER_BUILTIN_H
|
||||
#ifndef INC_SRT_PACKETFILTER_BUILTIN_H
|
||||
#define INC_SRT_PACKETFILTER_BUILTIN_H
|
||||
|
||||
// Integration header
|
||||
#include "fec.h"
|
||||
|
|
97
trunk/3rdparty/srt-1-fit/srtcore/platform_sys.h
vendored
97
trunk/3rdparty/srt-1-fit/srtcore/platform_sys.h
vendored
|
@ -7,28 +7,117 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
#ifndef INC__PLATFORM_SYS_H
|
||||
#define INC__PLATFORM_SYS_H
|
||||
#ifndef INC_SRT_PLATFORM_SYS_H
|
||||
#define INC_SRT_PLATFORM_SYS_H
|
||||
|
||||
// INFORMATION
|
||||
//
|
||||
// This file collects all required platform-specific declarations
|
||||
// required to provide everything that the SRT library needs from system.
|
||||
//
|
||||
// There's also semi-modular system implemented using SRT_IMPORT_* macros.
|
||||
// To require a module to be imported, #define SRT_IMPORT_* where * is
|
||||
// the module name. Currently handled module macros:
|
||||
//
|
||||
// SRT_IMPORT_TIME (mach time on Mac, portability gettimeofday on WIN32)
|
||||
// SRT_IMPORT_EVENT (includes kevent on Mac)
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _CRT_SECURE_NO_WARNINGS 1 // silences windows complaints for sscanf
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <ws2ipdef.h>
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef __MINGW32__
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef SRT_IMPORT_TIME
|
||||
#include <win/wintime.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable:4251)
|
||||
#pragma warning(disable: 4251 26812)
|
||||
#endif
|
||||
#else
|
||||
|
||||
#if defined(__APPLE__) && __APPLE__
|
||||
// Warning: please keep this test as it is, do not make it
|
||||
// "#if __APPLE__" or "#ifdef __APPLE__". In applications with
|
||||
// a strict "no warning policy", "#if __APPLE__" triggers an "undef"
|
||||
// error. With GCC, an old & never fixed bug prevents muting this
|
||||
// warning (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431).
|
||||
// Before this fix, the solution was to "#define __APPLE__ 0" before
|
||||
// including srt.h. So, don't use "#ifdef __APPLE__" either.
|
||||
|
||||
// XXX Check if this condition doesn't require checking of
|
||||
// also other macros, like TARGET_OS_IOS etc.
|
||||
|
||||
#include "TargetConditionals.h"
|
||||
#define __APPLE_USE_RFC_3542 /* IPV6_PKTINFO */
|
||||
|
||||
#ifdef SRT_IMPORT_TIME
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
#ifdef SRT_IMPORT_EVENT
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef BSD
|
||||
#ifdef SRT_IMPORT_EVENT
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef LINUX
|
||||
|
||||
#ifdef SRT_IMPORT_EVENT
|
||||
#include <sys/epoll.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
#ifdef SRT_IMPORT_EVENT
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
// Headers for errno, string and stdlib are
|
||||
// included indirectly correct C++ way.
|
||||
#else
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
1238
trunk/3rdparty/srt-1-fit/srtcore/queue.cpp
vendored
1238
trunk/3rdparty/srt-1-fit/srtcore/queue.cpp
vendored
File diff suppressed because it is too large
Load diff
686
trunk/3rdparty/srt-1-fit/srtcore/queue.h
vendored
686
trunk/3rdparty/srt-1-fit/srtcore/queue.h
vendored
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -50,13 +50,12 @@ modified by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC_SRT_QUEUE_H
|
||||
#define INC_SRT_QUEUE_H
|
||||
|
||||
#ifndef __UDT_QUEUE_H__
|
||||
#define __UDT_QUEUE_H__
|
||||
|
||||
#include "channel.h"
|
||||
#include "common.h"
|
||||
#include "packet.h"
|
||||
#include "socketconfig.h"
|
||||
#include "netinet_any.h"
|
||||
#include "utilities.h"
|
||||
#include <list>
|
||||
|
@ -64,485 +63,548 @@ modified by
|
|||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
namespace srt
|
||||
{
|
||||
class CChannel;
|
||||
class CUDT;
|
||||
|
||||
struct CUnit
|
||||
{
|
||||
CPacket m_Packet; // packet
|
||||
enum Flag { FREE = 0, GOOD = 1, PASSACK = 2, DROPPED = 3 };
|
||||
Flag m_iFlag; // 0: free, 1: occupied, 2: msg read but not freed (out-of-order), 3: msg dropped
|
||||
CPacket m_Packet; // packet
|
||||
enum Flag
|
||||
{
|
||||
FREE = 0,
|
||||
GOOD = 1,
|
||||
PASSACK = 2,
|
||||
DROPPED = 3
|
||||
};
|
||||
|
||||
// TODO: The new RcvBuffer allows to use atomic_bool here.
|
||||
sync::atomic<Flag> m_iFlag; // 0: free, 1: occupied, 2: msg read but not freed (out-of-order), 3: msg dropped
|
||||
};
|
||||
|
||||
class CUnitQueue
|
||||
{
|
||||
public:
|
||||
/// @brief Construct a unit queue.
|
||||
/// @param mss Initial number of units to allocate.
|
||||
/// @param mss Maximum segment size meaning the size of each unit.
|
||||
/// @throws CUDTException SRT_ENOBUF.
|
||||
CUnitQueue(int initNumUnits, int mss);
|
||||
~CUnitQueue();
|
||||
|
||||
public:
|
||||
|
||||
CUnitQueue();
|
||||
~CUnitQueue();
|
||||
|
||||
public: // Storage size operations
|
||||
|
||||
/// Initialize the unit queue.
|
||||
/// @param [in] size queue size
|
||||
/// @param [in] mss maximum segment size
|
||||
/// @param [in] version IP version
|
||||
/// @return 0: success, -1: failure.
|
||||
|
||||
int init(int size, int mss, int version);
|
||||
|
||||
/// Increase (double) the unit queue size.
|
||||
/// @return 0: success, -1: failure.
|
||||
|
||||
int increase();
|
||||
|
||||
/// Decrease (halve) the unit queue size.
|
||||
/// @return 0: success, -1: failure.
|
||||
|
||||
int shrink();
|
||||
|
||||
public: // Operations on units
|
||||
|
||||
/// find an available unit for incoming packet.
|
||||
/// @return Pointer to the available unit, NULL if not found.
|
||||
|
||||
CUnit* getNextAvailUnit();
|
||||
|
||||
|
||||
void makeUnitFree(CUnit * unit);
|
||||
|
||||
void makeUnitGood(CUnit * unit);
|
||||
int capacity() const { return m_iSize; }
|
||||
int size() const { return m_iSize - m_iNumTaken; }
|
||||
|
||||
public:
|
||||
/// @brief Find an available unit for incoming packet. Allocate new units if 90% or more are in use.
|
||||
/// @note This function is not thread-safe. Currently only CRcvQueue::worker thread calls it, thus
|
||||
/// it is not an issue. However, must be protected if used from several threads in the future.
|
||||
/// @return Pointer to the available unit, NULL if not found.
|
||||
CUnit* getNextAvailUnit();
|
||||
|
||||
inline int getIPversion() const { return m_iIPversion; }
|
||||
void makeUnitFree(CUnit* unit);
|
||||
|
||||
void makeUnitGood(CUnit* unit);
|
||||
|
||||
private:
|
||||
struct CQEntry
|
||||
{
|
||||
CUnit* m_pUnit; // unit queue
|
||||
char* m_pBuffer; // data buffer
|
||||
int m_iSize; // size of each queue
|
||||
struct CQEntry
|
||||
{
|
||||
CUnit* m_pUnit; // unit queue
|
||||
char* m_pBuffer; // data buffer
|
||||
int m_iSize; // size of each queue
|
||||
|
||||
CQEntry* m_pNext;
|
||||
}
|
||||
*m_pQEntry, // pointer to the first unit queue
|
||||
*m_pCurrQueue, // pointer to the current available queue
|
||||
*m_pLastQueue; // pointer to the last unit queue
|
||||
CQEntry* m_pNext;
|
||||
};
|
||||
|
||||
CUnit* m_pAvailUnit; // recent available unit
|
||||
/// Increase the unit queue size (by @a m_iBlockSize units).
|
||||
/// Uses m_mtx to protect access and changes of the queue state.
|
||||
/// @return 0: success, -1: failure.
|
||||
int increase_();
|
||||
|
||||
int m_iSize; // total size of the unit queue, in number of packets
|
||||
int m_iCount; // total number of valid packets in the queue
|
||||
|
||||
int m_iMSS; // unit buffer size
|
||||
int m_iIPversion; // IP version
|
||||
/// @brief Allocated a CQEntry of iNumUnits with each unit of mss bytes.
|
||||
/// @param iNumUnits a number of units to allocate
|
||||
/// @param mss the size of each unit in bytes.
|
||||
/// @return a pointer to a newly allocated entry on success, NULL otherwise.
|
||||
static CQEntry* allocateEntry(const int iNumUnits, const int mss);
|
||||
|
||||
private:
|
||||
CUnitQueue(const CUnitQueue&);
|
||||
CUnitQueue& operator=(const CUnitQueue&);
|
||||
CQEntry* m_pQEntry; // pointer to the first unit queue
|
||||
CQEntry* m_pCurrQueue; // pointer to the current available queue
|
||||
CQEntry* m_pLastQueue; // pointer to the last unit queue
|
||||
CUnit* m_pAvailUnit; // recent available unit
|
||||
int m_iSize; // total size of the unit queue, in number of packets
|
||||
sync::atomic<int> m_iNumTaken; // total number of valid (occupied) packets in the queue
|
||||
const int m_iMSS; // unit buffer size
|
||||
const int m_iBlockSize; // Number of units in each CQEntry.
|
||||
|
||||
private:
|
||||
CUnitQueue(const CUnitQueue&);
|
||||
CUnitQueue& operator=(const CUnitQueue&);
|
||||
};
|
||||
|
||||
struct CSNode
|
||||
{
|
||||
CUDT* m_pUDT; // Pointer to the instance of CUDT socket
|
||||
uint64_t m_llTimeStamp_tk; // Time Stamp
|
||||
CUDT* m_pUDT; // Pointer to the instance of CUDT socket
|
||||
sync::steady_clock::time_point m_tsTimeStamp;
|
||||
|
||||
int m_iHeapLoc; // location on the heap, -1 means not on the heap
|
||||
sync::atomic<int> m_iHeapLoc; // location on the heap, -1 means not on the heap
|
||||
};
|
||||
|
||||
class CSndUList
|
||||
{
|
||||
friend class CSndQueue;
|
||||
public:
|
||||
CSndUList(sync::CTimer* pTimer);
|
||||
~CSndUList();
|
||||
|
||||
public:
|
||||
CSndUList();
|
||||
~CSndUList();
|
||||
enum EReschedule
|
||||
{
|
||||
DONT_RESCHEDULE = 0,
|
||||
DO_RESCHEDULE = 1
|
||||
};
|
||||
|
||||
public:
|
||||
static EReschedule rescheduleIf(bool cond) { return cond ? DO_RESCHEDULE : DONT_RESCHEDULE; }
|
||||
|
||||
enum EReschedule { DONT_RESCHEDULE = 0, DO_RESCHEDULE = 1 };
|
||||
/// Update the timestamp of the UDT instance on the list.
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
/// @param [in] reschedule if the timestamp should be rescheduled
|
||||
/// @param [in] ts the next time to trigger sending logic on the CUDT
|
||||
void update(const CUDT* u, EReschedule reschedule, sync::steady_clock::time_point ts = sync::steady_clock::now());
|
||||
|
||||
static EReschedule rescheduleIf(bool cond) { return cond ? DO_RESCHEDULE : DONT_RESCHEDULE; }
|
||||
/// Retrieve the next (in time) socket from the heap to process its sending request.
|
||||
/// @return a pointer to CUDT instance to process next.
|
||||
CUDT* pop();
|
||||
|
||||
/// Update the timestamp of the UDT instance on the list.
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
/// @param [in] reschedule if the timestamp should be rescheduled
|
||||
/// Remove UDT instance from the list.
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
void remove(const CUDT* u);// EXCLUDES(m_ListLock);
|
||||
|
||||
void update(const CUDT* u, EReschedule reschedule);
|
||||
/// Retrieve the next scheduled processing time.
|
||||
/// @return Scheduled processing time of the first UDT socket in the list.
|
||||
sync::steady_clock::time_point getNextProcTime();
|
||||
|
||||
/// Retrieve the next packet and peer address from the first entry, and reschedule it in the queue.
|
||||
/// @param [out] addr destination address of the next packet
|
||||
/// @param [out] pkt the next packet to be sent
|
||||
/// @return 1 if successfully retrieved, -1 if no packet found.
|
||||
/// Wait for the list to become non empty.
|
||||
void waitNonEmpty() const;
|
||||
|
||||
int pop(sockaddr*& addr, CPacket& pkt);
|
||||
|
||||
/// Remove UDT instance from the list.
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
|
||||
void remove(const CUDT* u);
|
||||
|
||||
/// Retrieve the next scheduled processing time.
|
||||
/// @return Scheduled processing time of the first UDT socket in the list.
|
||||
|
||||
uint64_t getNextProcTime();
|
||||
/// Signal to stop waiting in waitNonEmpty().
|
||||
void signalInterrupt() const;
|
||||
|
||||
private:
|
||||
/// Doubles the size of the list.
|
||||
///
|
||||
void realloc_();// REQUIRES(m_ListLock);
|
||||
|
||||
/// Doubles the size of the list.
|
||||
///
|
||||
void realloc_();
|
||||
/// Insert a new UDT instance into the list with realloc if required.
|
||||
///
|
||||
/// @param [in] ts time stamp: next processing time
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
void insert_(const sync::steady_clock::time_point& ts, const CUDT* u);
|
||||
|
||||
/// Insert a new UDT instance into the list with realloc if required.
|
||||
///
|
||||
/// @param [in] ts time stamp: next processing time
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
void insert_(int64_t ts, const CUDT* u);
|
||||
/// Insert a new UDT instance into the list without realloc.
|
||||
/// Should be called if there is a gauranteed space for the element.
|
||||
///
|
||||
/// @param [in] ts time stamp: next processing time
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
void insert_norealloc_(const sync::steady_clock::time_point& ts, const CUDT* u);// REQUIRES(m_ListLock);
|
||||
|
||||
/// Insert a new UDT instance into the list without realloc.
|
||||
/// Should be called if there is a gauranteed space for the element.
|
||||
///
|
||||
/// @param [in] ts time stamp: next processing time
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
void insert_norealloc_(int64_t ts, const CUDT* u);
|
||||
|
||||
void remove_(const CUDT* u);
|
||||
/// Removes CUDT entry from the list.
|
||||
/// If the last entry is removed, calls sync::CTimer::interrupt().
|
||||
void remove_(const CUDT* u);
|
||||
|
||||
private:
|
||||
CSNode** m_pHeap; // The heap array
|
||||
int m_iArrayLength; // physical length of the array
|
||||
int m_iLastEntry; // position of last entry on the heap array
|
||||
CSNode** m_pHeap; // The heap array
|
||||
int m_iArrayLength; // physical length of the array
|
||||
int m_iLastEntry; // position of last entry on the heap array or -1 if empty.
|
||||
|
||||
pthread_mutex_t m_ListLock;
|
||||
mutable sync::Mutex m_ListLock; // Protects the list (m_pHeap, m_iArrayLength, m_iLastEntry).
|
||||
mutable sync::Condition m_ListCond;
|
||||
|
||||
pthread_mutex_t* m_pWindowLock;
|
||||
pthread_cond_t* m_pWindowCond;
|
||||
|
||||
CTimer* m_pTimer;
|
||||
sync::CTimer* const m_pTimer;
|
||||
|
||||
private:
|
||||
CSndUList(const CSndUList&);
|
||||
CSndUList& operator=(const CSndUList&);
|
||||
CSndUList(const CSndUList&);
|
||||
CSndUList& operator=(const CSndUList&);
|
||||
};
|
||||
|
||||
struct CRNode
|
||||
{
|
||||
CUDT* m_pUDT; // Pointer to the instance of CUDT socket
|
||||
uint64_t m_llTimeStamp_tk; // Time Stamp
|
||||
CUDT* m_pUDT; // Pointer to the instance of CUDT socket
|
||||
sync::steady_clock::time_point m_tsTimeStamp; // Time Stamp
|
||||
|
||||
CRNode* m_pPrev; // previous link
|
||||
CRNode* m_pNext; // next link
|
||||
CRNode* m_pPrev; // previous link
|
||||
CRNode* m_pNext; // next link
|
||||
|
||||
bool m_bOnList; // if the node is already on the list
|
||||
sync::atomic<bool> m_bOnList; // if the node is already on the list
|
||||
};
|
||||
|
||||
class CRcvUList
|
||||
{
|
||||
public:
|
||||
CRcvUList();
|
||||
~CRcvUList();
|
||||
CRcvUList();
|
||||
~CRcvUList();
|
||||
|
||||
public:
|
||||
/// Insert a new UDT instance to the list.
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
|
||||
/// Insert a new UDT instance to the list.
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
void insert(const CUDT* u);
|
||||
|
||||
void insert(const CUDT* u);
|
||||
/// Remove the UDT instance from the list.
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
|
||||
/// Remove the UDT instance from the list.
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
void remove(const CUDT* u);
|
||||
|
||||
void remove(const CUDT* u);
|
||||
/// Move the UDT instance to the end of the list, if it already exists; otherwise, do nothing.
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
|
||||
/// Move the UDT instance to the end of the list, if it already exists; otherwise, do nothing.
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
|
||||
void update(const CUDT* u);
|
||||
void update(const CUDT* u);
|
||||
|
||||
public:
|
||||
CRNode* m_pUList; // the head node
|
||||
CRNode* m_pUList; // the head node
|
||||
|
||||
private:
|
||||
CRNode* m_pLast; // the last node
|
||||
CRNode* m_pLast; // the last node
|
||||
|
||||
private:
|
||||
CRcvUList(const CRcvUList&);
|
||||
CRcvUList& operator=(const CRcvUList&);
|
||||
CRcvUList(const CRcvUList&);
|
||||
CRcvUList& operator=(const CRcvUList&);
|
||||
};
|
||||
|
||||
class CHash
|
||||
{
|
||||
public:
|
||||
CHash();
|
||||
~CHash();
|
||||
CHash();
|
||||
~CHash();
|
||||
|
||||
public:
|
||||
/// Initialize the hash table.
|
||||
/// @param [in] size hash table size
|
||||
|
||||
/// Initialize the hash table.
|
||||
/// @param [in] size hash table size
|
||||
void init(int size);
|
||||
|
||||
void init(int size);
|
||||
/// Look for a UDT instance from the hash table.
|
||||
/// @param [in] id socket ID
|
||||
/// @return Pointer to a UDT instance, or NULL if not found.
|
||||
|
||||
/// Look for a UDT instance from the hash table.
|
||||
/// @param [in] id socket ID
|
||||
/// @return Pointer to a UDT instance, or NULL if not found.
|
||||
CUDT* lookup(int32_t id);
|
||||
|
||||
CUDT* lookup(int32_t id);
|
||||
/// Insert an entry to the hash table.
|
||||
/// @param [in] id socket ID
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
|
||||
/// Insert an entry to the hash table.
|
||||
/// @param [in] id socket ID
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
void insert(int32_t id, CUDT* u);
|
||||
|
||||
void insert(int32_t id, CUDT* u);
|
||||
/// Remove an entry from the hash table.
|
||||
/// @param [in] id socket ID
|
||||
|
||||
/// Remove an entry from the hash table.
|
||||
/// @param [in] id socket ID
|
||||
|
||||
void remove(int32_t id);
|
||||
void remove(int32_t id);
|
||||
|
||||
private:
|
||||
struct CBucket
|
||||
{
|
||||
int32_t m_iID; // Socket ID
|
||||
CUDT* m_pUDT; // Socket instance
|
||||
struct CBucket
|
||||
{
|
||||
int32_t m_iID; // Socket ID
|
||||
CUDT* m_pUDT; // Socket instance
|
||||
|
||||
CBucket* m_pNext; // next bucket
|
||||
} **m_pBucket; // list of buckets (the hash table)
|
||||
CBucket* m_pNext; // next bucket
|
||||
} * *m_pBucket; // list of buckets (the hash table)
|
||||
|
||||
int m_iHashSize; // size of hash table
|
||||
int m_iHashSize; // size of hash table
|
||||
|
||||
private:
|
||||
CHash(const CHash&);
|
||||
CHash& operator=(const CHash&);
|
||||
CHash(const CHash&);
|
||||
CHash& operator=(const CHash&);
|
||||
};
|
||||
|
||||
/// @brief A queue of sockets pending for connection.
|
||||
/// It can be either a caller socket in a non-blocking mode
|
||||
/// (the connection has to be handled in background),
|
||||
/// or a socket in rendezvous connection mode.
|
||||
class CRendezvousQueue
|
||||
{
|
||||
public:
|
||||
CRendezvousQueue();
|
||||
~CRendezvousQueue();
|
||||
CRendezvousQueue();
|
||||
~CRendezvousQueue();
|
||||
|
||||
public:
|
||||
void insert(const SRTSOCKET& id, CUDT* u, int ipv, const sockaddr* addr, uint64_t ttl);
|
||||
/// @brief Insert a new socket pending for connection (non-blocking caller or rendezvous).
|
||||
/// @param id socket ID.
|
||||
/// @param u pointer to a corresponding CUDT instance.
|
||||
/// @param addr remote address to connect to.
|
||||
/// @param ttl timepoint for connection attempt to expire.
|
||||
void insert(const SRTSOCKET& id, CUDT* u, const sockaddr_any& addr, const srt::sync::steady_clock::time_point& ttl);
|
||||
|
||||
// The should_lock parameter is given here to state as to whether
|
||||
// the lock should be applied here. If called from some internals
|
||||
// and the lock IS ALREADY APPLIED, use false here to prevent
|
||||
// double locking and deadlock in result.
|
||||
void remove(const SRTSOCKET& id, bool should_lock);
|
||||
CUDT* retrieve(const sockaddr* addr, ref_t<SRTSOCKET> id);
|
||||
/// @brief Remove a socket from the connection pending list.
|
||||
/// @param id socket ID.
|
||||
void remove(const SRTSOCKET& id);
|
||||
|
||||
void updateConnStatus(EReadStatus rst, EConnectStatus, const CPacket& response);
|
||||
/// @brief Locate a socket in the connection pending queue.
|
||||
/// @param addr source address of the packet received over UDP (peer address).
|
||||
/// @param id socket ID.
|
||||
/// @return a pointer to CUDT instance retrieved, or NULL if nothing was found.
|
||||
CUDT* retrieve(const sockaddr_any& addr, SRTSOCKET& id) const;
|
||||
|
||||
/// @brief Update status of connections in the pending queue.
|
||||
/// Stop connecting if TTL expires. Resend handshake request every 250 ms if no response from the peer.
|
||||
/// @param rst result of reading from a UDP socket: received packet / nothin read / read error.
|
||||
/// @param cst target status for pending connection: reject or proceed.
|
||||
/// @param pktIn packet received from the UDP socket.
|
||||
void updateConnStatus(EReadStatus rst, EConnectStatus cst, CUnit* unit);
|
||||
|
||||
private:
|
||||
struct CRL
|
||||
{
|
||||
SRTSOCKET m_iID; // UDT socket ID (self)
|
||||
CUDT* m_pUDT; // UDT instance
|
||||
int m_iIPversion; // IP version
|
||||
sockaddr* m_pPeerAddr; // UDT sonnection peer address
|
||||
uint64_t m_ullTTL; // the time that this request expires
|
||||
};
|
||||
std::list<CRL> m_lRendezvousID; // The sockets currently in rendezvous mode
|
||||
struct LinkStatusInfo
|
||||
{
|
||||
CUDT* u;
|
||||
SRTSOCKET id;
|
||||
int errorcode;
|
||||
sockaddr_any peeraddr;
|
||||
int token;
|
||||
|
||||
pthread_mutex_t m_RIDVectorLock;
|
||||
struct HasID
|
||||
{
|
||||
SRTSOCKET id;
|
||||
HasID(SRTSOCKET p)
|
||||
: id(p)
|
||||
{
|
||||
}
|
||||
bool operator()(const LinkStatusInfo& i) { return i.id == id; }
|
||||
};
|
||||
};
|
||||
|
||||
/// @brief Qualify pending connections:
|
||||
/// - Sockets with expired TTL go to the 'to_remove' list and removed from the queue straight away.
|
||||
/// - If HS request is to be resent (resend 250 ms if no response from the peer) go to the 'to_process' list.
|
||||
///
|
||||
/// @param rst result of reading from a UDP socket: received packet / nothin read / read error.
|
||||
/// @param cst target status for pending connection: reject or proceed.
|
||||
/// @param iDstSockID destination socket ID of the received packet.
|
||||
/// @param[in,out] toRemove stores sockets with expired TTL.
|
||||
/// @param[in,out] toProcess stores sockets which should repeat (resend) HS connection request.
|
||||
bool qualifyToHandle(EReadStatus rst,
|
||||
EConnectStatus cst,
|
||||
int iDstSockID,
|
||||
std::vector<LinkStatusInfo>& toRemove,
|
||||
std::vector<LinkStatusInfo>& toProcess);
|
||||
|
||||
private:
|
||||
struct CRL
|
||||
{
|
||||
SRTSOCKET m_iID; // SRT socket ID (self)
|
||||
CUDT* m_pUDT; // CUDT instance
|
||||
sockaddr_any m_PeerAddr; // SRT sonnection peer address
|
||||
sync::steady_clock::time_point m_tsTTL; // the time that this request expires
|
||||
};
|
||||
std::list<CRL> m_lRendezvousID; // The sockets currently in rendezvous mode
|
||||
|
||||
mutable sync::Mutex m_RIDListLock;
|
||||
};
|
||||
|
||||
class CSndQueue
|
||||
{
|
||||
friend class CUDT;
|
||||
friend class CUDTUnited;
|
||||
friend class CUDT;
|
||||
friend class CUDTUnited;
|
||||
|
||||
public:
|
||||
CSndQueue();
|
||||
~CSndQueue();
|
||||
CSndQueue();
|
||||
~CSndQueue();
|
||||
|
||||
public:
|
||||
// XXX There's currently no way to access the socket ID set for
|
||||
// whatever the queue is currently working for. Required to find
|
||||
// some way to do this, possibly by having a "reverse pointer".
|
||||
// Currently just "unimplemented".
|
||||
std::string CONID() const { return ""; }
|
||||
|
||||
// XXX There's currently no way to access the socket ID set for
|
||||
// whatever the queue is currently working for. Required to find
|
||||
// some way to do this, possibly by having a "reverse pointer".
|
||||
// Currently just "unimplemented".
|
||||
std::string CONID() const { return ""; }
|
||||
/// Initialize the sending queue.
|
||||
/// @param [in] c UDP channel to be associated to the queue
|
||||
/// @param [in] t Timer
|
||||
|
||||
/// Initialize the sending queue.
|
||||
/// @param [in] c UDP channel to be associated to the queue
|
||||
/// @param [in] t Timer
|
||||
void init(CChannel* c, sync::CTimer* t);
|
||||
|
||||
void init(CChannel* c, CTimer* t);
|
||||
/// Send out a packet to a given address.
|
||||
/// @param [in] addr destination address
|
||||
/// @param [in] packet packet to be sent out
|
||||
/// @return Size of data sent out.
|
||||
|
||||
/// Send out a packet to a given address.
|
||||
/// @param [in] addr destination address
|
||||
/// @param [in] packet packet to be sent out
|
||||
/// @return Size of data sent out.
|
||||
int sendto(const sockaddr_any& addr, CPacket& packet);
|
||||
|
||||
int sendto(const sockaddr* addr, CPacket& packet);
|
||||
/// Get the IP TTL.
|
||||
/// @param [in] ttl IP Time To Live.
|
||||
/// @return TTL.
|
||||
|
||||
#ifdef SRT_ENABLE_IPOPTS
|
||||
/// Get the IP TTL.
|
||||
/// @param [in] ttl IP Time To Live.
|
||||
/// @return TTL.
|
||||
int getIpTTL() const;
|
||||
|
||||
int getIpTTL() const;
|
||||
/// Get the IP Type of Service.
|
||||
/// @return ToS.
|
||||
|
||||
/// Get the IP Type of Service.
|
||||
/// @return ToS.
|
||||
int getIpToS() const;
|
||||
|
||||
int getIpToS() const;
|
||||
#ifdef SRT_ENABLE_BINDTODEVICE
|
||||
bool getBind(char* dst, size_t len) const;
|
||||
#endif
|
||||
|
||||
int ioctlQuery(int type) const { return m_pChannel->ioctlQuery(type); }
|
||||
int sockoptQuery(int level, int type) const { return m_pChannel->sockoptQuery(level, type); }
|
||||
int ioctlQuery(int type) const;
|
||||
int sockoptQuery(int level, int type) const;
|
||||
|
||||
void setClosing()
|
||||
{
|
||||
m_bClosing = true;
|
||||
}
|
||||
void setClosing() { m_bClosing = true; }
|
||||
|
||||
private:
|
||||
static void* worker(void* param);
|
||||
pthread_t m_WorkerThread;
|
||||
|
||||
static void* worker(void* param);
|
||||
sync::CThread m_WorkerThread;
|
||||
|
||||
private:
|
||||
CSndUList* m_pSndUList; // List of UDT instances for data sending
|
||||
CChannel* m_pChannel; // The UDP channel for data sending
|
||||
CTimer* m_pTimer; // Timing facility
|
||||
CSndUList* m_pSndUList; // List of UDT instances for data sending
|
||||
CChannel* m_pChannel; // The UDP channel for data sending
|
||||
sync::CTimer* m_pTimer; // Timing facility
|
||||
|
||||
pthread_mutex_t m_WindowLock;
|
||||
pthread_cond_t m_WindowCond;
|
||||
sync::atomic<bool> m_bClosing; // closing the worker
|
||||
|
||||
volatile bool m_bClosing; // closing the worker
|
||||
|
||||
#if defined(SRT_DEBUG_SNDQ_HIGHRATE)//>>debug high freq worker
|
||||
uint64_t m_ullDbgPeriod;
|
||||
uint64_t m_ullDbgTime;
|
||||
struct {
|
||||
#if defined(SRT_DEBUG_SNDQ_HIGHRATE) //>>debug high freq worker
|
||||
uint64_t m_ullDbgPeriod;
|
||||
uint64_t m_ullDbgTime;
|
||||
struct
|
||||
{
|
||||
unsigned long lIteration; //
|
||||
unsigned long lSleepTo; //SleepTo
|
||||
unsigned long lNotReadyPop; //Continue
|
||||
unsigned long lSleepTo; // SleepTo
|
||||
unsigned long lNotReadyPop; // Continue
|
||||
unsigned long lSendTo;
|
||||
unsigned long lNotReadyTs;
|
||||
unsigned long lCondWait; //block on m_WindowCond
|
||||
} m_WorkerStats;
|
||||
unsigned long lNotReadyTs;
|
||||
unsigned long lCondWait; // block on m_WindowCond
|
||||
} m_WorkerStats;
|
||||
#endif /* SRT_DEBUG_SNDQ_HIGHRATE */
|
||||
|
||||
#if ENABLE_LOGGING
|
||||
static int m_counter;
|
||||
#endif
|
||||
|
||||
private:
|
||||
CSndQueue(const CSndQueue&);
|
||||
CSndQueue& operator=(const CSndQueue&);
|
||||
CSndQueue(const CSndQueue&);
|
||||
CSndQueue& operator=(const CSndQueue&);
|
||||
};
|
||||
|
||||
class CRcvQueue
|
||||
{
|
||||
friend class CUDT;
|
||||
friend class CUDTUnited;
|
||||
friend class CUDT;
|
||||
friend class CUDTUnited;
|
||||
|
||||
public:
|
||||
CRcvQueue();
|
||||
~CRcvQueue();
|
||||
CRcvQueue();
|
||||
~CRcvQueue();
|
||||
|
||||
public:
|
||||
// XXX There's currently no way to access the socket ID set for
|
||||
// whatever the queue is currently working. Required to find
|
||||
// some way to do this, possibly by having a "reverse pointer".
|
||||
// Currently just "unimplemented".
|
||||
std::string CONID() const { return ""; }
|
||||
|
||||
// XXX There's currently no way to access the socket ID set for
|
||||
// whatever the queue is currently working. Required to find
|
||||
// some way to do this, possibly by having a "reverse pointer".
|
||||
// Currently just "unimplemented".
|
||||
std::string CONID() const { return ""; }
|
||||
/// Initialize the receiving queue.
|
||||
/// @param [in] size queue size
|
||||
/// @param [in] mss maximum packet size
|
||||
/// @param [in] version IP version
|
||||
/// @param [in] hsize hash table size
|
||||
/// @param [in] c UDP channel to be associated to the queue
|
||||
/// @param [in] t timer
|
||||
void init(int size, size_t payload, int version, int hsize, CChannel* c, sync::CTimer* t);
|
||||
|
||||
/// Initialize the receiving queue.
|
||||
/// @param [in] size queue size
|
||||
/// @param [in] mss maximum packet size
|
||||
/// @param [in] version IP version
|
||||
/// @param [in] hsize hash table size
|
||||
/// @param [in] c UDP channel to be associated to the queue
|
||||
/// @param [in] t timer
|
||||
/// Read a packet for a specific UDT socket id.
|
||||
/// @param [in] id Socket ID
|
||||
/// @param [out] packet received packet
|
||||
/// @return Data size of the packet
|
||||
int recvfrom(int32_t id, CPacket& to_packet);
|
||||
|
||||
void init(int size, int payload, int version, int hsize, CChannel* c, CTimer* t);
|
||||
void stopWorker();
|
||||
|
||||
/// Read a packet for a specific UDT socket id.
|
||||
/// @param [in] id Socket ID
|
||||
/// @param [out] packet received packet
|
||||
/// @return Data size of the packet
|
||||
void setClosing() { m_bClosing = true; }
|
||||
|
||||
int recvfrom(int32_t id, ref_t<CPacket> packet);
|
||||
|
||||
void setClosing()
|
||||
{
|
||||
m_bClosing = true;
|
||||
}
|
||||
int getIPversion() { return m_iIPversion; }
|
||||
|
||||
private:
|
||||
static void* worker(void* param);
|
||||
pthread_t m_WorkerThread;
|
||||
// Subroutines of worker
|
||||
EReadStatus worker_RetrieveUnit(ref_t<int32_t> id, ref_t<CUnit*> unit, sockaddr* sa);
|
||||
EConnectStatus worker_ProcessConnectionRequest(CUnit* unit, const sockaddr* sa);
|
||||
EConnectStatus worker_TryAsyncRend_OrStore(int32_t id, CUnit* unit, const sockaddr* sa);
|
||||
EConnectStatus worker_ProcessAddressedPacket(int32_t id, CUnit* unit, const sockaddr* sa);
|
||||
static void* worker(void* param);
|
||||
sync::CThread m_WorkerThread;
|
||||
// Subroutines of worker
|
||||
EReadStatus worker_RetrieveUnit(int32_t& id, CUnit*& unit, sockaddr_any& sa);
|
||||
EConnectStatus worker_ProcessConnectionRequest(CUnit* unit, const sockaddr_any& sa);
|
||||
EConnectStatus worker_TryAsyncRend_OrStore(int32_t id, CUnit* unit, const sockaddr_any& sa);
|
||||
EConnectStatus worker_ProcessAddressedPacket(int32_t id, CUnit* unit, const sockaddr_any& sa);
|
||||
|
||||
private:
|
||||
CUnitQueue m_UnitQueue; // The received packet queue
|
||||
CUnitQueue* m_pUnitQueue; // The received packet queue
|
||||
CRcvUList* m_pRcvUList; // List of UDT instances that will read packets from the queue
|
||||
CHash* m_pHash; // Hash table for UDT socket looking up
|
||||
CChannel* m_pChannel; // UDP channel for receving packets
|
||||
sync::CTimer* m_pTimer; // shared timer with the snd queue
|
||||
|
||||
CRcvUList* m_pRcvUList; // List of UDT instances that will read packets from the queue
|
||||
CHash* m_pHash; // Hash table for UDT socket looking up
|
||||
CChannel* m_pChannel; // UDP channel for receving packets
|
||||
CTimer* m_pTimer; // shared timer with the snd queue
|
||||
int m_iIPversion; // IP version
|
||||
size_t m_szPayloadSize; // packet payload size
|
||||
|
||||
int m_iPayloadSize; // packet payload size
|
||||
|
||||
volatile bool m_bClosing; // closing the worker
|
||||
sync::atomic<bool> m_bClosing; // closing the worker
|
||||
#if ENABLE_LOGGING
|
||||
static srt::sync::atomic<int> m_counter; // A static counter to log RcvQueue worker thread number.
|
||||
#endif
|
||||
|
||||
private:
|
||||
int setListener(CUDT* u);
|
||||
void removeListener(const CUDT* u);
|
||||
int setListener(CUDT* u);
|
||||
void removeListener(const CUDT* u);
|
||||
|
||||
void registerConnector(const SRTSOCKET& id, CUDT* u, int ipv, const sockaddr* addr, uint64_t ttl);
|
||||
void removeConnector(const SRTSOCKET& id, bool should_lock = true);
|
||||
void registerConnector(const SRTSOCKET& id,
|
||||
CUDT* u,
|
||||
const sockaddr_any& addr,
|
||||
const sync::steady_clock::time_point& ttl);
|
||||
void removeConnector(const SRTSOCKET& id);
|
||||
|
||||
void setNewEntry(CUDT* u);
|
||||
bool ifNewEntry();
|
||||
CUDT* getNewEntry();
|
||||
void setNewEntry(CUDT* u);
|
||||
bool ifNewEntry();
|
||||
CUDT* getNewEntry();
|
||||
|
||||
void storePkt(int32_t id, CPacket* pkt);
|
||||
void storePkt(int32_t id, CPacket* pkt);
|
||||
|
||||
private:
|
||||
pthread_mutex_t m_LSLock;
|
||||
CUDT* m_pListener; // pointer to the (unique, if any) listening UDT entity
|
||||
CRendezvousQueue* m_pRendezvousQueue; // The list of sockets in rendezvous mode
|
||||
sync::Mutex m_LSLock;
|
||||
CUDT* m_pListener; // pointer to the (unique, if any) listening UDT entity
|
||||
CRendezvousQueue* m_pRendezvousQueue; // The list of sockets in rendezvous mode
|
||||
|
||||
std::vector<CUDT*> m_vNewEntry; // newly added entries, to be inserted
|
||||
pthread_mutex_t m_IDLock;
|
||||
std::vector<CUDT*> m_vNewEntry; // newly added entries, to be inserted
|
||||
sync::Mutex m_IDLock;
|
||||
|
||||
std::map<int32_t, std::queue<CPacket*> > m_mBuffer; // temporary buffer for rendezvous connection request
|
||||
pthread_mutex_t m_PassLock;
|
||||
pthread_cond_t m_PassCond;
|
||||
std::map<int32_t, std::queue<CPacket*> > m_mBuffer; // temporary buffer for rendezvous connection request
|
||||
sync::Mutex m_BufferLock;
|
||||
sync::Condition m_BufferCond;
|
||||
|
||||
private:
|
||||
CRcvQueue(const CRcvQueue&);
|
||||
CRcvQueue& operator=(const CRcvQueue&);
|
||||
CRcvQueue(const CRcvQueue&);
|
||||
CRcvQueue& operator=(const CRcvQueue&);
|
||||
};
|
||||
|
||||
struct CMultiplexer
|
||||
{
|
||||
CSndQueue* m_pSndQueue; // The sending queue
|
||||
CRcvQueue* m_pRcvQueue; // The receiving queue
|
||||
CChannel* m_pChannel; // The UDP channel for sending and receiving
|
||||
CTimer* m_pTimer; // The timer
|
||||
CSndQueue* m_pSndQueue; // The sending queue
|
||||
CRcvQueue* m_pRcvQueue; // The receiving queue
|
||||
CChannel* m_pChannel; // The UDP channel for sending and receiving
|
||||
sync::CTimer* m_pTimer; // The timer
|
||||
|
||||
int m_iPort; // The UDP port number of this multiplexer
|
||||
int m_iIPversion; // IP version
|
||||
#ifdef SRT_ENABLE_IPOPTS
|
||||
int m_iIpTTL;
|
||||
int m_iIpToS;
|
||||
#endif
|
||||
int m_iMSS; // Maximum Segment Size
|
||||
int m_iRefCount; // number of UDT instances that are associated with this multiplexer
|
||||
int m_iIpV6Only; // IPV6_V6ONLY option
|
||||
bool m_bReusable; // if this one can be shared with others
|
||||
int m_iPort; // The UDP port number of this multiplexer
|
||||
int m_iIPversion; // Address family (AF_INET or AF_INET6)
|
||||
int m_iRefCount; // number of UDT instances that are associated with this multiplexer
|
||||
|
||||
int m_iID; // multiplexer ID
|
||||
CSrtMuxerConfig m_mcfg;
|
||||
|
||||
int m_iID; // multiplexer ID
|
||||
|
||||
// Constructor should reset all pointers to NULL
|
||||
// to prevent dangling pointer when checking for memory alloc fails
|
||||
CMultiplexer()
|
||||
: m_pSndQueue(NULL)
|
||||
, m_pRcvQueue(NULL)
|
||||
, m_pChannel(NULL)
|
||||
, m_pTimer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void destroy();
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
1020
trunk/3rdparty/srt-1-fit/srtcore/socketconfig.cpp
vendored
Normal file
1020
trunk/3rdparty/srt-1-fit/srtcore/socketconfig.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
377
trunk/3rdparty/srt-1-fit/srtcore/socketconfig.h
vendored
Normal file
377
trunk/3rdparty/srt-1-fit/srtcore/socketconfig.h
vendored
Normal file
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.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
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC_SRT_SOCKETCONFIG_H
|
||||
#define INC_SRT_SOCKETCONFIG_H
|
||||
|
||||
#include "platform_sys.h"
|
||||
#ifdef SRT_ENABLE_BINDTODEVICE
|
||||
#include <linux/if.h>
|
||||
#endif
|
||||
#include <string>
|
||||
#include "haicrypt.h"
|
||||
#include "congctl.h"
|
||||
#include "packet.h"
|
||||
#include "handshake.h"
|
||||
#include "logger_defs.h"
|
||||
#include "packetfilter.h"
|
||||
|
||||
// SRT Version constants
|
||||
#define SRT_VERSION_UNK 0
|
||||
#define SRT_VERSION_MAJ1 0x010000 /* Version 1 major */
|
||||
#define SRT_VERSION_MAJ(v) (0xFF0000 & (v)) /* Major number ensuring backward compatibility */
|
||||
#define SRT_VERSION_MIN(v) (0x00FF00 & (v))
|
||||
#define SRT_VERSION_PCH(v) (0x0000FF & (v))
|
||||
|
||||
// NOTE: SRT_VERSION is primarily defined in the build file.
|
||||
extern const int32_t SRT_DEF_VERSION;
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
struct CSrtMuxerConfig
|
||||
{
|
||||
static const int DEF_UDP_BUFFER_SIZE = 65536;
|
||||
|
||||
int iIpTTL;
|
||||
int iIpToS;
|
||||
int iIpV6Only; // IPV6_V6ONLY option (-1 if not set)
|
||||
bool bReuseAddr; // reuse an exiting port or not, for UDP multiplexer
|
||||
|
||||
#ifdef SRT_ENABLE_BINDTODEVICE
|
||||
std::string sBindToDevice;
|
||||
#endif
|
||||
int iUDPSndBufSize; // UDP sending buffer size
|
||||
int iUDPRcvBufSize; // UDP receiving buffer size
|
||||
|
||||
bool operator==(const CSrtMuxerConfig& other) const
|
||||
{
|
||||
#define CEQUAL(field) (field == other.field)
|
||||
return CEQUAL(iIpTTL)
|
||||
&& CEQUAL(iIpToS)
|
||||
&& CEQUAL(iIpV6Only)
|
||||
&& CEQUAL(bReuseAddr)
|
||||
#ifdef SRT_ENABLE_BINDTODEVICE
|
||||
&& CEQUAL(sBindToDevice)
|
||||
#endif
|
||||
&& CEQUAL(iUDPSndBufSize)
|
||||
&& CEQUAL(iUDPRcvBufSize);
|
||||
#undef CEQUAL
|
||||
}
|
||||
|
||||
CSrtMuxerConfig()
|
||||
: iIpTTL(-1) /* IPv4 TTL or IPv6 HOPs [1..255] (-1:undefined) */
|
||||
, iIpToS(-1) /* IPv4 Type of Service or IPv6 Traffic Class [0x00..0xff] (-1:undefined) */
|
||||
, iIpV6Only(-1)
|
||||
, bReuseAddr(true) // This is default in SRT
|
||||
, iUDPSndBufSize(DEF_UDP_BUFFER_SIZE)
|
||||
, iUDPRcvBufSize(DEF_UDP_BUFFER_SIZE)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct CSrtConfig;
|
||||
|
||||
template <size_t SIZE>
|
||||
class StringStorage
|
||||
{
|
||||
char stor[SIZE + 1];
|
||||
uint16_t len;
|
||||
|
||||
// NOTE: default copying allowed.
|
||||
|
||||
public:
|
||||
StringStorage()
|
||||
: len(0)
|
||||
{
|
||||
memset(stor, 0, sizeof stor);
|
||||
}
|
||||
|
||||
bool set(const char* s, size_t length)
|
||||
{
|
||||
if (length > SIZE)
|
||||
return false;
|
||||
|
||||
memcpy(stor, s, length);
|
||||
stor[length] = 0;
|
||||
len = (int) length;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set(const std::string& s)
|
||||
{
|
||||
return set(s.c_str(), s.size());
|
||||
}
|
||||
|
||||
std::string str() const
|
||||
{
|
||||
return len == 0 ? std::string() : std::string(stor);
|
||||
}
|
||||
|
||||
const char* c_str() const
|
||||
{
|
||||
return stor;
|
||||
}
|
||||
|
||||
size_t size() const { return size_t(len); }
|
||||
bool empty() const { return len == 0; }
|
||||
};
|
||||
|
||||
struct CSrtConfig: CSrtMuxerConfig
|
||||
{
|
||||
typedef srt::sync::steady_clock::time_point time_point;
|
||||
typedef srt::sync::steady_clock::duration duration;
|
||||
|
||||
static const int
|
||||
DEF_MSS = 1500,
|
||||
DEF_FLIGHT_SIZE = 25600,
|
||||
DEF_BUFFER_SIZE = 8192, //Rcv buffer MUST NOT be bigger than Flight Flag size
|
||||
DEF_LINGER_S = 3*60, // 3 minutes
|
||||
DEF_CONNTIMEO_S = 3; // 3 seconds
|
||||
|
||||
static const int COMM_RESPONSE_TIMEOUT_MS = 5 * 1000; // 5 seconds
|
||||
static const uint32_t COMM_DEF_MIN_STABILITY_TIMEOUT_MS = 60; // 60 ms
|
||||
|
||||
// Mimimum recv flight flag size is 32 packets
|
||||
static const int DEF_MIN_FLIGHT_PKT = 32;
|
||||
static const size_t MAX_SID_LENGTH = 512;
|
||||
static const size_t MAX_PFILTER_LENGTH = 64;
|
||||
static const size_t MAX_CONG_LENGTH = 16;
|
||||
|
||||
int iMSS; // Maximum Segment Size, in bytes
|
||||
size_t zExpPayloadSize; // Expected average payload size (user option)
|
||||
|
||||
// Options
|
||||
bool bSynSending; // Sending syncronization mode
|
||||
bool bSynRecving; // Receiving syncronization mode
|
||||
int iFlightFlagSize; // Maximum number of packets in flight from the peer side
|
||||
int iSndBufSize; // Maximum UDT sender buffer size
|
||||
int iRcvBufSize; // Maximum UDT receiver buffer size
|
||||
linger Linger; // Linger information on close
|
||||
bool bRendezvous; // Rendezvous connection mode
|
||||
|
||||
duration tdConnTimeOut; // connect timeout in milliseconds
|
||||
bool bDriftTracer;
|
||||
int iSndTimeOut; // sending timeout in milliseconds
|
||||
int iRcvTimeOut; // receiving timeout in milliseconds
|
||||
int64_t llMaxBW; // maximum data transfer rate (threshold)
|
||||
|
||||
// These fields keep the options for encryption
|
||||
// (SRTO_PASSPHRASE, SRTO_PBKEYLEN). Crypto object is
|
||||
// created later and takes values from these.
|
||||
HaiCrypt_Secret CryptoSecret;
|
||||
int iSndCryptoKeyLen;
|
||||
|
||||
// XXX Consider removing. The bDataSender stays here
|
||||
// in order to maintain the HS side selection in HSv4.
|
||||
bool bDataSender;
|
||||
|
||||
bool bMessageAPI;
|
||||
bool bTSBPD; // Whether AGENT will do TSBPD Rx (whether peer does, is not agent's problem)
|
||||
int iRcvLatency; // Agent's Rx latency
|
||||
int iPeerLatency; // Peer's Rx latency for the traffic made by Agent's Tx.
|
||||
bool bTLPktDrop; // Whether Agent WILL DO TLPKTDROP on Rx.
|
||||
int iSndDropDelay; // Extra delay when deciding to snd-drop for TLPKTDROP, -1 to off
|
||||
bool bEnforcedEnc; // Off by default. When on, any connection other than nopw-nopw & pw1-pw1 is rejected.
|
||||
int iGroupConnect; // 1 - allow group connections
|
||||
int iPeerIdleTimeout_ms; // Timeout for hearing anything from the peer (ms).
|
||||
uint32_t uMinStabilityTimeout_ms;
|
||||
int iRetransmitAlgo;
|
||||
|
||||
int64_t llInputBW; // Input stream rate (bytes/sec). 0: use internally estimated input bandwidth
|
||||
int64_t llMinInputBW; // Minimum input stream rate estimate (bytes/sec)
|
||||
int iOverheadBW; // Percent above input stream rate (applies if llMaxBW == 0)
|
||||
bool bRcvNakReport; // Enable Receiver Periodic NAK Reports
|
||||
int iMaxReorderTolerance; //< Maximum allowed value for dynamic reorder tolerance
|
||||
|
||||
// For the use of CCryptoControl
|
||||
// HaiCrypt configuration
|
||||
unsigned int uKmRefreshRatePkt;
|
||||
unsigned int uKmPreAnnouncePkt;
|
||||
|
||||
uint32_t uSrtVersion;
|
||||
uint32_t uMinimumPeerSrtVersion;
|
||||
|
||||
StringStorage<MAX_CONG_LENGTH> sCongestion;
|
||||
StringStorage<MAX_PFILTER_LENGTH> sPacketFilterConfig;
|
||||
StringStorage<MAX_SID_LENGTH> sStreamName;
|
||||
|
||||
// Shortcuts and utilities
|
||||
int32_t flightCapacity()
|
||||
{
|
||||
return std::min(iRcvBufSize, iFlightFlagSize);
|
||||
}
|
||||
|
||||
CSrtConfig()
|
||||
: iMSS(DEF_MSS)
|
||||
, zExpPayloadSize(SRT_LIVE_DEF_PLSIZE)
|
||||
, bSynSending(true)
|
||||
, bSynRecving(true)
|
||||
, iFlightFlagSize(DEF_FLIGHT_SIZE)
|
||||
, iSndBufSize(DEF_BUFFER_SIZE)
|
||||
, iRcvBufSize(DEF_BUFFER_SIZE)
|
||||
, bRendezvous(false)
|
||||
, tdConnTimeOut(srt::sync::seconds_from(DEF_CONNTIMEO_S))
|
||||
, bDriftTracer(true)
|
||||
, iSndTimeOut(-1)
|
||||
, iRcvTimeOut(-1)
|
||||
, llMaxBW(-1)
|
||||
, bDataSender(false)
|
||||
, bMessageAPI(true)
|
||||
, bTSBPD(true)
|
||||
, iRcvLatency(SRT_LIVE_DEF_LATENCY_MS)
|
||||
, iPeerLatency(0)
|
||||
, bTLPktDrop(true)
|
||||
, iSndDropDelay(0)
|
||||
, bEnforcedEnc(true)
|
||||
, iGroupConnect(0)
|
||||
, iPeerIdleTimeout_ms(COMM_RESPONSE_TIMEOUT_MS)
|
||||
, uMinStabilityTimeout_ms(COMM_DEF_MIN_STABILITY_TIMEOUT_MS)
|
||||
, iRetransmitAlgo(1)
|
||||
, llInputBW(0)
|
||||
, llMinInputBW(0)
|
||||
, iOverheadBW(25)
|
||||
, bRcvNakReport(true)
|
||||
, iMaxReorderTolerance(0) // Sensible optimal value is 10, 0 preserves old behavior
|
||||
, uKmRefreshRatePkt(0)
|
||||
, uKmPreAnnouncePkt(0)
|
||||
, uSrtVersion(SRT_DEF_VERSION)
|
||||
, uMinimumPeerSrtVersion(SRT_VERSION_MAJ1)
|
||||
|
||||
{
|
||||
// Default UDT configurations
|
||||
iUDPRcvBufSize = iRcvBufSize * iMSS;
|
||||
|
||||
// Linger: LIVE mode defaults, please refer to `SRTO_TRANSTYPE` option
|
||||
// for other modes.
|
||||
Linger.l_onoff = 0;
|
||||
Linger.l_linger = 0;
|
||||
CryptoSecret.len = 0;
|
||||
iSndCryptoKeyLen = 0;
|
||||
|
||||
// Default congestion is "live".
|
||||
// Available builtin congestions: "file".
|
||||
// Others can be registerred.
|
||||
sCongestion.set("live", 4);
|
||||
}
|
||||
|
||||
~CSrtConfig()
|
||||
{
|
||||
// Wipeout critical data
|
||||
memset(&CryptoSecret, 0, sizeof(CryptoSecret));
|
||||
}
|
||||
|
||||
int set(SRT_SOCKOPT optName, const void* val, int size);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline T cast_optval(const void* optval)
|
||||
{
|
||||
return *reinterpret_cast<const T*>(optval);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T cast_optval(const void* optval, int optlen)
|
||||
{
|
||||
if (optlen > 0 && optlen != sizeof(T))
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
|
||||
return cast_optval<T>(optval);
|
||||
}
|
||||
|
||||
// This function is to make it possible for both C and C++
|
||||
// API to accept both bool and int types for boolean options.
|
||||
// (it's not that C couldn't use <stdbool.h>, it's that people
|
||||
// often forget to use correct type).
|
||||
template <>
|
||||
inline bool cast_optval(const void* optval, int optlen)
|
||||
{
|
||||
if (optlen == sizeof(bool))
|
||||
{
|
||||
return *reinterpret_cast<const bool*>(optval);
|
||||
}
|
||||
|
||||
if (optlen == sizeof(int))
|
||||
{
|
||||
// 0!= is a windows warning-killer int-to-bool conversion
|
||||
return 0 != *reinterpret_cast<const int*>(optval);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace srt
|
||||
|
||||
struct SRT_SocketOptionObject
|
||||
{
|
||||
struct SingleOption
|
||||
{
|
||||
uint16_t option;
|
||||
uint16_t length;
|
||||
unsigned char storage[1]; // NOTE: Variable length object!
|
||||
};
|
||||
|
||||
std::vector<SingleOption*> options;
|
||||
|
||||
SRT_SocketOptionObject() {}
|
||||
|
||||
~SRT_SocketOptionObject()
|
||||
{
|
||||
for (size_t i = 0; i < options.size(); ++i)
|
||||
{
|
||||
// Convert back
|
||||
unsigned char* mem = reinterpret_cast<unsigned char*>(options[i]);
|
||||
delete[] mem;
|
||||
}
|
||||
}
|
||||
|
||||
bool add(SRT_SOCKOPT optname, const void* optval, size_t optlen);
|
||||
};
|
||||
|
||||
#endif
|
600
trunk/3rdparty/srt-1-fit/srtcore/srt.h
vendored
600
trunk/3rdparty/srt-1-fit/srtcore/srt.h
vendored
|
@ -13,8 +13,8 @@ written by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC__SRTC_H
|
||||
#define INC__SRTC_H
|
||||
#ifndef INC_SRTC_H
|
||||
#define INC_SRTC_H
|
||||
|
||||
#include "version.h"
|
||||
|
||||
|
@ -23,7 +23,6 @@ written by
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "srt4udt.h"
|
||||
#include "logging_api.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -36,7 +35,7 @@ written by
|
|||
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef __MINGW__
|
||||
#ifndef __MINGW32__
|
||||
// Explicitly define 32-bit and 64-bit numbers
|
||||
typedef __int32 int32_t;
|
||||
typedef __int64 int64_t;
|
||||
|
@ -47,17 +46,14 @@ written by
|
|||
// VC 6.0 does not support unsigned __int64: may cause potential problems.
|
||||
typedef __int64 uint64_t;
|
||||
#endif
|
||||
|
||||
#ifdef SRT_DYNAMIC
|
||||
#ifdef SRT_EXPORTS
|
||||
#define SRT_API __declspec(dllexport)
|
||||
#else
|
||||
#define SRT_API __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
#ifdef SRT_DYNAMIC
|
||||
#ifdef SRT_EXPORTS
|
||||
#define SRT_API __declspec(dllexport)
|
||||
#else
|
||||
#define SRT_API
|
||||
#define SRT_API __declspec(dllimport)
|
||||
#endif
|
||||
#else // __MINGW__
|
||||
#else // !SRT_DYNAMIC
|
||||
#define SRT_API
|
||||
#endif
|
||||
#else
|
||||
|
@ -69,48 +65,99 @@ written by
|
|||
// You can use these constants with SRTO_MINVERSION option.
|
||||
#define SRT_VERSION_FEAT_HSv5 0x010300
|
||||
|
||||
#if defined(__cplusplus) && __cplusplus > 201406
|
||||
#define SRT_HAVE_CXX17 1
|
||||
#else
|
||||
#define SRT_HAVE_CXX17 0
|
||||
#endif
|
||||
|
||||
|
||||
// Stadnard attributes
|
||||
|
||||
// When compiling in C++17 mode, use the standard C++17 attributes
|
||||
// (out of these, only [[deprecated]] is supported in C++14, so
|
||||
// for all lesser standard use compiler-specific attributes).
|
||||
#if defined(SRT_NO_DEPRECATED)
|
||||
|
||||
#define SRT_ATR_UNUSED
|
||||
#define SRT_ATR_DEPRECATED
|
||||
#define SRT_ATR_NODISCARD
|
||||
|
||||
#elif defined(__cplusplus) && __cplusplus > 201406
|
||||
#if SRT_HAVE_CXX17
|
||||
|
||||
// Unused: DO NOT issue a warning if this entity is unused.
|
||||
#define SRT_ATR_UNUSED [[maybe_unused]]
|
||||
#define SRT_ATR_DEPRECATED [[deprecated]]
|
||||
|
||||
// Nodiscard: issue a warning if the return value was discarded.
|
||||
#define SRT_ATR_NODISCARD [[nodiscard]]
|
||||
|
||||
// GNUG is GNU C/C++; this syntax is also supported by Clang
|
||||
#elif defined( __GNUC__)
|
||||
#elif defined(__GNUC__)
|
||||
#define SRT_ATR_UNUSED __attribute__((unused))
|
||||
#define SRT_ATR_DEPRECATED __attribute__((deprecated))
|
||||
#define SRT_ATR_NODISCARD __attribute__((warn_unused_result))
|
||||
#elif defined(_MSC_VER)
|
||||
#define SRT_ATR_UNUSED __pragma(warning(suppress: 4100 4101))
|
||||
#define SRT_ATR_NODISCARD _Check_return_
|
||||
#else
|
||||
#define SRT_ATR_UNUSED
|
||||
#define SRT_ATR_DEPRECATED
|
||||
#define SRT_ATR_NODISCARD
|
||||
#endif
|
||||
|
||||
|
||||
// DEPRECATED attributes
|
||||
|
||||
// There's needed DEPRECATED and DEPRECATED_PX, as some compilers require them
|
||||
// before the entity, others after the entity.
|
||||
// The *_PX version is the prefix attribute, which applies only
|
||||
// to functions (Microsoft compilers).
|
||||
|
||||
// When deprecating a function, mark it:
|
||||
//
|
||||
// SRT_ATR_DEPRECATED_PX retval function(arguments) SRT_ATR_DEPRECATED;
|
||||
//
|
||||
|
||||
// When SRT_NO_DEPRECATED defined, do not issue any deprecation warnings.
|
||||
// Regardless of the compiler type.
|
||||
#if defined(SRT_NO_DEPRECATED)
|
||||
|
||||
#define SRT_ATR_DEPRECATED
|
||||
#define SRT_ATR_DEPRECATED_PX
|
||||
|
||||
#elif SRT_HAVE_CXX17
|
||||
|
||||
#define SRT_ATR_DEPRECATED
|
||||
#define SRT_ATR_DEPRECATED_PX [[deprecated]]
|
||||
|
||||
// GNUG is GNU C/C++; this syntax is also supported by Clang
|
||||
#elif defined(__GNUC__)
|
||||
#define SRT_ATR_DEPRECATED_PX
|
||||
#define SRT_ATR_DEPRECATED __attribute__((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
#define SRT_ATR_DEPRECATED_PX __declspec(deprecated)
|
||||
#define SRT_ATR_DEPRECATED // no postfix-type modifier
|
||||
#else
|
||||
#define SRT_ATR_DEPRECATED_PX
|
||||
#define SRT_ATR_DEPRECATED
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int SRTSOCKET; // SRTSOCKET is a typedef to int anyway, and it's not even in UDT namespace :)
|
||||
typedef int32_t SRTSOCKET;
|
||||
|
||||
// The most significant bit 31 (sign bit actually) is left unused,
|
||||
// so that all people who check the value for < 0 instead of -1
|
||||
// still get what they want. The bit 30 is reserved for marking
|
||||
// the "socket group". Most of the API functions should work
|
||||
// transparently with the socket descriptor designating a single
|
||||
// socket or a socket group.
|
||||
static const int32_t SRTGROUP_MASK = (1 << 30);
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef __MINGW__
|
||||
typedef SOCKET SYSSOCKET;
|
||||
#else
|
||||
typedef int SYSSOCKET;
|
||||
#endif
|
||||
typedef SOCKET SYSSOCKET;
|
||||
#else
|
||||
typedef int SYSSOCKET;
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_BONDING
|
||||
#define ENABLE_BONDING 0
|
||||
#endif
|
||||
|
||||
typedef SYSSOCKET UDPSOCKET;
|
||||
|
||||
|
||||
|
@ -141,8 +188,7 @@ typedef enum SRT_SOCKOPT {
|
|||
SRTO_LINGER = 7, // waiting for unsent data when closing
|
||||
SRTO_UDP_SNDBUF = 8, // UDP sending buffer size
|
||||
SRTO_UDP_RCVBUF = 9, // UDP receiving buffer size
|
||||
// XXX Free space for 2 options
|
||||
// after deprecated ones are removed
|
||||
// (some space left)
|
||||
SRTO_RENDEZVOUS = 12, // rendezvous connection mode
|
||||
SRTO_SNDTIMEO = 13, // send() timeout
|
||||
SRTO_RCVTIMEO = 14, // recv() timeout
|
||||
|
@ -155,11 +201,10 @@ typedef enum SRT_SOCKOPT {
|
|||
SRTO_SENDER = 21, // Sender mode (independent of conn mode), for encryption, tsbpd handshake.
|
||||
SRTO_TSBPDMODE = 22, // Enable/Disable TsbPd. Enable -> Tx set origin timestamp, Rx deliver packet at origin time + delay
|
||||
SRTO_LATENCY = 23, // NOT RECOMMENDED. SET: to both SRTO_RCVLATENCY and SRTO_PEERLATENCY. GET: same as SRTO_RCVLATENCY.
|
||||
SRTO_TSBPDDELAY = 23, // DEPRECATED. ALIAS: SRTO_LATENCY
|
||||
SRTO_INPUTBW = 24, // Estimated input stream rate.
|
||||
SRTO_OHEADBW, // MaxBW ceiling based on % over input stream rate. Applies when UDT_MAXBW=0 (auto).
|
||||
SRTO_PASSPHRASE = 26, // Crypto PBKDF2 Passphrase size[0,10..64] 0:disable crypto
|
||||
SRTO_PBKEYLEN, // Crypto key len in bytes {16,24,32} Default: 16 (128-bit)
|
||||
SRTO_PASSPHRASE = 26, // Crypto PBKDF2 Passphrase (must be 10..79 characters, or empty to disable encryption)
|
||||
SRTO_PBKEYLEN, // Crypto key len in bytes {16,24,32} Default: 16 (AES-128)
|
||||
SRTO_KMSTATE, // Key Material exchange status (UDT_SRTKmState)
|
||||
SRTO_IPTTL = 29, // IP Time To Live (passthru for system sockopt IPPROTO_IP/IP_TTL)
|
||||
SRTO_IPTOS, // IP Type of Service (passthru for system sockopt IPPROTO_IP/IP_TOS)
|
||||
|
@ -168,10 +213,10 @@ typedef enum SRT_SOCKOPT {
|
|||
SRTO_NAKREPORT = 33, // Enable receiver to send periodic NAK reports
|
||||
SRTO_VERSION = 34, // Local SRT Version
|
||||
SRTO_PEERVERSION, // Peer SRT Version (from SRT Handshake)
|
||||
SRTO_CONNTIMEO = 36, // Connect timeout in msec. Ccaller default: 3000, rendezvous (x 10)
|
||||
// deprecated: SRTO_TWOWAYDATA, SRTO_SNDPBKEYLEN, SRTO_RCVPBKEYLEN (@c below)
|
||||
_DEPRECATED_SRTO_SNDPBKEYLEN = 38, // (needed to use inside the code without generating -Wswitch)
|
||||
//
|
||||
SRTO_CONNTIMEO = 36, // Connect timeout in msec. Caller default: 3000, rendezvous (x 10)
|
||||
SRTO_DRIFTTRACER = 37, // Enable or disable drift tracer
|
||||
SRTO_MININPUTBW = 38, // Minimum estimate of input stream rate.
|
||||
// (some space left)
|
||||
SRTO_SNDKMSTATE = 40, // (GET) the current state of the encryption at the peer side
|
||||
SRTO_RCVKMSTATE, // (GET) the current state of the encryption at the agent side
|
||||
SRTO_LOSSMAXTTL, // Maximum possible packet reorder tolerance (number of packets to receive after loss to send lossreport)
|
||||
|
@ -188,15 +233,34 @@ typedef enum SRT_SOCKOPT {
|
|||
SRTO_ENFORCEDENCRYPTION, // Connection to be rejected or quickly broken when one side encryption set or bad password
|
||||
SRTO_IPV6ONLY, // IPV6_V6ONLY mode
|
||||
SRTO_PEERIDLETIMEO, // Peer-idle timeout (max time of silence heard from peer) in [ms]
|
||||
// (some space left)
|
||||
SRTO_PACKETFILTER = 60 // Add and configure a packet filter
|
||||
SRTO_BINDTODEVICE, // Forward the SOL_SOCKET/SO_BINDTODEVICE option on socket (pass packets only from that device)
|
||||
SRTO_GROUPCONNECT, // Set on a listener to allow group connection (ENABLE_BONDING)
|
||||
SRTO_GROUPMINSTABLETIMEO, // Minimum Link Stability timeout (backup mode) in milliseconds (ENABLE_BONDING)
|
||||
SRTO_GROUPTYPE, // Group type to which an accepted socket is about to be added, available in the handshake (ENABLE_BONDING)
|
||||
SRTO_PACKETFILTER = 60, // Add and configure a packet filter
|
||||
SRTO_RETRANSMITALGO = 61, // An option to select packet retransmission algorithm
|
||||
|
||||
SRTO_E_SIZE // Always last element, not a valid option.
|
||||
} SRT_SOCKOPT;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
typedef SRT_ATR_DEPRECATED SRT_SOCKOPT SRT_SOCKOPT_DEPRECATED;
|
||||
|
||||
#if __cplusplus > 199711L // C++11
|
||||
// Newer compilers report error when [[deprecated]] is applied to types,
|
||||
// and C++11 and higher uses this.
|
||||
// Note that this doesn't exactly use the 'deprecated' attribute,
|
||||
// as it's introduced in C++14. What is actually used here is the
|
||||
// fact that unknown attributes are ignored, but still warned about.
|
||||
// This should only catch an eye - and that's what it does.
|
||||
#define SRT_DEPRECATED_OPTION(value) ((SRT_SOCKOPT [[deprecated]])value)
|
||||
#else
|
||||
// Older (pre-C++11) compilers use gcc deprecated applied to a typedef
|
||||
typedef SRT_ATR_DEPRECATED_PX SRT_SOCKOPT SRT_SOCKOPT_DEPRECATED SRT_ATR_DEPRECATED;
|
||||
#define SRT_DEPRECATED_OPTION(value) ((SRT_SOCKOPT_DEPRECATED)value)
|
||||
#endif
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
@ -213,46 +277,9 @@ enum SRT_ATR_DEPRECATED SRT_SOCKOPT_DEPRECATED
|
|||
#define SRT_DEPRECATED_OPTION(value) ((enum SRT_SOCKOPT_DEPRECATED)value)
|
||||
#endif
|
||||
|
||||
// DEPRECATED OPTIONS:
|
||||
|
||||
// SRTO_TWOWAYDATA: not to be used. SRT connection is always bidirectional if
|
||||
// both clients support HSv5 - that is, since version 1.3.0. This flag was
|
||||
// introducted around 1.2.0 version when full bidirectional support was added,
|
||||
// but the bidirectional feature was decided no to be enabled due to huge
|
||||
// differences between bidirectional support (especially concerning encryption)
|
||||
// with HSv4 and HSv5 (that is, HSv4 was decided to remain unidirectional only,
|
||||
// even though partial support is already provided in this version).
|
||||
|
||||
#define SRTO_TWOWAYDATA SRT_DEPRECATED_OPTION(37)
|
||||
|
||||
// This has been deprecated a long time ago, treat this as never implemented.
|
||||
// The value is also already reused for another option.
|
||||
#define SRTO_TSBPDMAXLAG SRT_DEPRECATED_OPTION(32)
|
||||
|
||||
// This option is a derivative from UDT; the mechanism that uses it is now
|
||||
// settable by SRTO_CONGESTION, or more generally by SRTO_TRANSTYPE. The freed
|
||||
// number has been reused for a read-only option SRTO_ISN. This option should
|
||||
// have never been used anywhere, just for safety this is temporarily declared
|
||||
// as deprecated.
|
||||
#define SRTO_CC SRT_DEPRECATED_OPTION(3)
|
||||
|
||||
// These two flags were derived from UDT, but they were never used.
|
||||
// Probably it didn't make sense anyway. The maximum size of the message
|
||||
// in File/Message mode is defined by SRTO_SNDBUF, and the MSGTTL is
|
||||
// a parameter used in `srt_sendmsg` and `srt_sendmsg2`.
|
||||
#define SRTO_MAXMSG SRT_DEPRECATED_OPTION(10)
|
||||
#define SRTO_MSGTTL SRT_DEPRECATED_OPTION(11)
|
||||
|
||||
// These flags come from an older experimental implementation of bidirectional
|
||||
// encryption support, which were used two different SEKs, KEKs and passphrases
|
||||
// per direction. The current implementation uses just one in both directions,
|
||||
// so SRTO_PBKEYLEN should be used for both cases.
|
||||
#define SRTO_SNDPBKEYLEN SRT_DEPRECATED_OPTION(38)
|
||||
#define SRTO_RCVPBKEYLEN SRT_DEPRECATED_OPTION(39)
|
||||
|
||||
// Keeping old name for compatibility (deprecated)
|
||||
#define SRTO_SMOOTHER SRT_DEPRECATED_OPTION(47)
|
||||
#define SRTO_STRICTENC SRT_DEPRECATED_OPTION(53)
|
||||
// Note that there are no deprecated options at the moment, but the mechanism
|
||||
// stays so that it can be used in future. Example:
|
||||
// #define SRTO_STRICTENC SRT_DEPRECATED_OPTION(53)
|
||||
|
||||
typedef enum SRT_TRANSTYPE
|
||||
{
|
||||
|
@ -295,9 +322,7 @@ struct CBytePerfMon
|
|||
int pktRcvUndecryptTotal; // number of undecrypted packets
|
||||
uint64_t byteSentTotal; // total number of sent data bytes, including retransmissions
|
||||
uint64_t byteRecvTotal; // total number of received bytes
|
||||
#ifdef SRT_ENABLE_LOSTBYTESCOUNT
|
||||
uint64_t byteRcvLossTotal; // total number of lost bytes
|
||||
#endif
|
||||
uint64_t byteRetransTotal; // total number of retransmitted bytes
|
||||
uint64_t byteSndDropTotal; // number of too-late-to-send dropped bytes
|
||||
uint64_t byteRcvDropTotal; // number of too-late-to play missing bytes (estimate based on average packet size)
|
||||
|
@ -327,9 +352,7 @@ struct CBytePerfMon
|
|||
int pktRcvUndecrypt; // number of undecrypted packets
|
||||
uint64_t byteSent; // number of sent data bytes, including retransmissions
|
||||
uint64_t byteRecv; // number of received bytes
|
||||
#ifdef SRT_ENABLE_LOSTBYTESCOUNT
|
||||
uint64_t byteRcvLoss; // number of retransmitted bytes
|
||||
#endif
|
||||
uint64_t byteRetrans; // number of retransmitted bytes
|
||||
uint64_t byteSndDrop; // number of too-late-to-send dropped bytes
|
||||
uint64_t byteRcvDrop; // number of too-late-to play missing bytes (estimate based on average packet size)
|
||||
|
@ -370,6 +393,20 @@ struct CBytePerfMon
|
|||
int pktRcvFilterLoss; // number of packet loss not coverable by filter
|
||||
int pktReorderTolerance; // packet reorder tolerance value
|
||||
//<
|
||||
|
||||
// New stats in 1.5.0
|
||||
|
||||
// Total
|
||||
int64_t pktSentUniqueTotal; // total number of data packets sent by the application
|
||||
int64_t pktRecvUniqueTotal; // total number of packets to be received by the application
|
||||
uint64_t byteSentUniqueTotal; // total number of data bytes, sent by the application
|
||||
uint64_t byteRecvUniqueTotal; // total number of data bytes to be received by the application
|
||||
|
||||
// Local
|
||||
int64_t pktSentUnique; // number of data packets sent by the application
|
||||
int64_t pktRecvUnique; // number of packets to be received by the application
|
||||
uint64_t byteSentUnique; // number of data bytes, sent by the application
|
||||
uint64_t byteRecvUnique; // number of data bytes to be received by the application
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -399,12 +436,14 @@ enum CodeMinor
|
|||
MN_REJECTED = 2,
|
||||
MN_NORES = 3,
|
||||
MN_SECURITY = 4,
|
||||
MN_CLOSED = 5,
|
||||
// MJ_CONNECTION
|
||||
MN_CONNLOST = 1,
|
||||
MN_NOCONN = 2,
|
||||
// MJ_SYSTEMRES
|
||||
MN_THREAD = 1,
|
||||
MN_MEMORY = 2,
|
||||
MN_OBJECT = 3,
|
||||
// MJ_FILESYSTEM
|
||||
MN_SEEKGFAIL = 1,
|
||||
MN_READFAIL = 2,
|
||||
|
@ -424,6 +463,8 @@ enum CodeMinor
|
|||
MN_BUSY = 11,
|
||||
MN_XSIZE = 12,
|
||||
MN_EIDINVAL = 13,
|
||||
MN_EEMPTY = 14,
|
||||
MN_BUSYPORT = 15,
|
||||
// MJ_AGAIN
|
||||
MN_WRAVAIL = 1,
|
||||
MN_RDAVAIL = 2,
|
||||
|
@ -431,12 +472,10 @@ enum CodeMinor
|
|||
MN_CONGESTION = 4
|
||||
};
|
||||
|
||||
static const enum CodeMinor MN_ISSTREAM SRT_ATR_DEPRECATED = (enum CodeMinor)(9);
|
||||
static const enum CodeMinor MN_ISDGRAM SRT_ATR_DEPRECATED = (enum CodeMinor)(10);
|
||||
|
||||
// Stupid, but effective. This will be #undefined, so don't worry.
|
||||
#define MJ(major) (1000 * MJ_##major)
|
||||
#define MN(major, minor) (1000 * MJ_##major + MN_##minor)
|
||||
#define SRT_EMJ(major) (1000 * MJ_##major)
|
||||
#define SRT_EMN(major, minor) (1000 * MJ_##major + MN_##minor)
|
||||
|
||||
// Some better way to define it, and better for C language.
|
||||
typedef enum SRT_ERRNO
|
||||
|
@ -444,55 +483,56 @@ typedef enum SRT_ERRNO
|
|||
SRT_EUNKNOWN = -1,
|
||||
SRT_SUCCESS = MJ_SUCCESS,
|
||||
|
||||
SRT_ECONNSETUP = MJ(SETUP),
|
||||
SRT_ENOSERVER = MN(SETUP, TIMEOUT),
|
||||
SRT_ECONNREJ = MN(SETUP, REJECTED),
|
||||
SRT_ESOCKFAIL = MN(SETUP, NORES),
|
||||
SRT_ESECFAIL = MN(SETUP, SECURITY),
|
||||
SRT_ECONNSETUP = SRT_EMJ(SETUP),
|
||||
SRT_ENOSERVER = SRT_EMN(SETUP, TIMEOUT),
|
||||
SRT_ECONNREJ = SRT_EMN(SETUP, REJECTED),
|
||||
SRT_ESOCKFAIL = SRT_EMN(SETUP, NORES),
|
||||
SRT_ESECFAIL = SRT_EMN(SETUP, SECURITY),
|
||||
SRT_ESCLOSED = SRT_EMN(SETUP, CLOSED),
|
||||
|
||||
SRT_ECONNFAIL = MJ(CONNECTION),
|
||||
SRT_ECONNLOST = MN(CONNECTION, CONNLOST),
|
||||
SRT_ENOCONN = MN(CONNECTION, NOCONN),
|
||||
SRT_ECONNFAIL = SRT_EMJ(CONNECTION),
|
||||
SRT_ECONNLOST = SRT_EMN(CONNECTION, CONNLOST),
|
||||
SRT_ENOCONN = SRT_EMN(CONNECTION, NOCONN),
|
||||
|
||||
SRT_ERESOURCE = MJ(SYSTEMRES),
|
||||
SRT_ETHREAD = MN(SYSTEMRES, THREAD),
|
||||
SRT_ENOBUF = MN(SYSTEMRES, MEMORY),
|
||||
SRT_ERESOURCE = SRT_EMJ(SYSTEMRES),
|
||||
SRT_ETHREAD = SRT_EMN(SYSTEMRES, THREAD),
|
||||
SRT_ENOBUF = SRT_EMN(SYSTEMRES, MEMORY),
|
||||
SRT_ESYSOBJ = SRT_EMN(SYSTEMRES, OBJECT),
|
||||
|
||||
SRT_EFILE = MJ(FILESYSTEM),
|
||||
SRT_EINVRDOFF = MN(FILESYSTEM, SEEKGFAIL),
|
||||
SRT_ERDPERM = MN(FILESYSTEM, READFAIL),
|
||||
SRT_EINVWROFF = MN(FILESYSTEM, SEEKPFAIL),
|
||||
SRT_EWRPERM = MN(FILESYSTEM, WRITEFAIL),
|
||||
SRT_EFILE = SRT_EMJ(FILESYSTEM),
|
||||
SRT_EINVRDOFF = SRT_EMN(FILESYSTEM, SEEKGFAIL),
|
||||
SRT_ERDPERM = SRT_EMN(FILESYSTEM, READFAIL),
|
||||
SRT_EINVWROFF = SRT_EMN(FILESYSTEM, SEEKPFAIL),
|
||||
SRT_EWRPERM = SRT_EMN(FILESYSTEM, WRITEFAIL),
|
||||
|
||||
SRT_EINVOP = MJ(NOTSUP),
|
||||
SRT_EBOUNDSOCK = MN(NOTSUP, ISBOUND),
|
||||
SRT_ECONNSOCK = MN(NOTSUP, ISCONNECTED),
|
||||
SRT_EINVPARAM = MN(NOTSUP, INVAL),
|
||||
SRT_EINVSOCK = MN(NOTSUP, SIDINVAL),
|
||||
SRT_EUNBOUNDSOCK = MN(NOTSUP, ISUNBOUND),
|
||||
SRT_ENOLISTEN = MN(NOTSUP, NOLISTEN),
|
||||
SRT_ERDVNOSERV = MN(NOTSUP, ISRENDEZVOUS),
|
||||
SRT_ERDVUNBOUND = MN(NOTSUP, ISRENDUNBOUND),
|
||||
SRT_EINVALMSGAPI = MN(NOTSUP, INVALMSGAPI),
|
||||
SRT_EINVALBUFFERAPI = MN(NOTSUP, INVALBUFFERAPI),
|
||||
SRT_EDUPLISTEN = MN(NOTSUP, BUSY),
|
||||
SRT_ELARGEMSG = MN(NOTSUP, XSIZE),
|
||||
SRT_EINVPOLLID = MN(NOTSUP, EIDINVAL),
|
||||
SRT_EINVOP = SRT_EMJ(NOTSUP),
|
||||
SRT_EBOUNDSOCK = SRT_EMN(NOTSUP, ISBOUND),
|
||||
SRT_ECONNSOCK = SRT_EMN(NOTSUP, ISCONNECTED),
|
||||
SRT_EINVPARAM = SRT_EMN(NOTSUP, INVAL),
|
||||
SRT_EINVSOCK = SRT_EMN(NOTSUP, SIDINVAL),
|
||||
SRT_EUNBOUNDSOCK = SRT_EMN(NOTSUP, ISUNBOUND),
|
||||
SRT_ENOLISTEN = SRT_EMN(NOTSUP, NOLISTEN),
|
||||
SRT_ERDVNOSERV = SRT_EMN(NOTSUP, ISRENDEZVOUS),
|
||||
SRT_ERDVUNBOUND = SRT_EMN(NOTSUP, ISRENDUNBOUND),
|
||||
SRT_EINVALMSGAPI = SRT_EMN(NOTSUP, INVALMSGAPI),
|
||||
SRT_EINVALBUFFERAPI = SRT_EMN(NOTSUP, INVALBUFFERAPI),
|
||||
SRT_EDUPLISTEN = SRT_EMN(NOTSUP, BUSY),
|
||||
SRT_ELARGEMSG = SRT_EMN(NOTSUP, XSIZE),
|
||||
SRT_EINVPOLLID = SRT_EMN(NOTSUP, EIDINVAL),
|
||||
SRT_EPOLLEMPTY = SRT_EMN(NOTSUP, EEMPTY),
|
||||
SRT_EBINDCONFLICT = SRT_EMN(NOTSUP, BUSYPORT),
|
||||
|
||||
SRT_EASYNCFAIL = MJ(AGAIN),
|
||||
SRT_EASYNCSND = MN(AGAIN, WRAVAIL),
|
||||
SRT_EASYNCRCV = MN(AGAIN, RDAVAIL),
|
||||
SRT_ETIMEOUT = MN(AGAIN, XMTIMEOUT),
|
||||
SRT_ECONGEST = MN(AGAIN, CONGESTION),
|
||||
SRT_EASYNCFAIL = SRT_EMJ(AGAIN),
|
||||
SRT_EASYNCSND = SRT_EMN(AGAIN, WRAVAIL),
|
||||
SRT_EASYNCRCV = SRT_EMN(AGAIN, RDAVAIL),
|
||||
SRT_ETIMEOUT = SRT_EMN(AGAIN, XMTIMEOUT),
|
||||
SRT_ECONGEST = SRT_EMN(AGAIN, CONGESTION),
|
||||
|
||||
SRT_EPEERERR = MJ(PEERERROR)
|
||||
SRT_EPEERERR = SRT_EMJ(PEERERROR)
|
||||
} SRT_ERRNO;
|
||||
|
||||
static const SRT_ERRNO SRT_EISSTREAM SRT_ATR_DEPRECATED = (SRT_ERRNO) MN(NOTSUP, INVALMSGAPI);
|
||||
static const SRT_ERRNO SRT_EISDGRAM SRT_ATR_DEPRECATED = (SRT_ERRNO) MN(NOTSUP, INVALBUFFERAPI);
|
||||
|
||||
#undef MJ
|
||||
#undef MN
|
||||
#undef SRT_EMJ
|
||||
#undef SRT_EMN
|
||||
|
||||
enum SRT_REJECT_REASON
|
||||
{
|
||||
|
@ -510,33 +550,87 @@ enum SRT_REJECT_REASON
|
|||
SRT_REJ_UNSECURE, // password required or unexpected
|
||||
SRT_REJ_MESSAGEAPI, // streamapi/messageapi collision
|
||||
SRT_REJ_CONGESTION, // incompatible congestion-controller type
|
||||
SRT_REJ_FILTER, // incompatible packet filter
|
||||
SRT_REJ_FILTER, // incompatible packet filter
|
||||
SRT_REJ_GROUP, // incompatible group
|
||||
SRT_REJ_TIMEOUT, // connection timeout
|
||||
|
||||
SRT_REJ__SIZE,
|
||||
SRT_REJ_E_SIZE,
|
||||
};
|
||||
|
||||
// XXX This value remains for some time, but it's deprecated
|
||||
// Planned deprecation removal: rel1.6.0.
|
||||
#define SRT_REJ__SIZE SRT_REJ_E_SIZE
|
||||
|
||||
// Reject category codes:
|
||||
|
||||
#define SRT_REJC_VALUE(code) (1000 * (code/1000))
|
||||
#define SRT_REJC_INTERNAL 0 // Codes from above SRT_REJECT_REASON enum
|
||||
#define SRT_REJC_PREDEFINED 1000 // Standard server error codes
|
||||
#define SRT_REJC_USERDEFINED 2000 // User defined error codes
|
||||
|
||||
|
||||
// Logging API - specialization for SRT.
|
||||
|
||||
// Define logging functional areas for log selection.
|
||||
// Use values greater than 0. Value 0 is reserved for LOGFA_GENERAL,
|
||||
// which is considered always enabled.
|
||||
// WARNING: This part is generated.
|
||||
|
||||
// Logger Functional Areas
|
||||
// Note that 0 is "general".
|
||||
|
||||
// Made by #define so that it's available also for C API.
|
||||
#define SRT_LOGFA_GENERAL 0
|
||||
#define SRT_LOGFA_BSTATS 1
|
||||
#define SRT_LOGFA_CONTROL 2
|
||||
#define SRT_LOGFA_DATA 3
|
||||
#define SRT_LOGFA_TSBPD 4
|
||||
#define SRT_LOGFA_REXMIT 5
|
||||
#define SRT_LOGFA_HAICRYPT 6
|
||||
#define SRT_LOGFA_CONGEST 7
|
||||
// Values 0* - general, unqualified
|
||||
// Values 1* - control
|
||||
// Values 2* - receiving
|
||||
// Values 3* - sending
|
||||
// Values 4* - management
|
||||
|
||||
// To make a typical int32_t size, although still use std::bitset.
|
||||
// Made by #define so that it's available also for C API.
|
||||
|
||||
// Use ../scripts/generate-logging-defs.tcl to regenerate.
|
||||
|
||||
// SRT_LOGFA BEGIN GENERATED SECTION {
|
||||
|
||||
#define SRT_LOGFA_GENERAL 0 // gglog: General uncategorized log, for serious issues only
|
||||
#define SRT_LOGFA_SOCKMGMT 1 // smlog: Socket create/open/close/configure activities
|
||||
#define SRT_LOGFA_CONN 2 // cnlog: Connection establishment and handshake
|
||||
#define SRT_LOGFA_XTIMER 3 // xtlog: The checkTimer and around activities
|
||||
#define SRT_LOGFA_TSBPD 4 // tslog: The TsBPD thread
|
||||
#define SRT_LOGFA_RSRC 5 // rslog: System resource allocation and management
|
||||
|
||||
#define SRT_LOGFA_CONGEST 7 // cclog: Congestion control module
|
||||
#define SRT_LOGFA_PFILTER 8 // pflog: Packet filter module
|
||||
|
||||
#define SRT_LOGFA_API_CTRL 11 // aclog: API part for socket and library managmenet
|
||||
|
||||
#define SRT_LOGFA_QUE_CTRL 13 // qclog: Queue control activities
|
||||
|
||||
#define SRT_LOGFA_EPOLL_UPD 16 // eilog: EPoll, internal update activities
|
||||
|
||||
#define SRT_LOGFA_API_RECV 21 // arlog: API part for receiving
|
||||
#define SRT_LOGFA_BUF_RECV 22 // brlog: Buffer, receiving side
|
||||
#define SRT_LOGFA_QUE_RECV 23 // qrlog: Queue, receiving side
|
||||
#define SRT_LOGFA_CHN_RECV 24 // krlog: CChannel, receiving side
|
||||
#define SRT_LOGFA_GRP_RECV 25 // grlog: Group, receiving side
|
||||
|
||||
#define SRT_LOGFA_API_SEND 31 // aslog: API part for sending
|
||||
#define SRT_LOGFA_BUF_SEND 32 // bslog: Buffer, sending side
|
||||
#define SRT_LOGFA_QUE_SEND 33 // qslog: Queue, sending side
|
||||
#define SRT_LOGFA_CHN_SEND 34 // kslog: CChannel, sending side
|
||||
#define SRT_LOGFA_GRP_SEND 35 // gslog: Group, sending side
|
||||
|
||||
#define SRT_LOGFA_INTERNAL 41 // inlog: Internal activities not connected directly to a socket
|
||||
|
||||
#define SRT_LOGFA_QUE_MGMT 43 // qmlog: Queue, management part
|
||||
#define SRT_LOGFA_CHN_MGMT 44 // kmlog: CChannel, management part
|
||||
#define SRT_LOGFA_GRP_MGMT 45 // gmlog: Group, management part
|
||||
#define SRT_LOGFA_EPOLL_API 46 // ealog: EPoll, API part
|
||||
|
||||
#define SRT_LOGFA_HAICRYPT 6 // hclog: Haicrypt module area
|
||||
#define SRT_LOGFA_APPLOG 10 // aplog: Applications
|
||||
|
||||
// } SRT_LOGFA END GENERATED SECTION
|
||||
|
||||
// To make a typical int64_t size, although still use std::bitset.
|
||||
// C API will carry it over.
|
||||
#define SRT_LOGFA_LASTNONE 31
|
||||
#define SRT_LOGFA_LASTNONE 63
|
||||
|
||||
enum SRT_KM_STATE
|
||||
{
|
||||
|
@ -550,16 +644,73 @@ enum SRT_KM_STATE
|
|||
enum SRT_EPOLL_OPT
|
||||
{
|
||||
SRT_EPOLL_OPT_NONE = 0x0, // fallback
|
||||
// this values are defined same as linux epoll.h
|
||||
|
||||
// Values intended to be the same as in `<sys/epoll.h>`.
|
||||
// so that if system values are used by mistake, they should have the same effect
|
||||
// This applies to: IN, OUT, ERR and ET.
|
||||
|
||||
/// Ready for 'recv' operation:
|
||||
///
|
||||
/// - For stream mode it means that at least 1 byte is available.
|
||||
/// In this mode the buffer may extract only a part of the packet,
|
||||
/// leaving next data possible for extraction later.
|
||||
///
|
||||
/// - For message mode it means that there is at least one packet
|
||||
/// available (this may change in future, as it is desired that
|
||||
/// one full message should only wake up, not single packet of a
|
||||
/// not yet extractable message).
|
||||
///
|
||||
/// - For live mode it means that there's at least one packet
|
||||
/// ready to play.
|
||||
///
|
||||
/// - For listener sockets, this means that there is a new connection
|
||||
/// waiting for pickup through the `srt_accept()` call, that is,
|
||||
/// the next call to `srt_accept()` will succeed without blocking
|
||||
/// (see an alias SRT_EPOLL_ACCEPT below).
|
||||
SRT_EPOLL_IN = 0x1,
|
||||
|
||||
/// Ready for 'send' operation.
|
||||
///
|
||||
/// - For stream mode it means that there's a free space in the
|
||||
/// sender buffer for at least 1 byte of data. The next send
|
||||
/// operation will only allow to send as much data as it is free
|
||||
/// space in the buffer.
|
||||
///
|
||||
/// - For message mode it means that there's a free space for at
|
||||
/// least one UDP packet. The edge-triggered mode can be used to
|
||||
/// pick up updates as the free space in the sender buffer grows.
|
||||
///
|
||||
/// - For live mode it means that there's a free space for at least
|
||||
/// one UDP packet. On the other hand, no readiness for OUT usually
|
||||
/// means an extraordinary congestion on the link, meaning also that
|
||||
/// you should immediately slow down the sending rate or you may get
|
||||
/// a connection break soon.
|
||||
///
|
||||
/// - For non-blocking sockets used with `srt_connect*` operation,
|
||||
/// this flag simply means that the connection was established.
|
||||
SRT_EPOLL_OUT = 0x4,
|
||||
|
||||
/// The socket has encountered an error in the last operation
|
||||
/// and the next operation on that socket will end up with error.
|
||||
/// You can retry the operation, but getting the error from it
|
||||
/// is certain, so you may as well close the socket.
|
||||
SRT_EPOLL_ERR = 0x8,
|
||||
|
||||
// To avoid confusion in the internal code, the following
|
||||
// duplicates are introduced to improve clarity.
|
||||
SRT_EPOLL_CONNECT = SRT_EPOLL_OUT,
|
||||
SRT_EPOLL_ACCEPT = SRT_EPOLL_IN,
|
||||
|
||||
SRT_EPOLL_UPDATE = 0x10,
|
||||
SRT_EPOLL_ET = 1u << 31
|
||||
};
|
||||
// These are actually flags - use a bit container:
|
||||
typedef int32_t SRT_EPOLL_T;
|
||||
|
||||
// Define which epoll flags determine events. All others are special flags.
|
||||
#define SRT_EPOLL_EVENTTYPES (SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_UPDATE | SRT_EPOLL_ERR)
|
||||
#define SRT_EPOLL_ETONLY (SRT_EPOLL_UPDATE)
|
||||
|
||||
enum SRT_EPOLL_FLAGS
|
||||
{
|
||||
/// This allows the EID container to be empty when calling the waiting
|
||||
|
@ -582,17 +733,8 @@ inline SRT_EPOLL_OPT operator|(SRT_EPOLL_OPT a1, SRT_EPOLL_OPT a2)
|
|||
return SRT_EPOLL_OPT( (int)a1 | (int)a2 );
|
||||
}
|
||||
|
||||
inline bool operator&(int flags, SRT_EPOLL_OPT eflg)
|
||||
{
|
||||
// Using an enum prevents treating int automatically as enum,
|
||||
// requires explicit enum to be passed here, and minimizes the
|
||||
// risk that the right side value will contain multiple flags.
|
||||
return (flags & int(eflg)) != 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
typedef struct CBytePerfMon SRT_TRACEBSTATS;
|
||||
|
||||
static const SRTSOCKET SRT_INVALID_SOCK = -1;
|
||||
|
@ -605,18 +747,32 @@ SRT_API int srt_cleanup(void);
|
|||
//
|
||||
// Socket operations
|
||||
//
|
||||
SRT_API SRTSOCKET srt_socket (int af, int type, int protocol);
|
||||
SRT_API SRTSOCKET srt_create_socket();
|
||||
// DEPRECATED: srt_socket with 3 arguments. All these arguments are ignored
|
||||
// and socket creation doesn't need any arguments. Use srt_create_socket().
|
||||
// Planned deprecation removal: rel1.6.0
|
||||
SRT_ATR_DEPRECATED_PX SRT_API SRTSOCKET srt_socket(int, int, int) SRT_ATR_DEPRECATED;
|
||||
SRT_API SRTSOCKET srt_create_socket(void);
|
||||
|
||||
SRT_API int srt_bind (SRTSOCKET u, const struct sockaddr* name, int namelen);
|
||||
SRT_API int srt_bind_peerof (SRTSOCKET u, UDPSOCKET udpsock);
|
||||
SRT_API int srt_bind_acquire (SRTSOCKET u, UDPSOCKET sys_udp_sock);
|
||||
// Old name of srt_bind_acquire(), please don't use
|
||||
// Planned deprecation removal: rel1.6.0
|
||||
SRT_ATR_DEPRECATED_PX static inline int srt_bind_peerof(SRTSOCKET u, UDPSOCKET sys_udp_sock) SRT_ATR_DEPRECATED;
|
||||
static inline int srt_bind_peerof (SRTSOCKET u, UDPSOCKET sys_udp_sock) { return srt_bind_acquire(u, sys_udp_sock); }
|
||||
SRT_API int srt_listen (SRTSOCKET u, int backlog);
|
||||
SRT_API SRTSOCKET srt_accept (SRTSOCKET u, struct sockaddr* addr, int* addrlen);
|
||||
SRT_API SRTSOCKET srt_accept_bond (const SRTSOCKET listeners[], int lsize, int64_t msTimeOut);
|
||||
typedef int srt_listen_callback_fn (void* opaq, SRTSOCKET ns, int hsversion, const struct sockaddr* peeraddr, const char* streamid);
|
||||
SRT_API int srt_listen_callback(SRTSOCKET lsn, srt_listen_callback_fn* hook_fn, void* hook_opaque);
|
||||
typedef void srt_connect_callback_fn (void* opaq, SRTSOCKET ns, int errorcode, const struct sockaddr* peeraddr, int token);
|
||||
SRT_API int srt_connect_callback(SRTSOCKET clr, srt_connect_callback_fn* hook_fn, void* hook_opaque);
|
||||
SRT_API int srt_connect (SRTSOCKET u, const struct sockaddr* name, int namelen);
|
||||
SRT_API int srt_connect_debug(SRTSOCKET u, const struct sockaddr* name, int namelen, int forced_isn);
|
||||
SRT_API int srt_connect_bind (SRTSOCKET u, const struct sockaddr* source,
|
||||
const struct sockaddr* target, int len);
|
||||
SRT_API int srt_rendezvous (SRTSOCKET u, const struct sockaddr* local_name, int local_namelen,
|
||||
const struct sockaddr* remote_name, int remote_namelen);
|
||||
|
||||
SRT_API int srt_close (SRTSOCKET u);
|
||||
SRT_API int srt_getpeername (SRTSOCKET u, struct sockaddr* name, int* namelen);
|
||||
SRT_API int srt_getsockname (SRTSOCKET u, struct sockaddr* name, int* namelen);
|
||||
|
@ -625,19 +781,34 @@ SRT_API int srt_setsockopt (SRTSOCKET u, int level /*ignored*/, SRT_SOCK
|
|||
SRT_API int srt_getsockflag (SRTSOCKET u, SRT_SOCKOPT opt, void* optval, int* optlen);
|
||||
SRT_API int srt_setsockflag (SRTSOCKET u, SRT_SOCKOPT opt, const void* optval, int optlen);
|
||||
|
||||
typedef struct SRT_SocketGroupData_ SRT_SOCKGROUPDATA;
|
||||
|
||||
// XXX Note that the srctime functionality doesn't work yet and needs fixing.
|
||||
typedef struct SRT_MsgCtrl_
|
||||
{
|
||||
int flags; // Left for future
|
||||
int msgttl; // TTL for a message, default -1 (no TTL limitation)
|
||||
int msgttl; // TTL for a message (millisec), default -1 (no TTL limitation)
|
||||
int inorder; // Whether a message is allowed to supersede partially lost one. Unused in stream and live mode.
|
||||
int boundary; // 0:mid pkt, 1(01b):end of frame, 2(11b):complete frame, 3(10b): start of frame
|
||||
uint64_t srctime; // source timestamp (usec), 0: use internal time
|
||||
int64_t srctime; // source time since epoch (usec), 0: use internal time (sender)
|
||||
int32_t pktseq; // sequence number of the first packet in received message (unused for sending)
|
||||
int32_t msgno; // message number (output value for both sending and receiving)
|
||||
SRT_SOCKGROUPDATA* grpdata;
|
||||
size_t grpdata_size;
|
||||
} SRT_MSGCTRL;
|
||||
|
||||
// Trap representation for sequence and message numbers
|
||||
// This value means that this is "unset", and it's never
|
||||
// a result of an operation made on this number.
|
||||
static const int32_t SRT_SEQNO_NONE = -1; // -1: no seq (0 is a valid seqno!)
|
||||
static const int32_t SRT_MSGNO_NONE = -1; // -1: unset
|
||||
static const int32_t SRT_MSGNO_CONTROL = 0; // 0: control (used by packet filter)
|
||||
|
||||
static const int SRT_MSGTTL_INF = -1; // unlimited TTL specification for message TTL
|
||||
|
||||
// XXX Might be useful also other special uses of -1:
|
||||
// - -1 as infinity for srt_epoll_wait
|
||||
// - -1 as a trap index value used in list.cpp
|
||||
|
||||
// You are free to use either of these two methods to set SRT_MSGCTRL object
|
||||
// to default values: either call srt_msgctrl_init(&obj) or obj = srt_msgctrl_default.
|
||||
SRT_API void srt_msgctrl_init(SRT_MSGCTRL* mctrl);
|
||||
|
@ -657,11 +828,6 @@ SRT_API extern const SRT_MSGCTRL srt_msgctrl_default;
|
|||
// parameters will be filled, as needed. NULL is acceptable, in which case
|
||||
// the defaults are used.
|
||||
|
||||
// NOTE: srt_send and srt_recv have the last "..." left to allow ignore a
|
||||
// deprecated and unused "flags" parameter. After confirming that all
|
||||
// compat applications that pass useless 0 there are fixed, this will be
|
||||
// removed.
|
||||
|
||||
//
|
||||
// Sending functions
|
||||
//
|
||||
|
@ -692,16 +858,17 @@ SRT_API int srt_getlasterror(int* errno_loc);
|
|||
SRT_API const char* srt_strerror(int code, int errnoval);
|
||||
SRT_API void srt_clearlasterror(void);
|
||||
|
||||
// performance track
|
||||
// perfmon with Byte counters for better bitrate estimation.
|
||||
// Performance tracking
|
||||
// Performance monitor with Byte counters for better bitrate estimation.
|
||||
SRT_API int srt_bstats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear);
|
||||
// permon with Byte counters and instantaneous stats instead of moving averages for Snd/Rcvbuffer sizes.
|
||||
// Performance monitor with Byte counters and instantaneous stats instead of moving averages for Snd/Rcvbuffer sizes.
|
||||
SRT_API int srt_bistats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear, int instantaneous);
|
||||
|
||||
// Socket Status (for problem tracking)
|
||||
SRT_API SRT_SOCKSTATUS srt_getsockstate(SRTSOCKET u);
|
||||
|
||||
SRT_API int srt_epoll_create(void);
|
||||
SRT_API int srt_epoll_clear_usocks(int eid);
|
||||
SRT_API int srt_epoll_add_usock(int eid, SRTSOCKET u, const int* events);
|
||||
SRT_API int srt_epoll_add_ssock(int eid, SYSSOCKET s, const int* events);
|
||||
SRT_API int srt_epoll_remove_usock(int eid, SRTSOCKET u);
|
||||
|
@ -711,10 +878,14 @@ SRT_API int srt_epoll_update_ssock(int eid, SYSSOCKET s, const int* events);
|
|||
|
||||
SRT_API int srt_epoll_wait(int eid, SRTSOCKET* readfds, int* rnum, SRTSOCKET* writefds, int* wnum, int64_t msTimeOut,
|
||||
SYSSOCKET* lrfds, int* lrnum, SYSSOCKET* lwfds, int* lwnum);
|
||||
typedef struct SRT_EPOLL_EVENT_
|
||||
typedef struct SRT_EPOLL_EVENT_STR
|
||||
{
|
||||
SRTSOCKET fd;
|
||||
int events; // SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR
|
||||
#ifdef __cplusplus
|
||||
SRT_EPOLL_EVENT_STR(SRTSOCKET s, int ev): fd(s), events(ev) {}
|
||||
SRT_EPOLL_EVENT_STR(): fd(-1), events(0) {} // NOTE: allows singular values, no init.
|
||||
#endif
|
||||
} SRT_EPOLL_EVENT;
|
||||
SRT_API int srt_epoll_uwait(int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut);
|
||||
|
||||
|
@ -736,9 +907,88 @@ SRT_API void srt_setlogflags(int flags);
|
|||
|
||||
SRT_API int srt_getsndbuffer(SRTSOCKET sock, size_t* blocks, size_t* bytes);
|
||||
|
||||
SRT_API enum SRT_REJECT_REASON srt_getrejectreason(SRTSOCKET sock);
|
||||
SRT_API extern const char* const srt_rejectreason_msg [];
|
||||
const char* srt_rejectreason_str(enum SRT_REJECT_REASON id);
|
||||
SRT_API int srt_getrejectreason(SRTSOCKET sock);
|
||||
SRT_API int srt_setrejectreason(SRTSOCKET sock, int value);
|
||||
// The srt_rejectreason_msg[] array is deprecated (as unsafe).
|
||||
// Planned removal: v1.6.0.
|
||||
SRT_API SRT_ATR_DEPRECATED extern const char* const srt_rejectreason_msg [];
|
||||
SRT_API const char* srt_rejectreason_str(int id);
|
||||
|
||||
SRT_API uint32_t srt_getversion(void);
|
||||
|
||||
SRT_API int64_t srt_time_now(void);
|
||||
|
||||
SRT_API int64_t srt_connection_time(SRTSOCKET sock);
|
||||
|
||||
// Possible internal clock types
|
||||
#define SRT_SYNC_CLOCK_STDCXX_STEADY 0 // C++11 std::chrono::steady_clock
|
||||
#define SRT_SYNC_CLOCK_GETTIME_MONOTONIC 1 // clock_gettime with CLOCK_MONOTONIC
|
||||
#define SRT_SYNC_CLOCK_WINQPC 2
|
||||
#define SRT_SYNC_CLOCK_MACH_ABSTIME 3
|
||||
#define SRT_SYNC_CLOCK_POSIX_GETTIMEOFDAY 4
|
||||
#define SRT_SYNC_CLOCK_AMD64_RDTSC 5
|
||||
#define SRT_SYNC_CLOCK_IA32_RDTSC 6
|
||||
#define SRT_SYNC_CLOCK_IA64_ITC 7
|
||||
|
||||
SRT_API int srt_clock_type(void);
|
||||
|
||||
// SRT Socket Groups API (ENABLE_BONDING)
|
||||
|
||||
typedef enum SRT_GROUP_TYPE
|
||||
{
|
||||
SRT_GTYPE_UNDEFINED,
|
||||
SRT_GTYPE_BROADCAST,
|
||||
SRT_GTYPE_BACKUP,
|
||||
// ...
|
||||
SRT_GTYPE_E_END
|
||||
} SRT_GROUP_TYPE;
|
||||
|
||||
// Free-form flags for groups
|
||||
// Flags may be type-specific!
|
||||
static const uint32_t SRT_GFLAG_SYNCONMSG = 1;
|
||||
|
||||
typedef enum SRT_MemberStatus
|
||||
{
|
||||
SRT_GST_PENDING, // The socket is created correctly, but not yet ready for getting data.
|
||||
SRT_GST_IDLE, // The socket is ready to be activated
|
||||
SRT_GST_RUNNING, // The socket was already activated and is in use
|
||||
SRT_GST_BROKEN // The last operation broke the socket, it should be closed.
|
||||
} SRT_MEMBERSTATUS;
|
||||
|
||||
struct SRT_SocketGroupData_
|
||||
{
|
||||
SRTSOCKET id;
|
||||
struct sockaddr_storage peeraddr; // Don't want to expose sockaddr_any to public API
|
||||
SRT_SOCKSTATUS sockstate;
|
||||
uint16_t weight;
|
||||
SRT_MEMBERSTATUS memberstate;
|
||||
int result;
|
||||
int token;
|
||||
};
|
||||
|
||||
typedef struct SRT_SocketOptionObject SRT_SOCKOPT_CONFIG;
|
||||
|
||||
typedef struct SRT_GroupMemberConfig_
|
||||
{
|
||||
SRTSOCKET id;
|
||||
struct sockaddr_storage srcaddr;
|
||||
struct sockaddr_storage peeraddr; // Don't want to expose sockaddr_any to public API
|
||||
uint16_t weight;
|
||||
SRT_SOCKOPT_CONFIG* config;
|
||||
int errorcode;
|
||||
int token;
|
||||
} SRT_SOCKGROUPCONFIG;
|
||||
|
||||
SRT_API SRTSOCKET srt_create_group(SRT_GROUP_TYPE);
|
||||
SRT_API SRTSOCKET srt_groupof(SRTSOCKET socket);
|
||||
SRT_API int srt_group_data(SRTSOCKET socketgroup, SRT_SOCKGROUPDATA* output, size_t* inoutlen);
|
||||
|
||||
SRT_API SRT_SOCKOPT_CONFIG* srt_create_config(void);
|
||||
SRT_API void srt_delete_config(SRT_SOCKOPT_CONFIG* config /*nullable*/);
|
||||
SRT_API int srt_config_add(SRT_SOCKOPT_CONFIG* config, SRT_SOCKOPT option, const void* contents, int len);
|
||||
|
||||
SRT_API SRT_SOCKGROUPCONFIG srt_prepare_endpoint(const struct sockaddr* src /*nullable*/, const struct sockaddr* adr, int namelen);
|
||||
SRT_API int srt_connect_group(SRTSOCKET group, SRT_SOCKGROUPCONFIG name[], int arraysize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
71
trunk/3rdparty/srt-1-fit/srtcore/srt4udt.h
vendored
71
trunk/3rdparty/srt-1-fit/srtcore/srt4udt.h
vendored
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
written by
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SRT4UDT_H
|
||||
#define SRT4UDT_H
|
||||
|
||||
#ifndef INC__SRTC_H
|
||||
#error "This is protected header, used by udt.h. This shouldn't be included directly"
|
||||
#endif
|
||||
|
||||
//undef SRT_ENABLE_ECN 1 /* Early Congestion Notification (for source bitrate control) */
|
||||
|
||||
//undef SRT_DEBUG_TSBPD_OUTJITTER 1 /* Packet Delivery histogram */
|
||||
//undef SRT_DEBUG_TSBPD_DRIFT 1 /* Debug Encoder-Decoder Drift) */
|
||||
//undef SRT_DEBUG_TSBPD_WRAP 1 /* Debug packet timestamp wraparound */
|
||||
//undef SRT_DEBUG_TLPKTDROP_DROPSEQ 1
|
||||
//undef SRT_DEBUG_SNDQ_HIGHRATE 1
|
||||
|
||||
|
||||
/*
|
||||
* SRT_ENABLE_CONNTIMEO
|
||||
* Option UDT_CONNTIMEO added to the API to set/get the connection timeout.
|
||||
* The UDT hard coded default of 3000 msec is too small for some large RTT (satellite) use cases.
|
||||
* The SRT handshake (2 exchanges) needs 2 times the RTT to complete with no packet loss.
|
||||
*/
|
||||
#define SRT_ENABLE_CONNTIMEO 1
|
||||
|
||||
/*
|
||||
* SRT_ENABLE_NOCWND
|
||||
* Set the congestion window at its max (then disabling it) to prevent stopping transmission
|
||||
* when too many packets are not acknowledged.
|
||||
* The congestion windows is the maximum distance in pkts since the last acknowledged packets.
|
||||
*/
|
||||
#define SRT_ENABLE_NOCWND 1
|
||||
|
||||
/*
|
||||
* SRT_ENABLE_NAKREPORT
|
||||
* Send periodic NAK report for more efficient retransmission instead of relying on ACK timeout
|
||||
* to retransmit all non-ACKed packets, very inefficient with real-time and no congestion window.
|
||||
*/
|
||||
#define SRT_ENABLE_NAKREPORT 1
|
||||
|
||||
#define SRT_ENABLE_RCVBUFSZ_MAVG 1 /* Recv buffer size moving average */
|
||||
#define SRT_ENABLE_SNDBUFSZ_MAVG 1 /* Send buffer size moving average */
|
||||
#define SRT_MAVG_SAMPLING_RATE 40 /* Max sampling rate */
|
||||
|
||||
#define SRT_ENABLE_LOSTBYTESCOUNT 1
|
||||
|
||||
|
||||
/*
|
||||
* SRT_ENABLE_IPOPTS
|
||||
* Enable IP TTL and ToS setting
|
||||
*/
|
||||
#define SRT_ENABLE_IPOPTS 1
|
||||
|
||||
|
||||
#define SRT_ENABLE_CLOSE_SYNCH 1
|
||||
|
||||
#endif /* SRT4UDT_H */
|
191
trunk/3rdparty/srt-1-fit/srtcore/srt_attr_defs.h
vendored
Normal file
191
trunk/3rdparty/srt-1-fit/srtcore/srt_attr_defs.h
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2019 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v.2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
/*****************************************************************************
|
||||
The file contains various planform and compiler dependent attribute definitions
|
||||
used by SRT library internally.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC_SRT_ATTR_DEFS_H
|
||||
#define INC_SRT_ATTR_DEFS_H
|
||||
|
||||
// ATTRIBUTES:
|
||||
//
|
||||
// SRT_ATR_UNUSED: declare an entity ALLOWED to be unused (prevents warnings)
|
||||
// ATR_DEPRECATED: declare an entity deprecated (compiler should warn when used)
|
||||
// ATR_NOEXCEPT: The true `noexcept` from C++11, or nothing if compiling in pre-C++11 mode
|
||||
// ATR_NOTHROW: In C++11: `noexcept`. In pre-C++11: `throw()`. Required for GNU libstdc++.
|
||||
// ATR_CONSTEXPR: In C++11: `constexpr`. Otherwise empty.
|
||||
// ATR_OVERRIDE: In C++11: `override`. Otherwise empty.
|
||||
// ATR_FINAL: In C++11: `final`. Otherwise empty.
|
||||
|
||||
#ifdef __GNUG__
|
||||
#define ATR_DEPRECATED __attribute__((deprecated))
|
||||
#else
|
||||
#define ATR_DEPRECATED
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) && __cplusplus > 199711L
|
||||
#define HAVE_CXX11 1
|
||||
// For gcc 4.7, claim C++11 is supported, as long as experimental C++0x is on,
|
||||
// however it's only the "most required C++11 support".
|
||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 7 // 4.7 only!
|
||||
#define ATR_NOEXCEPT
|
||||
#define ATR_NOTHROW throw()
|
||||
#define ATR_CONSTEXPR
|
||||
#define ATR_OVERRIDE
|
||||
#define ATR_FINAL
|
||||
#else
|
||||
#define HAVE_FULL_CXX11 1
|
||||
#define ATR_NOEXCEPT noexcept
|
||||
#define ATR_NOTHROW noexcept
|
||||
#define ATR_CONSTEXPR constexpr
|
||||
#define ATR_OVERRIDE override
|
||||
#define ATR_FINAL final
|
||||
#endif
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1800
|
||||
// Microsoft Visual Studio supports C++11, but not fully,
|
||||
// and still did not change the value of __cplusplus. Treat
|
||||
// this special way.
|
||||
// _MSC_VER == 1800 means Microsoft Visual Studio 2013.
|
||||
#define HAVE_CXX11 1
|
||||
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
|
||||
#define HAVE_FULL_CXX11 1
|
||||
#define ATR_NOEXCEPT noexcept
|
||||
#define ATR_NOTHROW noexcept
|
||||
#define ATR_CONSTEXPR constexpr
|
||||
#define ATR_OVERRIDE override
|
||||
#define ATR_FINAL final
|
||||
#else
|
||||
#define ATR_NOEXCEPT
|
||||
#define ATR_NOTHROW throw()
|
||||
#define ATR_CONSTEXPR
|
||||
#define ATR_OVERRIDE
|
||||
#define ATR_FINAL
|
||||
#endif
|
||||
#else
|
||||
#define HAVE_CXX11 0
|
||||
#define ATR_NOEXCEPT
|
||||
#define ATR_NOTHROW throw()
|
||||
#define ATR_CONSTEXPR
|
||||
#define ATR_OVERRIDE
|
||||
#define ATR_FINAL
|
||||
#endif // __cplusplus
|
||||
|
||||
#if !HAVE_CXX11 && defined(REQUIRE_CXX11) && REQUIRE_CXX11 == 1
|
||||
#error "The currently compiled application required C++11, but your compiler doesn't support it."
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Attributes for thread safety analysis
|
||||
// - Clang TSA (https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#mutexheader).
|
||||
// - MSVC SAL (partially).
|
||||
// - Other compilers: none.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#if _MSC_VER >= 1920
|
||||
// In case of MSVC these attributes have to preceed the attributed objects (variable, function).
|
||||
// E.g. SRT_ATTR_GUARDED_BY(mtx) int object;
|
||||
// It is tricky to annotate e.g. the following function, as clang complaints it does not know 'm'.
|
||||
// SRT_ATTR_EXCLUDES(m) SRT_ATTR_ACQUIRE(m)
|
||||
// inline void enterCS(Mutex& m) { m.lock(); }
|
||||
#define SRT_ATTR_CAPABILITY(expr)
|
||||
#define SRT_ATTR_SCOPED_CAPABILITY
|
||||
#define SRT_ATTR_GUARDED_BY(expr) _Guarded_by_(expr)
|
||||
#define SRT_ATTR_PT_GUARDED_BY(expr)
|
||||
#define SRT_ATTR_ACQUIRED_BEFORE(...)
|
||||
#define SRT_ATTR_ACQUIRED_AFTER(...)
|
||||
#define SRT_ATTR_REQUIRES(expr) _Requires_lock_held_(expr)
|
||||
#define SRT_ATTR_REQUIRES2(expr1, expr2) _Requires_lock_held_(expr1) _Requires_lock_held_(expr2)
|
||||
#define SRT_ATTR_REQUIRES_SHARED(...)
|
||||
#define SRT_ATTR_ACQUIRE(expr) _Acquires_nonreentrant_lock_(expr)
|
||||
#define SRT_ATTR_ACQUIRE_SHARED(...)
|
||||
#define SRT_ATTR_RELEASE(expr) _Releases_lock_(expr)
|
||||
#define SRT_ATTR_RELEASE_SHARED(...)
|
||||
#define SRT_ATTR_RELEASE_GENERIC(...)
|
||||
#define SRT_ATTR_TRY_ACQUIRE(...) _Acquires_nonreentrant_lock_(expr)
|
||||
#define SRT_ATTR_TRY_ACQUIRE_SHARED(...)
|
||||
#define SRT_ATTR_EXCLUDES(...)
|
||||
#define SRT_ATTR_ASSERT_CAPABILITY(expr)
|
||||
#define SRT_ATTR_ASSERT_SHARED_CAPABILITY(x)
|
||||
#define SRT_ATTR_RETURN_CAPABILITY(x)
|
||||
#define SRT_ATTR_NO_THREAD_SAFETY_ANALYSIS
|
||||
#else
|
||||
|
||||
#if defined(__clang__) && defined(__clang_major__) && (__clang_major__ > 5)
|
||||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
|
||||
#else
|
||||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
|
||||
#endif
|
||||
|
||||
#define SRT_ATTR_CAPABILITY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
|
||||
|
||||
#define SRT_ATTR_SCOPED_CAPABILITY \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
|
||||
|
||||
#define SRT_ATTR_GUARDED_BY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
|
||||
|
||||
#define SRT_ATTR_PT_GUARDED_BY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
|
||||
|
||||
#define SRT_ATTR_ACQUIRED_BEFORE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
|
||||
|
||||
#define SRT_ATTR_ACQUIRED_AFTER(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
|
||||
|
||||
#define SRT_ATTR_REQUIRES(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
|
||||
|
||||
#define SRT_ATTR_REQUIRES2(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
|
||||
|
||||
#define SRT_ATTR_REQUIRES_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define SRT_ATTR_ACQUIRE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define SRT_ATTR_ACQUIRE_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define SRT_ATTR_RELEASE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
|
||||
|
||||
#define SRT_ATTR_RELEASE_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define SRT_ATTR_RELEASE_GENERIC(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__))
|
||||
|
||||
#define SRT_ATTR_TRY_ACQUIRE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define SRT_ATTR_TRY_ACQUIRE_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define SRT_ATTR_EXCLUDES(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
|
||||
|
||||
#define SRT_ATTR_ASSERT_CAPABILITY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
|
||||
|
||||
#define SRT_ATTR_ASSERT_SHARED_CAPABILITY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
|
||||
|
||||
#define SRT_ATTR_RETURN_CAPABILITY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
|
||||
|
||||
#define SRT_ATTR_NO_THREAD_SAFETY_ANALYSIS \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
|
||||
|
||||
#endif // not _MSC_VER
|
||||
|
||||
#endif // INC_SRT_ATTR_DEFS_H
|
248
trunk/3rdparty/srt-1-fit/srtcore/srt_c_api.cpp
vendored
248
trunk/3rdparty/srt-1-fit/srtcore/srt_c_api.cpp
vendored
|
@ -13,17 +13,18 @@ written by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <fstream>
|
||||
#if __APPLE__
|
||||
#include "TargetConditionals.h"
|
||||
#endif
|
||||
#include "srt.h"
|
||||
#include "common.h"
|
||||
#include "packet.h"
|
||||
#include "core.h"
|
||||
#include "utilities.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace srt;
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
@ -31,51 +32,111 @@ extern "C" {
|
|||
int srt_startup() { return CUDT::startup(); }
|
||||
int srt_cleanup() { return CUDT::cleanup(); }
|
||||
|
||||
SRTSOCKET srt_socket(int af, int type, int protocol) { return CUDT::socket(af, type, protocol); }
|
||||
SRTSOCKET srt_create_socket()
|
||||
// Socket creation.
|
||||
SRTSOCKET srt_socket(int , int , int ) { return CUDT::socket(); }
|
||||
SRTSOCKET srt_create_socket() { return CUDT::socket(); }
|
||||
|
||||
#if ENABLE_BONDING
|
||||
// Group management.
|
||||
SRTSOCKET srt_create_group(SRT_GROUP_TYPE gt) { return CUDT::createGroup(gt); }
|
||||
SRTSOCKET srt_groupof(SRTSOCKET socket) { return CUDT::getGroupOfSocket(socket); }
|
||||
int srt_group_data(SRTSOCKET socketgroup, SRT_SOCKGROUPDATA* output, size_t* inoutlen)
|
||||
{
|
||||
// XXX This must include rework around m_iIPVersion. This must be
|
||||
// abandoned completely and all "IP VERSION" thing should rely on
|
||||
// the exact specification in the 'sockaddr' objects passed to other functions,
|
||||
// that is, the "current IP Version" remains undefined until any of
|
||||
// srt_bind() or srt_connect() function is done. And when any of these
|
||||
// functions are being called, the IP version is contained in the
|
||||
// sockaddr object passed there.
|
||||
|
||||
// Until this rework is done, srt_create_socket() will set the
|
||||
// default AF_INET family.
|
||||
|
||||
// Note that all arguments except the first one here are ignored.
|
||||
return CUDT::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
return CUDT::getGroupData(socketgroup, output, inoutlen);
|
||||
}
|
||||
|
||||
SRT_SOCKOPT_CONFIG* srt_create_config()
|
||||
{
|
||||
return new SRT_SocketOptionObject;
|
||||
}
|
||||
|
||||
int srt_config_add(SRT_SOCKOPT_CONFIG* config, SRT_SOCKOPT option, const void* contents, int len)
|
||||
{
|
||||
if (!config)
|
||||
return -1;
|
||||
|
||||
if (!config->add(option, contents, len))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srt_connect_group(SRTSOCKET group,
|
||||
SRT_SOCKGROUPCONFIG name[], int arraysize)
|
||||
{
|
||||
return CUDT::connectLinks(group, name, arraysize);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
SRTSOCKET srt_create_group(SRT_GROUP_TYPE) { return SRT_INVALID_SOCK; }
|
||||
SRTSOCKET srt_groupof(SRTSOCKET) { return SRT_INVALID_SOCK; }
|
||||
int srt_group_data(SRTSOCKET, SRT_SOCKGROUPDATA*, size_t*) { return srt::CUDT::APIError(MJ_NOTSUP, MN_INVAL, 0); }
|
||||
SRT_SOCKOPT_CONFIG* srt_create_config() { return NULL; }
|
||||
int srt_config_add(SRT_SOCKOPT_CONFIG*, SRT_SOCKOPT, const void*, int) { return srt::CUDT::APIError(MJ_NOTSUP, MN_INVAL, 0); }
|
||||
|
||||
int srt_connect_group(SRTSOCKET, SRT_SOCKGROUPCONFIG[], int) { return srt::CUDT::APIError(MJ_NOTSUP, MN_INVAL, 0); }
|
||||
|
||||
#endif
|
||||
|
||||
SRT_SOCKGROUPCONFIG srt_prepare_endpoint(const struct sockaddr* src, const struct sockaddr* dst, int namelen)
|
||||
{
|
||||
SRT_SOCKGROUPCONFIG data;
|
||||
#if ENABLE_BONDING
|
||||
data.errorcode = SRT_SUCCESS;
|
||||
#else
|
||||
data.errorcode = SRT_EINVOP;
|
||||
#endif
|
||||
data.id = -1;
|
||||
data.token = -1;
|
||||
data.weight = 0;
|
||||
data.config = NULL;
|
||||
if (src)
|
||||
memcpy(&data.srcaddr, src, namelen);
|
||||
else
|
||||
{
|
||||
memset(&data.srcaddr, 0, sizeof data.srcaddr);
|
||||
// Still set the family according to the target address
|
||||
data.srcaddr.ss_family = dst->sa_family;
|
||||
}
|
||||
memcpy(&data.peeraddr, dst, namelen);
|
||||
return data;
|
||||
}
|
||||
|
||||
void srt_delete_config(SRT_SOCKOPT_CONFIG* in)
|
||||
{
|
||||
delete in;
|
||||
}
|
||||
|
||||
// Binding and connection management
|
||||
int srt_bind(SRTSOCKET u, const struct sockaddr * name, int namelen) { return CUDT::bind(u, name, namelen); }
|
||||
int srt_bind_peerof(SRTSOCKET u, UDPSOCKET udpsock) { return CUDT::bind(u, udpsock); }
|
||||
int srt_bind_acquire(SRTSOCKET u, UDPSOCKET udpsock) { return CUDT::bind(u, udpsock); }
|
||||
int srt_listen(SRTSOCKET u, int backlog) { return CUDT::listen(u, backlog); }
|
||||
SRTSOCKET srt_accept(SRTSOCKET u, struct sockaddr * addr, int * addrlen) { return CUDT::accept(u, addr, addrlen); }
|
||||
int srt_connect(SRTSOCKET u, const struct sockaddr * name, int namelen) { return CUDT::connect(u, name, namelen, 0); }
|
||||
SRTSOCKET srt_accept_bond(const SRTSOCKET lsns[], int lsize, int64_t msTimeOut) { return CUDT::accept_bond(lsns, lsize, msTimeOut); }
|
||||
int srt_connect(SRTSOCKET u, const struct sockaddr * name, int namelen) { return CUDT::connect(u, name, namelen, SRT_SEQNO_NONE); }
|
||||
int srt_connect_debug(SRTSOCKET u, const struct sockaddr * name, int namelen, int forced_isn) { return CUDT::connect(u, name, namelen, forced_isn); }
|
||||
int srt_connect_bind(SRTSOCKET u,
|
||||
const struct sockaddr* source,
|
||||
const struct sockaddr* target, int target_len)
|
||||
{
|
||||
return CUDT::connect(u, source, target, target_len);
|
||||
}
|
||||
|
||||
int srt_rendezvous(SRTSOCKET u, const struct sockaddr* local_name, int local_namelen,
|
||||
const struct sockaddr* remote_name, int remote_namelen)
|
||||
{
|
||||
bool yes = 1;
|
||||
CUDT::setsockopt(u, 0, UDT_RENDEZVOUS, &yes, sizeof yes);
|
||||
CUDT::setsockopt(u, 0, SRTO_RENDEZVOUS, &yes, sizeof yes);
|
||||
|
||||
// Note: PORT is 16-bit and at the same location in both sockaddr_in and sockaddr_in6.
|
||||
// Just as a safety precaution, check the structs.
|
||||
if ( (local_name->sa_family != AF_INET && local_name->sa_family != AF_INET6)
|
||||
|| local_name->sa_family != remote_name->sa_family)
|
||||
return SRT_EINVPARAM;
|
||||
return CUDT::APIError(MJ_NOTSUP, MN_INVAL, 0);
|
||||
|
||||
sockaddr_in* local_sin = (sockaddr_in*)local_name;
|
||||
sockaddr_in* remote_sin = (sockaddr_in*)remote_name;
|
||||
|
||||
if (local_sin->sin_port != remote_sin->sin_port)
|
||||
return SRT_EINVPARAM;
|
||||
|
||||
int st = srt_bind(u, local_name, local_namelen);
|
||||
if ( st != 0 )
|
||||
const int st = srt_bind(u, local_name, local_namelen);
|
||||
if (st != 0)
|
||||
return st;
|
||||
|
||||
return srt_connect(u, remote_name, remote_namelen);
|
||||
|
@ -111,17 +172,17 @@ int srt_setsockflag(SRTSOCKET u, SRT_SOCKOPT opt, const void* optval, int optlen
|
|||
int srt_send(SRTSOCKET u, const char * buf, int len) { return CUDT::send(u, buf, len, 0); }
|
||||
int srt_recv(SRTSOCKET u, char * buf, int len) { return CUDT::recv(u, buf, len, 0); }
|
||||
int srt_sendmsg(SRTSOCKET u, const char * buf, int len, int ttl, int inorder) { return CUDT::sendmsg(u, buf, len, ttl, 0!= inorder); }
|
||||
int srt_recvmsg(SRTSOCKET u, char * buf, int len) { uint64_t ign_srctime; return CUDT::recvmsg(u, buf, len, ign_srctime); }
|
||||
int srt_recvmsg(SRTSOCKET u, char * buf, int len) { int64_t ign_srctime; return CUDT::recvmsg(u, buf, len, ign_srctime); }
|
||||
int64_t srt_sendfile(SRTSOCKET u, const char* path, int64_t* offset, int64_t size, int block)
|
||||
{
|
||||
if (!path || !offset )
|
||||
{
|
||||
return CUDT::setError(CUDTException(MJ_NOTSUP, MN_INVAL, 0));
|
||||
return CUDT::APIError(MJ_NOTSUP, MN_INVAL, 0);
|
||||
}
|
||||
fstream ifs(path, ios::binary | ios::in);
|
||||
if (!ifs)
|
||||
{
|
||||
return CUDT::setError(CUDTException(MJ_FILESYSTEM, MN_READFAIL, 0));
|
||||
return CUDT::APIError(MJ_FILESYSTEM, MN_READFAIL, 0);
|
||||
}
|
||||
int64_t ret = CUDT::sendfile(u, ifs, *offset, size, block);
|
||||
ifs.close();
|
||||
|
@ -132,19 +193,29 @@ int64_t srt_recvfile(SRTSOCKET u, const char* path, int64_t* offset, int64_t siz
|
|||
{
|
||||
if (!path || !offset )
|
||||
{
|
||||
return CUDT::setError(CUDTException(MJ_NOTSUP, MN_INVAL, 0));
|
||||
return CUDT::APIError(MJ_NOTSUP, MN_INVAL, 0);
|
||||
}
|
||||
fstream ofs(path, ios::binary | ios::out);
|
||||
if (!ofs)
|
||||
{
|
||||
return CUDT::setError(CUDTException(MJ_FILESYSTEM, MN_WRAVAIL, 0));
|
||||
return CUDT::APIError(MJ_FILESYSTEM, MN_WRAVAIL, 0);
|
||||
}
|
||||
int64_t ret = CUDT::recvfile(u, ofs, *offset, size, block);
|
||||
ofs.close();
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern const SRT_MSGCTRL srt_msgctrl_default = { 0, -1, false, 0, 0, 0, 0 };
|
||||
extern const SRT_MSGCTRL srt_msgctrl_default = {
|
||||
0, // no flags set
|
||||
SRT_MSGTTL_INF,
|
||||
false, // not in order (matters for msg mode only)
|
||||
PB_SUBSEQUENT,
|
||||
0, // srctime: take "now" time
|
||||
SRT_SEQNO_NONE,
|
||||
SRT_MSGNO_NONE,
|
||||
NULL, // grpdata not supplied
|
||||
0 // idem
|
||||
};
|
||||
|
||||
void srt_msgctrl_init(SRT_MSGCTRL* mctrl)
|
||||
{
|
||||
|
@ -155,17 +226,17 @@ int srt_sendmsg2(SRTSOCKET u, const char * buf, int len, SRT_MSGCTRL *mctrl)
|
|||
{
|
||||
// Allow NULL mctrl in the API, but not internally.
|
||||
if (mctrl)
|
||||
return CUDT::sendmsg2(u, buf, len, Ref(*mctrl));
|
||||
return CUDT::sendmsg2(u, buf, len, (*mctrl));
|
||||
SRT_MSGCTRL mignore = srt_msgctrl_default;
|
||||
return CUDT::sendmsg2(u, buf, len, Ref(mignore));
|
||||
return CUDT::sendmsg2(u, buf, len, (mignore));
|
||||
}
|
||||
|
||||
int srt_recvmsg2(SRTSOCKET u, char * buf, int len, SRT_MSGCTRL *mctrl)
|
||||
{
|
||||
if (mctrl)
|
||||
return CUDT::recvmsg2(u, buf, len, Ref(*mctrl));
|
||||
return CUDT::recvmsg2(u, buf, len, (*mctrl));
|
||||
SRT_MSGCTRL mignore = srt_msgctrl_default;
|
||||
return CUDT::recvmsg2(u, buf, len, Ref(mignore));
|
||||
return CUDT::recvmsg2(u, buf, len, (mignore));
|
||||
}
|
||||
|
||||
const char* srt_getlasterror_str() { return UDT::getlasterror().getErrorMessage(); }
|
||||
|
@ -179,8 +250,8 @@ int srt_getlasterror(int* loc_errno)
|
|||
|
||||
const char* srt_strerror(int code, int err)
|
||||
{
|
||||
static CUDTException e;
|
||||
e = CUDTException(CodeMajor(code/1000), CodeMinor(code%1000), err);
|
||||
static srt::CUDTException e;
|
||||
e = srt::CUDTException(CodeMajor(code/1000), CodeMinor(code%1000), err);
|
||||
return(e.getErrorMessage());
|
||||
}
|
||||
|
||||
|
@ -198,6 +269,8 @@ SRT_SOCKSTATUS srt_getsockstate(SRTSOCKET u) { return SRT_SOCKSTATUS((int)CUDT::
|
|||
// event mechanism
|
||||
int srt_epoll_create() { return CUDT::epoll_create(); }
|
||||
|
||||
int srt_epoll_clear_usocks(int eit) { return CUDT::epoll_clear_usocks(eit); }
|
||||
|
||||
// You can use either SRT_EPOLL_* flags or EPOLL* flags from <sys/epoll.h>, both are the same. IN/OUT/ERR only.
|
||||
// events == NULL accepted, in which case all flags are set.
|
||||
int srt_epoll_add_usock(int eid, SRTSOCKET u, const int * events) { return CUDT::epoll_add_usock(eid, u, events); }
|
||||
|
@ -302,17 +375,104 @@ int srt_getsndbuffer(SRTSOCKET sock, size_t* blocks, size_t* bytes)
|
|||
return CUDT::getsndbuffer(sock, blocks, bytes);
|
||||
}
|
||||
|
||||
enum SRT_REJECT_REASON srt_getrejectreason(SRTSOCKET sock)
|
||||
int srt_getrejectreason(SRTSOCKET sock)
|
||||
{
|
||||
return CUDT::rejectReason(sock);
|
||||
}
|
||||
|
||||
int srt_setrejectreason(SRTSOCKET sock, int value)
|
||||
{
|
||||
return CUDT::rejectReason(sock, value);
|
||||
}
|
||||
|
||||
int srt_listen_callback(SRTSOCKET lsn, srt_listen_callback_fn* hook, void* opaq)
|
||||
{
|
||||
if (!hook)
|
||||
return CUDT::setError(CUDTException(MJ_NOTSUP, MN_INVAL));
|
||||
return CUDT::APIError(MJ_NOTSUP, MN_INVAL);
|
||||
|
||||
return CUDT::installAcceptHook(lsn, hook, opaq);
|
||||
}
|
||||
|
||||
int srt_connect_callback(SRTSOCKET lsn, srt_connect_callback_fn* hook, void* opaq)
|
||||
{
|
||||
if (!hook)
|
||||
return CUDT::APIError(MJ_NOTSUP, MN_INVAL);
|
||||
|
||||
return CUDT::installConnectHook(lsn, hook, opaq);
|
||||
}
|
||||
|
||||
uint32_t srt_getversion()
|
||||
{
|
||||
return SrtVersion(SRT_VERSION_MAJOR, SRT_VERSION_MINOR, SRT_VERSION_PATCH);
|
||||
}
|
||||
|
||||
int64_t srt_time_now()
|
||||
{
|
||||
return srt::sync::count_microseconds(srt::sync::steady_clock::now().time_since_epoch());
|
||||
}
|
||||
|
||||
int64_t srt_connection_time(SRTSOCKET sock)
|
||||
{
|
||||
return CUDT::socketStartTime(sock);
|
||||
}
|
||||
|
||||
int srt_clock_type()
|
||||
{
|
||||
return SRT_SYNC_CLOCK;
|
||||
}
|
||||
|
||||
const char* const srt_rejection_reason_msg [] = {
|
||||
"Unknown or erroneous",
|
||||
"Error in system calls",
|
||||
"Peer rejected connection",
|
||||
"Resource allocation failure",
|
||||
"Rogue peer or incorrect parameters",
|
||||
"Listener's backlog exceeded",
|
||||
"Internal Program Error",
|
||||
"Socket is being closed",
|
||||
"Peer version too old",
|
||||
"Rendezvous-mode cookie collision",
|
||||
"Incorrect passphrase",
|
||||
"Password required or unexpected",
|
||||
"MessageAPI/StreamAPI collision",
|
||||
"Congestion controller type collision",
|
||||
"Packet Filter settings error",
|
||||
"Group settings collision",
|
||||
"Connection timeout"
|
||||
};
|
||||
|
||||
// Deprecated, available in SRT API.
|
||||
extern const char* const srt_rejectreason_msg[] = {
|
||||
srt_rejection_reason_msg[0],
|
||||
srt_rejection_reason_msg[1],
|
||||
srt_rejection_reason_msg[2],
|
||||
srt_rejection_reason_msg[3],
|
||||
srt_rejection_reason_msg[4],
|
||||
srt_rejection_reason_msg[5],
|
||||
srt_rejection_reason_msg[6],
|
||||
srt_rejection_reason_msg[7],
|
||||
srt_rejection_reason_msg[8],
|
||||
srt_rejection_reason_msg[9],
|
||||
srt_rejection_reason_msg[10],
|
||||
srt_rejection_reason_msg[11],
|
||||
srt_rejection_reason_msg[12],
|
||||
srt_rejection_reason_msg[13],
|
||||
srt_rejection_reason_msg[14],
|
||||
srt_rejection_reason_msg[15],
|
||||
srt_rejection_reason_msg[16]
|
||||
};
|
||||
|
||||
const char* srt_rejectreason_str(int id)
|
||||
{
|
||||
if (id >= SRT_REJC_PREDEFINED)
|
||||
{
|
||||
return "Application-defined rejection reason";
|
||||
}
|
||||
|
||||
static const size_t ra_size = Size(srt_rejection_reason_msg);
|
||||
if (size_t(id) >= ra_size)
|
||||
return srt_rejection_reason_msg[0];
|
||||
return srt_rejection_reason_msg[id];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,12 +16,14 @@ written by
|
|||
|
||||
// Prevents from misconfiguration through preprocessor.
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <srt_compat.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#if defined(__unix__) && !defined(BSD)
|
||||
#if defined(__unix__) && !defined(BSD) && !defined(SUNOS)
|
||||
#include <features.h>
|
||||
#endif
|
||||
|
||||
|
|
14
trunk/3rdparty/srt-1-fit/srtcore/srt_compat.h
vendored
14
trunk/3rdparty/srt-1-fit/srtcore/srt_compat.h
vendored
|
@ -14,15 +14,15 @@ written by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef HAISRT_COMPAT_H__
|
||||
#define HAISRT_COMPAT_H__
|
||||
#ifndef INC_SRT_COMPAT_H
|
||||
#define INC_SRT_COMPAT_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef SRT_API
|
||||
#ifdef _WIN32
|
||||
#ifndef __MINGW__
|
||||
#ifndef __MINGW32__
|
||||
#ifdef SRT_DYNAMIC
|
||||
#ifdef SRT_EXPORTS
|
||||
#define SRT_API __declspec(dllexport)
|
||||
|
@ -78,6 +78,7 @@ SRT_API const char * SysStrError(int errnum, char * buf, size_t buflen);
|
|||
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
inline std::string SysStrError(int errnum)
|
||||
{
|
||||
char buf[1024];
|
||||
|
@ -93,7 +94,10 @@ inline struct tm SysLocalTime(time_t tt)
|
|||
if (rr == 0)
|
||||
return tms;
|
||||
#else
|
||||
tms = *localtime_r(&tt, &tms);
|
||||
|
||||
// Ignore the error, state that if something
|
||||
// happened, you simply have a pre-cleared tms.
|
||||
localtime_r(&tt, &tms);
|
||||
#endif
|
||||
|
||||
return tms;
|
||||
|
@ -102,4 +106,4 @@ inline struct tm SysLocalTime(time_t tt)
|
|||
|
||||
#endif // defined C++
|
||||
|
||||
#endif // HAISRT_COMPAT_H__
|
||||
#endif // INC_SRT_COMPAT_H
|
||||
|
|
221
trunk/3rdparty/srt-1-fit/srtcore/stats.h
vendored
Normal file
221
trunk/3rdparty/srt-1-fit/srtcore/stats.h
vendored
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2021 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INC_SRT_STATS_H
|
||||
#define INC_SRT_STATS_H
|
||||
|
||||
#include "platform_sys.h"
|
||||
#include "packet.h"
|
||||
|
||||
namespace srt
|
||||
{
|
||||
namespace stats
|
||||
{
|
||||
|
||||
class Packets
|
||||
{
|
||||
public:
|
||||
Packets() : m_count(0) {}
|
||||
|
||||
Packets(uint32_t num) : m_count(num) {}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
Packets& operator+= (const Packets& other)
|
||||
{
|
||||
m_count += other.m_count;
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint32_t count() const
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_count;
|
||||
};
|
||||
|
||||
class BytesPackets
|
||||
{
|
||||
public:
|
||||
BytesPackets()
|
||||
: m_bytes(0)
|
||||
, m_packets(0)
|
||||
{}
|
||||
|
||||
BytesPackets(uint64_t bytes, uint32_t n = 1)
|
||||
: m_bytes(bytes)
|
||||
, m_packets(n)
|
||||
{}
|
||||
|
||||
BytesPackets& operator+= (const BytesPackets& other)
|
||||
{
|
||||
m_bytes += other.m_bytes;
|
||||
m_packets += other.m_packets;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
void reset()
|
||||
{
|
||||
m_packets = 0;
|
||||
m_bytes = 0;
|
||||
}
|
||||
|
||||
void count(uint64_t bytes, size_t n = 1)
|
||||
{
|
||||
m_packets += (uint32_t) n;
|
||||
m_bytes += bytes;
|
||||
}
|
||||
|
||||
uint64_t bytes() const
|
||||
{
|
||||
return m_bytes;
|
||||
}
|
||||
|
||||
uint32_t count() const
|
||||
{
|
||||
return m_packets;
|
||||
}
|
||||
|
||||
uint64_t bytesWithHdr() const
|
||||
{
|
||||
return m_bytes + m_packets * CPacket::SRT_DATA_HDR_SIZE;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t m_bytes;
|
||||
uint32_t m_packets;
|
||||
};
|
||||
|
||||
template <class METRIC_TYPE>
|
||||
struct Metric
|
||||
{
|
||||
METRIC_TYPE trace;
|
||||
METRIC_TYPE total;
|
||||
|
||||
void count(METRIC_TYPE val)
|
||||
{
|
||||
trace += val;
|
||||
total += val;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
trace.reset();
|
||||
total.reset();
|
||||
}
|
||||
|
||||
void resetTrace()
|
||||
{
|
||||
trace.reset();
|
||||
}
|
||||
};
|
||||
|
||||
/// Sender-side statistics.
|
||||
struct Sender
|
||||
{
|
||||
Metric<BytesPackets> sent;
|
||||
Metric<BytesPackets> sentUnique;
|
||||
Metric<BytesPackets> sentRetrans; // The number of data packets retransmitted by the sender.
|
||||
Metric<Packets> lost; // The number of packets reported lost (including repeated reports) to the sender in NAKs.
|
||||
Metric<BytesPackets> dropped; // The number of data packets dropped by the sender.
|
||||
|
||||
Metric<Packets> sentFilterExtra; // The number of packets generate by the packet filter and sent by the sender.
|
||||
|
||||
Metric<Packets> recvdAck; // The number of ACK packets received by the sender.
|
||||
Metric<Packets> recvdNak; // The number of ACK packets received by the sender.
|
||||
|
||||
void reset()
|
||||
{
|
||||
sent.reset();
|
||||
sentUnique.reset();
|
||||
sentRetrans.reset();
|
||||
lost.reset();
|
||||
dropped.reset();
|
||||
recvdAck.reset();
|
||||
recvdNak.reset();
|
||||
sentFilterExtra.reset();
|
||||
}
|
||||
|
||||
void resetTrace()
|
||||
{
|
||||
sent.resetTrace();
|
||||
sentUnique.resetTrace();
|
||||
sentRetrans.resetTrace();
|
||||
lost.resetTrace();
|
||||
dropped.resetTrace();
|
||||
recvdAck.resetTrace();
|
||||
recvdNak.resetTrace();
|
||||
sentFilterExtra.resetTrace();
|
||||
}
|
||||
};
|
||||
|
||||
/// Receiver-side statistics.
|
||||
struct Receiver
|
||||
{
|
||||
Metric<BytesPackets> recvd;
|
||||
Metric<BytesPackets> recvdUnique;
|
||||
Metric<BytesPackets> recvdRetrans; // The number of retransmitted data packets received by the receiver.
|
||||
Metric<BytesPackets> lost; // The number of packets detected by the receiver as lost.
|
||||
Metric<BytesPackets> dropped; // The number of packets dropped by the receiver (as too-late to be delivered).
|
||||
Metric<BytesPackets> recvdBelated; // The number of belated packets received (dropped as too late but eventually received).
|
||||
Metric<BytesPackets> undecrypted; // The number of packets received by the receiver that failed to be decrypted.
|
||||
|
||||
Metric<Packets> recvdFilterExtra; // The number of filter packets (e.g. FEC) received by the receiver.
|
||||
Metric<Packets> suppliedByFilter; // The number of lost packets got from the packet filter at the receiver side (e.g. loss recovered by FEC).
|
||||
Metric<Packets> lossFilter; // The number of lost DATA packets not recovered by the packet filter at the receiver side.
|
||||
|
||||
Metric<Packets> sentAck; // The number of ACK packets sent by the receiver.
|
||||
Metric<Packets> sentNak; // The number of NACK packets sent by the receiver.
|
||||
|
||||
void reset()
|
||||
{
|
||||
recvd.reset();
|
||||
recvdUnique.reset();
|
||||
recvdRetrans.reset();
|
||||
lost.reset();
|
||||
dropped.reset();
|
||||
recvdBelated.reset();
|
||||
undecrypted.reset();
|
||||
recvdFilterExtra.reset();
|
||||
suppliedByFilter.reset();
|
||||
lossFilter.reset();
|
||||
sentAck.reset();
|
||||
sentNak.reset();
|
||||
}
|
||||
|
||||
void resetTrace()
|
||||
{
|
||||
recvd.resetTrace();
|
||||
recvdUnique.resetTrace();
|
||||
recvdRetrans.resetTrace();
|
||||
lost.resetTrace();
|
||||
dropped.resetTrace();
|
||||
recvdBelated.resetTrace();
|
||||
undecrypted.resetTrace();
|
||||
recvdFilterExtra.resetTrace();
|
||||
suppliedByFilter.resetTrace();
|
||||
lossFilter.resetTrace();
|
||||
sentAck.resetTrace();
|
||||
sentNak.resetTrace();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace stats
|
||||
} // namespace srt
|
||||
|
||||
#endif // INC_SRT_STATS_H
|
||||
|
||||
|
154
trunk/3rdparty/srt-1-fit/srtcore/strerror_defs.cpp
vendored
Normal file
154
trunk/3rdparty/srt-1-fit/srtcore/strerror_defs.cpp
vendored
Normal file
|
@ -0,0 +1,154 @@
|
|||
|
||||
/*
|
||||
WARNING: Generated from ../scripts/generate-error-types.tcl
|
||||
|
||||
DO NOT MODIFY.
|
||||
|
||||
Copyright applies as per the generator script.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
namespace srt
|
||||
{
|
||||
// MJ_SUCCESS 'Success'
|
||||
|
||||
const char* strerror_msgs_success [] = {
|
||||
"Success", // MN_NONE = 0
|
||||
""
|
||||
};
|
||||
|
||||
// MJ_SETUP 'Connection setup failure'
|
||||
|
||||
const char* strerror_msgs_setup [] = {
|
||||
"Connection setup failure", // MN_NONE = 0
|
||||
"Connection setup failure: connection timed out", // MN_TIMEOUT = 1
|
||||
"Connection setup failure: connection rejected", // MN_REJECTED = 2
|
||||
"Connection setup failure: unable to create/configure SRT socket", // MN_NORES = 3
|
||||
"Connection setup failure: aborted for security reasons", // MN_SECURITY = 4
|
||||
"Connection setup failure: socket closed during operation", // MN_CLOSED = 5
|
||||
""
|
||||
};
|
||||
|
||||
// MJ_CONNECTION ''
|
||||
|
||||
const char* strerror_msgs_connection [] = {
|
||||
"", // MN_NONE = 0
|
||||
"Connection was broken", // MN_CONNLOST = 1
|
||||
"Connection does not exist", // MN_NOCONN = 2
|
||||
""
|
||||
};
|
||||
|
||||
// MJ_SYSTEMRES 'System resource failure'
|
||||
|
||||
const char* strerror_msgs_systemres [] = {
|
||||
"System resource failure", // MN_NONE = 0
|
||||
"System resource failure: unable to create new threads", // MN_THREAD = 1
|
||||
"System resource failure: unable to allocate buffers", // MN_MEMORY = 2
|
||||
"System resource failure: unable to allocate a system object", // MN_OBJECT = 3
|
||||
""
|
||||
};
|
||||
|
||||
// MJ_FILESYSTEM 'File system failure'
|
||||
|
||||
const char* strerror_msgs_filesystem [] = {
|
||||
"File system failure", // MN_NONE = 0
|
||||
"File system failure: cannot seek read position", // MN_SEEKGFAIL = 1
|
||||
"File system failure: failure in read", // MN_READFAIL = 2
|
||||
"File system failure: cannot seek write position", // MN_SEEKPFAIL = 3
|
||||
"File system failure: failure in write", // MN_WRITEFAIL = 4
|
||||
""
|
||||
};
|
||||
|
||||
// MJ_NOTSUP 'Operation not supported'
|
||||
|
||||
const char* strerror_msgs_notsup [] = {
|
||||
"Operation not supported", // MN_NONE = 0
|
||||
"Operation not supported: Cannot do this operation on a BOUND socket", // MN_ISBOUND = 1
|
||||
"Operation not supported: Cannot do this operation on a CONNECTED socket", // MN_ISCONNECTED = 2
|
||||
"Operation not supported: Bad parameters", // MN_INVAL = 3
|
||||
"Operation not supported: Invalid socket ID", // MN_SIDINVAL = 4
|
||||
"Operation not supported: Cannot do this operation on an UNBOUND socket", // MN_ISUNBOUND = 5
|
||||
"Operation not supported: Socket is not in listening state", // MN_NOLISTEN = 6
|
||||
"Operation not supported: Listen/accept is not supported in rendezous connection setup", // MN_ISRENDEZVOUS = 7
|
||||
"Operation not supported: Cannot call connect on UNBOUND socket in rendezvous connection setup", // MN_ISRENDUNBOUND = 8
|
||||
"Operation not supported: Incorrect use of Message API (sendmsg/recvmsg).", // MN_INVALMSGAPI = 9
|
||||
"Operation not supported: Incorrect use of Buffer API (send/recv) or File API (sendfile/recvfile).", // MN_INVALBUFFERAPI = 10
|
||||
"Operation not supported: Another socket is already listening on the same port", // MN_BUSY = 11
|
||||
"Operation not supported: Message is too large to send (it must be less than the SRT send buffer size)", // MN_XSIZE = 12
|
||||
"Operation not supported: Invalid epoll ID", // MN_EIDINVAL = 13
|
||||
"Operation not supported: All sockets removed from epoll, waiting would deadlock", // MN_EEMPTY = 14
|
||||
"Operation not supported: Another socket is bound to that port and is not reusable for requested settings", // MN_BUSYPORT = 15
|
||||
""
|
||||
};
|
||||
|
||||
// MJ_AGAIN 'Non-blocking call failure'
|
||||
|
||||
const char* strerror_msgs_again [] = {
|
||||
"Non-blocking call failure", // MN_NONE = 0
|
||||
"Non-blocking call failure: no buffer available for sending", // MN_WRAVAIL = 1
|
||||
"Non-blocking call failure: no data available for reading", // MN_RDAVAIL = 2
|
||||
"Non-blocking call failure: transmission timed out", // MN_XMTIMEOUT = 3
|
||||
"Non-blocking call failure: early congestion notification", // MN_CONGESTION = 4
|
||||
""
|
||||
};
|
||||
|
||||
// MJ_PEERERROR 'The peer side has signaled an error'
|
||||
|
||||
const char* strerror_msgs_peererror [] = {
|
||||
"The peer side has signaled an error", // MN_NONE = 0
|
||||
""
|
||||
};
|
||||
|
||||
|
||||
const char** strerror_array_major [] = {
|
||||
strerror_msgs_success, // MJ_SUCCESS = 0
|
||||
strerror_msgs_setup, // MJ_SETUP = 1
|
||||
strerror_msgs_connection, // MJ_CONNECTION = 2
|
||||
strerror_msgs_systemres, // MJ_SYSTEMRES = 3
|
||||
strerror_msgs_filesystem, // MJ_FILESYSTEM = 4
|
||||
strerror_msgs_notsup, // MJ_NOTSUP = 5
|
||||
strerror_msgs_again, // MJ_AGAIN = 6
|
||||
strerror_msgs_peererror, // MJ_PEERERROR = 7
|
||||
NULL
|
||||
};
|
||||
|
||||
#define SRT_ARRAY_SIZE(ARR) sizeof(ARR) / sizeof(ARR[0])
|
||||
|
||||
const size_t strerror_array_sizes [] = {
|
||||
SRT_ARRAY_SIZE(strerror_msgs_success) - 1,
|
||||
SRT_ARRAY_SIZE(strerror_msgs_setup) - 1,
|
||||
SRT_ARRAY_SIZE(strerror_msgs_connection) - 1,
|
||||
SRT_ARRAY_SIZE(strerror_msgs_systemres) - 1,
|
||||
SRT_ARRAY_SIZE(strerror_msgs_filesystem) - 1,
|
||||
SRT_ARRAY_SIZE(strerror_msgs_notsup) - 1,
|
||||
SRT_ARRAY_SIZE(strerror_msgs_again) - 1,
|
||||
SRT_ARRAY_SIZE(strerror_msgs_peererror) - 1,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
const char* strerror_get_message(size_t major, size_t minor)
|
||||
{
|
||||
static const char* const undefined = "UNDEFINED ERROR";
|
||||
|
||||
// Extract the major array
|
||||
if (major >= sizeof(strerror_array_major)/sizeof(const char**))
|
||||
{
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const char** array = strerror_array_major[major];
|
||||
const size_t size = strerror_array_sizes[major];
|
||||
|
||||
if (minor >= size)
|
||||
{
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return array[minor];
|
||||
}
|
||||
|
||||
|
||||
} // namespace srt
|
355
trunk/3rdparty/srt-1-fit/srtcore/sync.cpp
vendored
Normal file
355
trunk/3rdparty/srt-1-fit/srtcore/sync.cpp
vendored
Normal file
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2019 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <cmath>
|
||||
#include "sync.h"
|
||||
#include "srt.h"
|
||||
#include "srt_compat.h"
|
||||
#include "logging.h"
|
||||
#include "common.h"
|
||||
|
||||
// HAVE_CXX11 is defined in utilities.h, included with common.h.
|
||||
// The following conditional inclusion must go after common.h.
|
||||
#if HAVE_CXX11
|
||||
#include <random>
|
||||
#endif
|
||||
|
||||
namespace srt_logging
|
||||
{
|
||||
extern Logger inlog;
|
||||
}
|
||||
using namespace srt_logging;
|
||||
using namespace std;
|
||||
|
||||
namespace srt
|
||||
{
|
||||
namespace sync
|
||||
{
|
||||
|
||||
std::string FormatTime(const steady_clock::time_point& timestamp)
|
||||
{
|
||||
if (is_zero(timestamp))
|
||||
{
|
||||
// Use special string for 0
|
||||
return "00:00:00.000000 [STDY]";
|
||||
}
|
||||
|
||||
const int decimals = clockSubsecondPrecision();
|
||||
const uint64_t total_sec = count_seconds(timestamp.time_since_epoch());
|
||||
const uint64_t days = total_sec / (60 * 60 * 24);
|
||||
const uint64_t hours = total_sec / (60 * 60) - days * 24;
|
||||
const uint64_t minutes = total_sec / 60 - (days * 24 * 60) - hours * 60;
|
||||
const uint64_t seconds = total_sec - (days * 24 * 60 * 60) - hours * 60 * 60 - minutes * 60;
|
||||
ostringstream out;
|
||||
if (days)
|
||||
out << days << "D ";
|
||||
out << setfill('0') << setw(2) << hours << ":"
|
||||
<< setfill('0') << setw(2) << minutes << ":"
|
||||
<< setfill('0') << setw(2) << seconds << "."
|
||||
<< setfill('0') << setw(decimals) << (timestamp - seconds_from(total_sec)).time_since_epoch().count() << " [STDY]";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string FormatTimeSys(const steady_clock::time_point& timestamp)
|
||||
{
|
||||
const time_t now_s = ::time(NULL); // get current time in seconds
|
||||
const steady_clock::time_point now_timestamp = steady_clock::now();
|
||||
const int64_t delta_us = count_microseconds(timestamp - now_timestamp);
|
||||
const int64_t delta_s =
|
||||
floor((static_cast<int64_t>(count_microseconds(now_timestamp.time_since_epoch()) % 1000000) + delta_us) / 1000000.0);
|
||||
const time_t tt = now_s + delta_s;
|
||||
struct tm tm = SysLocalTime(tt); // in seconds
|
||||
char tmp_buf[512];
|
||||
strftime(tmp_buf, 512, "%X.", &tm);
|
||||
|
||||
ostringstream out;
|
||||
out << tmp_buf << setfill('0') << setw(6) << (count_microseconds(timestamp.time_since_epoch()) % 1000000) << " [SYST]";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_STDCXX_SYNC
|
||||
bool StartThread(CThread& th, ThreadFunc&& f, void* args, const string& name)
|
||||
#else
|
||||
bool StartThread(CThread& th, void* (*f) (void*), void* args, const string& name)
|
||||
#endif
|
||||
{
|
||||
ThreadName tn(name);
|
||||
try
|
||||
{
|
||||
#if HAVE_FULL_CXX11 || defined(ENABLE_STDCXX_SYNC)
|
||||
th = CThread(f, args);
|
||||
#else
|
||||
// No move semantics in C++03, therefore using a dedicated function
|
||||
th.create_thread(f, args);
|
||||
#endif
|
||||
}
|
||||
catch (const CThreadException& e)
|
||||
{
|
||||
HLOGC(inlog.Debug, log << name << ": failed to start thread. " << e.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace sync
|
||||
} // namespace srt
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CEvent class
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
srt::sync::CEvent::CEvent()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
m_cond.init();
|
||||
#endif
|
||||
}
|
||||
|
||||
srt::sync::CEvent::~CEvent()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
m_cond.destroy();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool srt::sync::CEvent::lock_wait_until(const TimePoint<steady_clock>& tp)
|
||||
{
|
||||
UniqueLock lock(m_lock);
|
||||
return m_cond.wait_until(lock, tp);
|
||||
}
|
||||
|
||||
void srt::sync::CEvent::notify_one()
|
||||
{
|
||||
return m_cond.notify_one();
|
||||
}
|
||||
|
||||
void srt::sync::CEvent::notify_all()
|
||||
{
|
||||
return m_cond.notify_all();
|
||||
}
|
||||
|
||||
bool srt::sync::CEvent::lock_wait_for(const steady_clock::duration& rel_time)
|
||||
{
|
||||
UniqueLock lock(m_lock);
|
||||
return m_cond.wait_for(lock, rel_time);
|
||||
}
|
||||
|
||||
bool srt::sync::CEvent::wait_for(UniqueLock& lock, const steady_clock::duration& rel_time)
|
||||
{
|
||||
return m_cond.wait_for(lock, rel_time);
|
||||
}
|
||||
|
||||
void srt::sync::CEvent::lock_wait()
|
||||
{
|
||||
UniqueLock lock(m_lock);
|
||||
return wait(lock);
|
||||
}
|
||||
|
||||
void srt::sync::CEvent::wait(UniqueLock& lock)
|
||||
{
|
||||
return m_cond.wait(lock);
|
||||
}
|
||||
|
||||
namespace srt {
|
||||
namespace sync {
|
||||
|
||||
srt::sync::CEvent g_Sync;
|
||||
|
||||
} // namespace sync
|
||||
} // namespace srt
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Timer
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
srt::sync::CTimer::CTimer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
srt::sync::CTimer::~CTimer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool srt::sync::CTimer::sleep_until(TimePoint<steady_clock> tp)
|
||||
{
|
||||
// The class member m_sched_time can be used to interrupt the sleep.
|
||||
// Refer to Timer::interrupt().
|
||||
enterCS(m_event.mutex());
|
||||
m_tsSchedTime = tp;
|
||||
leaveCS(m_event.mutex());
|
||||
|
||||
#if USE_BUSY_WAITING
|
||||
#if defined(_WIN32)
|
||||
// 10 ms on Windows: bad accuracy of timers
|
||||
const steady_clock::duration
|
||||
td_threshold = milliseconds_from(10);
|
||||
#else
|
||||
// 1 ms on non-Windows platforms
|
||||
const steady_clock::duration
|
||||
td_threshold = milliseconds_from(1);
|
||||
#endif
|
||||
#endif // USE_BUSY_WAITING
|
||||
|
||||
TimePoint<steady_clock> cur_tp = steady_clock::now();
|
||||
|
||||
while (cur_tp < m_tsSchedTime)
|
||||
{
|
||||
#if USE_BUSY_WAITING
|
||||
steady_clock::duration td_wait = m_tsSchedTime - cur_tp;
|
||||
if (td_wait <= 2 * td_threshold)
|
||||
break;
|
||||
|
||||
td_wait -= td_threshold;
|
||||
m_event.lock_wait_for(td_wait);
|
||||
#else
|
||||
m_event.lock_wait_until(m_tsSchedTime);
|
||||
#endif // USE_BUSY_WAITING
|
||||
|
||||
cur_tp = steady_clock::now();
|
||||
}
|
||||
|
||||
#if USE_BUSY_WAITING
|
||||
while (cur_tp < m_tsSchedTime)
|
||||
{
|
||||
#ifdef IA32
|
||||
__asm__ volatile ("pause; rep; nop; nop; nop; nop; nop;");
|
||||
#elif IA64
|
||||
__asm__ volatile ("nop 0; nop 0; nop 0; nop 0; nop 0;");
|
||||
#elif AMD64
|
||||
__asm__ volatile ("nop; nop; nop; nop; nop;");
|
||||
#elif defined(_WIN32) && !defined(__MINGW32__)
|
||||
__nop();
|
||||
__nop();
|
||||
__nop();
|
||||
__nop();
|
||||
__nop();
|
||||
#endif
|
||||
|
||||
cur_tp = steady_clock::now();
|
||||
}
|
||||
#endif // USE_BUSY_WAITING
|
||||
|
||||
return cur_tp >= m_tsSchedTime;
|
||||
}
|
||||
|
||||
|
||||
void srt::sync::CTimer::interrupt()
|
||||
{
|
||||
UniqueLock lck(m_event.mutex());
|
||||
m_tsSchedTime = steady_clock::now();
|
||||
m_event.notify_all();
|
||||
}
|
||||
|
||||
|
||||
void srt::sync::CTimer::tick()
|
||||
{
|
||||
m_event.notify_one();
|
||||
}
|
||||
|
||||
|
||||
void srt::sync::CGlobEvent::triggerEvent()
|
||||
{
|
||||
return g_Sync.notify_one();
|
||||
}
|
||||
|
||||
bool srt::sync::CGlobEvent::waitForEvent()
|
||||
{
|
||||
return g_Sync.lock_wait_for(milliseconds_from(10));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Random
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace srt
|
||||
{
|
||||
#if HAVE_CXX11
|
||||
static std::mt19937& randomGen()
|
||||
{
|
||||
static std::random_device s_RandomDevice;
|
||||
static std::mt19937 s_GenMT19937(s_RandomDevice());
|
||||
return s_GenMT19937;
|
||||
}
|
||||
#elif defined(_WIN32) && defined(__MINGW32__)
|
||||
static void initRandSeed()
|
||||
{
|
||||
const int64_t seed = sync::steady_clock::now().time_since_epoch().count();
|
||||
srand((unsigned int) seed);
|
||||
}
|
||||
static pthread_once_t s_InitRandSeedOnce = PTHREAD_ONCE_INIT;
|
||||
#else
|
||||
|
||||
static unsigned int genRandSeed()
|
||||
{
|
||||
// Duration::count() does not depend on any global objects,
|
||||
// therefore it is preferred over count_microseconds(..).
|
||||
const int64_t seed = sync::steady_clock::now().time_since_epoch().count();
|
||||
return (unsigned int) seed;
|
||||
}
|
||||
|
||||
static unsigned int* getRandSeed()
|
||||
{
|
||||
static unsigned int s_uRandSeed = genRandSeed();
|
||||
return &s_uRandSeed;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
int srt::sync::genRandomInt(int minVal, int maxVal)
|
||||
{
|
||||
// This Meyers singleton initialization is thread-safe since C++11, but is not thread-safe in C++03.
|
||||
// A mutex to protect simultaneous access to the random device.
|
||||
// Thread-local storage could be used here instead to store the seed / random device.
|
||||
// However the generator is not used often (Initial Socket ID, Initial sequence number, FileCC),
|
||||
// so sharing a single seed among threads should not impact the performance.
|
||||
static sync::Mutex s_mtxRandomDevice;
|
||||
sync::ScopedLock lck(s_mtxRandomDevice);
|
||||
#if HAVE_CXX11
|
||||
uniform_int_distribution<> dis(minVal, maxVal);
|
||||
return dis(randomGen());
|
||||
#else
|
||||
#if defined(__MINGW32__)
|
||||
// No rand_r(..) for MinGW.
|
||||
pthread_once(&s_InitRandSeedOnce, initRandSeed);
|
||||
// rand() returns a pseudo-random integer in the range 0 to RAND_MAX inclusive
|
||||
// (i.e., the mathematical range [0, RAND_MAX]).
|
||||
// Therefore, rand_0_1 belongs to [0.0, 1.0].
|
||||
const double rand_0_1 = double(rand()) / RAND_MAX;
|
||||
#else // not __MINGW32__
|
||||
// rand_r(..) returns a pseudo-random integer in the range 0 to RAND_MAX inclusive
|
||||
// (i.e., the mathematical range [0, RAND_MAX]).
|
||||
// Therefore, rand_0_1 belongs to [0.0, 1.0].
|
||||
const double rand_0_1 = double(rand_r(getRandSeed())) / RAND_MAX;
|
||||
#endif
|
||||
|
||||
// Map onto [minVal, maxVal].
|
||||
// Note. There is a minuscule probablity to get maxVal+1 as the result.
|
||||
// So we have to use long long to handle cases when maxVal = INT32_MAX.
|
||||
// Also we must check 'res' does not exceed maxVal,
|
||||
// which may happen if rand_0_1 = 1, even though the chances are low.
|
||||
const long long llMaxVal = maxVal;
|
||||
const int res = minVal + static_cast<int>((llMaxVal + 1 - minVal) * rand_0_1);
|
||||
return min(res, maxVal);
|
||||
#endif // HAVE_CXX11
|
||||
}
|
||||
|
945
trunk/3rdparty/srt-1-fit/srtcore/sync.h
vendored
Normal file
945
trunk/3rdparty/srt-1-fit/srtcore/sync.h
vendored
Normal file
|
@ -0,0 +1,945 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2019 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef INC_SRT_SYNC_H
|
||||
#define INC_SRT_SYNC_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#ifdef ENABLE_STDCXX_SYNC
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <atomic>
|
||||
#define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_STDCXX_STEADY
|
||||
#define SRT_SYNC_CLOCK_STR "STDCXX_STEADY"
|
||||
#else
|
||||
#include <pthread.h>
|
||||
|
||||
// Defile clock type to use
|
||||
#ifdef IA32
|
||||
#define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_IA32_RDTSC
|
||||
#define SRT_SYNC_CLOCK_STR "IA32_RDTSC"
|
||||
#elif defined(IA64)
|
||||
#define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_IA64_ITC
|
||||
#define SRT_SYNC_CLOCK_STR "IA64_ITC"
|
||||
#elif defined(AMD64)
|
||||
#define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_AMD64_RDTSC
|
||||
#define SRT_SYNC_CLOCK_STR "AMD64_RDTSC"
|
||||
#elif defined(_WIN32)
|
||||
#define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_WINQPC
|
||||
#define SRT_SYNC_CLOCK_STR "WINQPC"
|
||||
#elif TARGET_OS_MAC
|
||||
#define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_MACH_ABSTIME
|
||||
#define SRT_SYNC_CLOCK_STR "MACH_ABSTIME"
|
||||
#elif defined(ENABLE_MONOTONIC_CLOCK)
|
||||
#define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_GETTIME_MONOTONIC
|
||||
#define SRT_SYNC_CLOCK_STR "GETTIME_MONOTONIC"
|
||||
#else
|
||||
#define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_POSIX_GETTIMEOFDAY
|
||||
#define SRT_SYNC_CLOCK_STR "POSIX_GETTIMEOFDAY"
|
||||
#endif
|
||||
|
||||
#endif // ENABLE_STDCXX_SYNC
|
||||
|
||||
#include "srt.h"
|
||||
#include "utilities.h"
|
||||
#include "srt_attr_defs.h"
|
||||
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
class CUDTException; // defined in common.h
|
||||
|
||||
namespace sync
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Duration class
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if ENABLE_STDCXX_SYNC
|
||||
|
||||
template <class Clock>
|
||||
using Duration = std::chrono::duration<Clock>;
|
||||
|
||||
#else
|
||||
|
||||
/// Class template srt::sync::Duration represents a time interval.
|
||||
/// It consists of a count of ticks of _Clock.
|
||||
/// It is a wrapper of system timers in case of non-C++11 chrono build.
|
||||
template <class Clock>
|
||||
class Duration
|
||||
{
|
||||
public:
|
||||
Duration()
|
||||
: m_duration(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit Duration(int64_t d)
|
||||
: m_duration(d)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
inline int64_t count() const { return m_duration; }
|
||||
|
||||
static Duration zero() { return Duration(); }
|
||||
|
||||
public: // Relational operators
|
||||
inline bool operator>=(const Duration& rhs) const { return m_duration >= rhs.m_duration; }
|
||||
inline bool operator>(const Duration& rhs) const { return m_duration > rhs.m_duration; }
|
||||
inline bool operator==(const Duration& rhs) const { return m_duration == rhs.m_duration; }
|
||||
inline bool operator!=(const Duration& rhs) const { return m_duration != rhs.m_duration; }
|
||||
inline bool operator<=(const Duration& rhs) const { return m_duration <= rhs.m_duration; }
|
||||
inline bool operator<(const Duration& rhs) const { return m_duration < rhs.m_duration; }
|
||||
|
||||
public: // Assignment operators
|
||||
inline void operator*=(const int64_t mult) { m_duration = static_cast<int64_t>(m_duration * mult); }
|
||||
inline void operator+=(const Duration& rhs) { m_duration += rhs.m_duration; }
|
||||
inline void operator-=(const Duration& rhs) { m_duration -= rhs.m_duration; }
|
||||
|
||||
inline Duration operator+(const Duration& rhs) const { return Duration(m_duration + rhs.m_duration); }
|
||||
inline Duration operator-(const Duration& rhs) const { return Duration(m_duration - rhs.m_duration); }
|
||||
inline Duration operator*(const int64_t& rhs) const { return Duration(m_duration * rhs); }
|
||||
inline Duration operator/(const int64_t& rhs) const { return Duration(m_duration / rhs); }
|
||||
|
||||
private:
|
||||
// int64_t range is from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
|
||||
int64_t m_duration;
|
||||
};
|
||||
|
||||
#endif // ENABLE_STDCXX_SYNC
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TimePoint and steadt_clock classes
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if ENABLE_STDCXX_SYNC
|
||||
|
||||
using steady_clock = std::chrono::steady_clock;
|
||||
|
||||
template <class Clock, class Duration = typename Clock::duration>
|
||||
using time_point = std::chrono::time_point<Clock, Duration>;
|
||||
|
||||
template <class Clock>
|
||||
using TimePoint = std::chrono::time_point<Clock>;
|
||||
|
||||
template <class Clock, class Duration = typename Clock::duration>
|
||||
inline bool is_zero(const time_point<Clock, Duration> &tp)
|
||||
{
|
||||
return tp.time_since_epoch() == Clock::duration::zero();
|
||||
}
|
||||
|
||||
inline bool is_zero(const steady_clock::time_point& t)
|
||||
{
|
||||
return t == steady_clock::time_point();
|
||||
}
|
||||
|
||||
#else
|
||||
template <class Clock>
|
||||
class TimePoint;
|
||||
|
||||
class steady_clock
|
||||
{
|
||||
public:
|
||||
typedef Duration<steady_clock> duration;
|
||||
typedef TimePoint<steady_clock> time_point;
|
||||
|
||||
public:
|
||||
static time_point now();
|
||||
};
|
||||
|
||||
/// Represents a point in time
|
||||
template <class Clock>
|
||||
class TimePoint
|
||||
{
|
||||
public:
|
||||
TimePoint()
|
||||
: m_timestamp(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit TimePoint(uint64_t tp)
|
||||
: m_timestamp(tp)
|
||||
{
|
||||
}
|
||||
|
||||
TimePoint(const TimePoint<Clock>& other)
|
||||
: m_timestamp(other.m_timestamp)
|
||||
{
|
||||
}
|
||||
|
||||
TimePoint(const Duration<Clock>& duration_since_epoch)
|
||||
: m_timestamp(duration_since_epoch.count())
|
||||
{
|
||||
}
|
||||
|
||||
~TimePoint() {}
|
||||
|
||||
public: // Relational operators
|
||||
inline bool operator<(const TimePoint<Clock>& rhs) const { return m_timestamp < rhs.m_timestamp; }
|
||||
inline bool operator<=(const TimePoint<Clock>& rhs) const { return m_timestamp <= rhs.m_timestamp; }
|
||||
inline bool operator==(const TimePoint<Clock>& rhs) const { return m_timestamp == rhs.m_timestamp; }
|
||||
inline bool operator!=(const TimePoint<Clock>& rhs) const { return m_timestamp != rhs.m_timestamp; }
|
||||
inline bool operator>=(const TimePoint<Clock>& rhs) const { return m_timestamp >= rhs.m_timestamp; }
|
||||
inline bool operator>(const TimePoint<Clock>& rhs) const { return m_timestamp > rhs.m_timestamp; }
|
||||
|
||||
public: // Arithmetic operators
|
||||
inline Duration<Clock> operator-(const TimePoint<Clock>& rhs) const
|
||||
{
|
||||
return Duration<Clock>(m_timestamp - rhs.m_timestamp);
|
||||
}
|
||||
inline TimePoint operator+(const Duration<Clock>& rhs) const { return TimePoint(m_timestamp + rhs.count()); }
|
||||
inline TimePoint operator-(const Duration<Clock>& rhs) const { return TimePoint(m_timestamp - rhs.count()); }
|
||||
|
||||
public: // Assignment operators
|
||||
inline void operator=(const TimePoint<Clock>& rhs) { m_timestamp = rhs.m_timestamp; }
|
||||
inline void operator+=(const Duration<Clock>& rhs) { m_timestamp += rhs.count(); }
|
||||
inline void operator-=(const Duration<Clock>& rhs) { m_timestamp -= rhs.count(); }
|
||||
|
||||
public: //
|
||||
static inline ATR_CONSTEXPR TimePoint min() { return TimePoint(std::numeric_limits<uint64_t>::min()); }
|
||||
static inline ATR_CONSTEXPR TimePoint max() { return TimePoint(std::numeric_limits<uint64_t>::max()); }
|
||||
|
||||
public:
|
||||
Duration<Clock> time_since_epoch() const;
|
||||
|
||||
private:
|
||||
uint64_t m_timestamp;
|
||||
};
|
||||
|
||||
template <>
|
||||
srt::sync::Duration<srt::sync::steady_clock> srt::sync::TimePoint<srt::sync::steady_clock>::time_since_epoch() const;
|
||||
|
||||
inline Duration<steady_clock> operator*(const int& lhs, const Duration<steady_clock>& rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
#endif // ENABLE_STDCXX_SYNC
|
||||
|
||||
// NOTE: Moved the following class definitons to "atomic_clock.h"
|
||||
// template <class Clock>
|
||||
// class AtomicDuration;
|
||||
// template <class Clock>
|
||||
// class AtomicClock;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Duration and timepoint conversions
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Function return number of decimals in a subsecond precision.
|
||||
/// E.g. for a microsecond accuracy of steady_clock the return would be 6.
|
||||
/// For a nanosecond accuracy of the steady_clock the return value would be 9.
|
||||
int clockSubsecondPrecision();
|
||||
|
||||
#if ENABLE_STDCXX_SYNC
|
||||
|
||||
inline long long count_microseconds(const steady_clock::duration &t)
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(t).count();
|
||||
}
|
||||
|
||||
inline long long count_microseconds(const steady_clock::time_point tp)
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(tp.time_since_epoch()).count();
|
||||
}
|
||||
|
||||
inline long long count_milliseconds(const steady_clock::duration &t)
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(t).count();
|
||||
}
|
||||
|
||||
inline long long count_seconds(const steady_clock::duration &t)
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(t).count();
|
||||
}
|
||||
|
||||
inline steady_clock::duration microseconds_from(int64_t t_us)
|
||||
{
|
||||
return std::chrono::microseconds(t_us);
|
||||
}
|
||||
|
||||
inline steady_clock::duration milliseconds_from(int64_t t_ms)
|
||||
{
|
||||
return std::chrono::milliseconds(t_ms);
|
||||
}
|
||||
|
||||
inline steady_clock::duration seconds_from(int64_t t_s)
|
||||
{
|
||||
return std::chrono::seconds(t_s);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int64_t count_microseconds(const steady_clock::duration& t);
|
||||
int64_t count_milliseconds(const steady_clock::duration& t);
|
||||
int64_t count_seconds(const steady_clock::duration& t);
|
||||
|
||||
Duration<steady_clock> microseconds_from(int64_t t_us);
|
||||
Duration<steady_clock> milliseconds_from(int64_t t_ms);
|
||||
Duration<steady_clock> seconds_from(int64_t t_s);
|
||||
|
||||
inline bool is_zero(const TimePoint<steady_clock>& t)
|
||||
{
|
||||
return t == TimePoint<steady_clock>();
|
||||
}
|
||||
|
||||
#endif // ENABLE_STDCXX_SYNC
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Mutex section
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if ENABLE_STDCXX_SYNC
|
||||
using Mutex = std::mutex;
|
||||
using UniqueLock = std::unique_lock<std::mutex>;
|
||||
using ScopedLock = std::lock_guard<std::mutex>;
|
||||
#else
|
||||
/// Mutex is a class wrapper, that should mimic the std::chrono::mutex class.
|
||||
/// At the moment the extra function ref() is temporally added to allow calls
|
||||
/// to pthread_cond_timedwait(). Will be removed by introducing CEvent.
|
||||
class SRT_ATTR_CAPABILITY("mutex") Mutex
|
||||
{
|
||||
friend class SyncEvent;
|
||||
|
||||
public:
|
||||
Mutex();
|
||||
~Mutex();
|
||||
|
||||
public:
|
||||
int lock() SRT_ATTR_ACQUIRE();
|
||||
int unlock() SRT_ATTR_RELEASE();
|
||||
|
||||
/// @return true if the lock was acquired successfully, otherwise false
|
||||
bool try_lock() SRT_ATTR_TRY_ACQUIRE(true);
|
||||
|
||||
// TODO: To be removed with introduction of the CEvent.
|
||||
pthread_mutex_t& ref() { return m_mutex; }
|
||||
|
||||
private:
|
||||
pthread_mutex_t m_mutex;
|
||||
};
|
||||
|
||||
/// A pthread version of std::chrono::scoped_lock<mutex> (or lock_guard for C++11)
|
||||
class SRT_ATTR_SCOPED_CAPABILITY ScopedLock
|
||||
{
|
||||
public:
|
||||
SRT_ATTR_ACQUIRE(m)
|
||||
explicit ScopedLock(Mutex& m);
|
||||
|
||||
SRT_ATTR_RELEASE()
|
||||
~ScopedLock();
|
||||
|
||||
private:
|
||||
Mutex& m_mutex;
|
||||
};
|
||||
|
||||
/// A pthread version of std::chrono::unique_lock<mutex>
|
||||
class SRT_ATTR_SCOPED_CAPABILITY UniqueLock
|
||||
{
|
||||
friend class SyncEvent;
|
||||
int m_iLocked;
|
||||
Mutex& m_Mutex;
|
||||
|
||||
public:
|
||||
SRT_ATTR_ACQUIRE(m)
|
||||
explicit UniqueLock(Mutex &m);
|
||||
|
||||
SRT_ATTR_RELEASE()
|
||||
~UniqueLock();
|
||||
|
||||
public:
|
||||
SRT_ATTR_ACQUIRE()
|
||||
void lock();
|
||||
|
||||
SRT_ATTR_RELEASE()
|
||||
void unlock();
|
||||
|
||||
SRT_ATTR_RETURN_CAPABILITY(m_Mutex)
|
||||
Mutex* mutex(); // reflects C++11 unique_lock::mutex()
|
||||
};
|
||||
#endif // ENABLE_STDCXX_SYNC
|
||||
|
||||
inline void enterCS(Mutex& m) SRT_ATTR_EXCLUDES(m) SRT_ATTR_ACQUIRE(m) { m.lock(); }
|
||||
|
||||
inline bool tryEnterCS(Mutex& m) SRT_ATTR_EXCLUDES(m) SRT_ATTR_TRY_ACQUIRE(true, m) { return m.try_lock(); }
|
||||
|
||||
inline void leaveCS(Mutex& m) SRT_ATTR_REQUIRES(m) SRT_ATTR_RELEASE(m) { m.unlock(); }
|
||||
|
||||
class InvertedLock
|
||||
{
|
||||
Mutex& m_mtx;
|
||||
|
||||
public:
|
||||
SRT_ATTR_REQUIRES(m) SRT_ATTR_RELEASE(m)
|
||||
InvertedLock(Mutex& m)
|
||||
: m_mtx(m)
|
||||
{
|
||||
m_mtx.unlock();
|
||||
}
|
||||
|
||||
SRT_ATTR_ACQUIRE(m_mtx)
|
||||
~InvertedLock()
|
||||
{
|
||||
m_mtx.lock();
|
||||
}
|
||||
};
|
||||
|
||||
inline void setupMutex(Mutex&, const char*) {}
|
||||
inline void releaseMutex(Mutex&) {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Condition section
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class Condition
|
||||
{
|
||||
public:
|
||||
Condition();
|
||||
~Condition();
|
||||
|
||||
public:
|
||||
/// These functions do not align with C++11 version. They are here hopefully as a temporal solution
|
||||
/// to avoud issues with static initialization of CV on windows.
|
||||
void init();
|
||||
void destroy();
|
||||
|
||||
public:
|
||||
/// Causes the current thread to block until the condition variable is notified
|
||||
/// or a spurious wakeup occurs.
|
||||
///
|
||||
/// @param lock Corresponding mutex locked by UniqueLock
|
||||
void wait(UniqueLock& lock);
|
||||
|
||||
/// Atomically releases lock, blocks the current executing thread,
|
||||
/// and adds it to the list of threads waiting on *this.
|
||||
/// The thread will be unblocked when notify_all() or notify_one() is executed,
|
||||
/// or when the relative timeout rel_time expires.
|
||||
/// It may also be unblocked spuriously. When unblocked, regardless of the reason,
|
||||
/// lock is reacquired and wait_for() exits.
|
||||
///
|
||||
/// @returns false if the relative timeout specified by rel_time expired,
|
||||
/// true otherwise (signal or spurious wake up).
|
||||
///
|
||||
/// @note Calling this function if lock.mutex()
|
||||
/// is not locked by the current thread is undefined behavior.
|
||||
/// Calling this function if lock.mutex() is not the same mutex as the one
|
||||
/// used by all other threads that are currently waiting on the same
|
||||
/// condition variable is undefined behavior.
|
||||
bool wait_for(UniqueLock& lock, const steady_clock::duration& rel_time);
|
||||
|
||||
/// Causes the current thread to block until the condition variable is notified,
|
||||
/// a specific time is reached, or a spurious wakeup occurs.
|
||||
///
|
||||
/// @param[in] lock an object of type UniqueLock, which must be locked by the current thread
|
||||
/// @param[in] timeout_time an object of type time_point representing the time when to stop waiting
|
||||
///
|
||||
/// @returns false if the relative timeout specified by timeout_time expired,
|
||||
/// true otherwise (signal or spurious wake up).
|
||||
bool wait_until(UniqueLock& lock, const steady_clock::time_point& timeout_time);
|
||||
|
||||
/// Calling notify_one() unblocks one of the waiting threads,
|
||||
/// if any threads are waiting on this CV.
|
||||
void notify_one();
|
||||
|
||||
/// Unblocks all threads currently waiting for this CV.
|
||||
void notify_all();
|
||||
|
||||
private:
|
||||
#if ENABLE_STDCXX_SYNC
|
||||
std::condition_variable m_cv;
|
||||
#else
|
||||
pthread_cond_t m_cv;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline void setupCond(Condition& cv, const char*) { cv.init(); }
|
||||
inline void releaseCond(Condition& cv) { cv.destroy(); }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Event (CV) section
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This class is used for condition variable combined with mutex by different ways.
|
||||
// This should provide a cleaner API around locking with debug-logging inside.
|
||||
class CSync
|
||||
{
|
||||
protected:
|
||||
Condition* m_cond;
|
||||
UniqueLock* m_locker;
|
||||
|
||||
public:
|
||||
// Locked version: must be declared only after the declaration of UniqueLock,
|
||||
// which has locked the mutex. On this delegate you should call only
|
||||
// signal_locked() and pass the UniqueLock variable that should remain locked.
|
||||
// Also wait() and wait_for() can be used only with this socket.
|
||||
CSync(Condition& cond, UniqueLock& g)
|
||||
: m_cond(&cond), m_locker(&g)
|
||||
{
|
||||
// XXX it would be nice to check whether the owner is also current thread
|
||||
// but this can't be done portable way.
|
||||
|
||||
// When constructed by this constructor, the user is expected
|
||||
// to only call signal_locked() function. You should pass the same guard
|
||||
// variable that you have used for construction as its argument.
|
||||
}
|
||||
|
||||
// COPY CONSTRUCTOR: DEFAULT!
|
||||
|
||||
// Wait indefinitely, until getting a signal on CV.
|
||||
void wait()
|
||||
{
|
||||
m_cond->wait(*m_locker);
|
||||
}
|
||||
|
||||
/// Block the call until either @a timestamp time achieved
|
||||
/// or the conditional is signaled.
|
||||
/// @param [in] delay Maximum time to wait since the moment of the call
|
||||
/// @retval false if the relative timeout specified by rel_time expired,
|
||||
/// @retval true if condition is signaled or spurious wake up.
|
||||
bool wait_for(const steady_clock::duration& delay)
|
||||
{
|
||||
return m_cond->wait_for(*m_locker, delay);
|
||||
}
|
||||
|
||||
// Wait until the given time is achieved.
|
||||
/// @param [in] exptime The target time to wait until.
|
||||
/// @retval false if the target wait time is reached.
|
||||
/// @retval true if condition is signal or spurious wake up.
|
||||
bool wait_until(const steady_clock::time_point& exptime)
|
||||
{
|
||||
return m_cond->wait_until(*m_locker, exptime);
|
||||
}
|
||||
|
||||
// Static ad-hoc version
|
||||
static void lock_notify_one(Condition& cond, Mutex& m)
|
||||
{
|
||||
ScopedLock lk(m); // XXX with thread logging, don't use ScopedLock directly!
|
||||
cond.notify_one();
|
||||
}
|
||||
|
||||
static void lock_notify_all(Condition& cond, Mutex& m)
|
||||
{
|
||||
ScopedLock lk(m); // XXX with thread logging, don't use ScopedLock directly!
|
||||
cond.notify_all();
|
||||
}
|
||||
|
||||
void notify_one_locked(UniqueLock& lk SRT_ATR_UNUSED)
|
||||
{
|
||||
// EXPECTED: lk.mutex() is LOCKED.
|
||||
m_cond->notify_one();
|
||||
}
|
||||
|
||||
void notify_all_locked(UniqueLock& lk SRT_ATR_UNUSED)
|
||||
{
|
||||
// EXPECTED: lk.mutex() is LOCKED.
|
||||
m_cond->notify_all();
|
||||
}
|
||||
|
||||
// The *_relaxed functions are to be used in case when you don't care
|
||||
// whether the associated mutex is locked or not (you accept the case that
|
||||
// a mutex isn't locked and the condition notification gets effectively
|
||||
// missed), or you somehow know that the mutex is locked, but you don't
|
||||
// have access to the associated UniqueLock object. This function, although
|
||||
// it does the same thing as CSync::notify_one_locked etc. here for the
|
||||
// user to declare explicitly that notifying is done without being
|
||||
// prematurely certain that the associated mutex is locked.
|
||||
//
|
||||
// It is then expected that whenever these functions are used, an extra
|
||||
// comment is provided to explain, why the use of the relaxed notification
|
||||
// is correctly used.
|
||||
|
||||
void notify_one_relaxed() { notify_one_relaxed(*m_cond); }
|
||||
static void notify_one_relaxed(Condition& cond) { cond.notify_one(); }
|
||||
static void notify_all_relaxed(Condition& cond) { cond.notify_all(); }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CEvent class
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// XXX Do not use this class now, there's an unknown issue
|
||||
// connected to object management with the use of release* functions.
|
||||
// Until this is solved, stay with separate *Cond and *Lock fields.
|
||||
class CEvent
|
||||
{
|
||||
public:
|
||||
CEvent();
|
||||
~CEvent();
|
||||
|
||||
public:
|
||||
Mutex& mutex() { return m_lock; }
|
||||
Condition& cond() { return m_cond; }
|
||||
|
||||
public:
|
||||
/// Causes the current thread to block until
|
||||
/// a specific time is reached.
|
||||
///
|
||||
/// @return true if condition occured or spuriously woken up
|
||||
/// false on timeout
|
||||
bool lock_wait_until(const steady_clock::time_point& tp);
|
||||
|
||||
/// Blocks the current executing thread,
|
||||
/// and adds it to the list of threads waiting on* this.
|
||||
/// The thread will be unblocked when notify_all() or notify_one() is executed,
|
||||
/// or when the relative timeout rel_time expires.
|
||||
/// It may also be unblocked spuriously.
|
||||
/// Uses internal mutex to lock.
|
||||
///
|
||||
/// @return true if condition occured or spuriously woken up
|
||||
/// false on timeout
|
||||
bool lock_wait_for(const steady_clock::duration& rel_time);
|
||||
|
||||
/// Atomically releases lock, blocks the current executing thread,
|
||||
/// and adds it to the list of threads waiting on* this.
|
||||
/// The thread will be unblocked when notify_all() or notify_one() is executed,
|
||||
/// or when the relative timeout rel_time expires.
|
||||
/// It may also be unblocked spuriously.
|
||||
/// When unblocked, regardless of the reason, lock is reacquiredand wait_for() exits.
|
||||
///
|
||||
/// @return true if condition occured or spuriously woken up
|
||||
/// false on timeout
|
||||
bool wait_for(UniqueLock& lk, const steady_clock::duration& rel_time);
|
||||
|
||||
void lock_wait();
|
||||
|
||||
void wait(UniqueLock& lk);
|
||||
|
||||
void notify_one();
|
||||
|
||||
void notify_all();
|
||||
|
||||
void lock_notify_one()
|
||||
{
|
||||
ScopedLock lk(m_lock); // XXX with thread logging, don't use ScopedLock directly!
|
||||
m_cond.notify_one();
|
||||
}
|
||||
|
||||
void lock_notify_all()
|
||||
{
|
||||
ScopedLock lk(m_lock); // XXX with thread logging, don't use ScopedLock directly!
|
||||
m_cond.notify_all();
|
||||
}
|
||||
|
||||
private:
|
||||
Mutex m_lock;
|
||||
Condition m_cond;
|
||||
};
|
||||
|
||||
|
||||
// This class binds together the functionality of
|
||||
// UniqueLock and CSync. It provides a simple interface of CSync
|
||||
// while having already the UniqueLock applied in the scope,
|
||||
// so a safe statement can be made about the mutex being locked
|
||||
// when signalling or waiting.
|
||||
class CUniqueSync: public CSync
|
||||
{
|
||||
UniqueLock m_ulock;
|
||||
|
||||
public:
|
||||
|
||||
UniqueLock& locker() { return m_ulock; }
|
||||
|
||||
CUniqueSync(Mutex& mut, Condition& cnd)
|
||||
: CSync(cnd, m_ulock)
|
||||
, m_ulock(mut)
|
||||
{
|
||||
}
|
||||
|
||||
CUniqueSync(CEvent& event)
|
||||
: CSync(event.cond(), m_ulock)
|
||||
, m_ulock(event.mutex())
|
||||
{
|
||||
}
|
||||
|
||||
// These functions can be used safely because
|
||||
// this whole class guarantees that whatever happens
|
||||
// while its object exists is that the mutex is locked.
|
||||
|
||||
void notify_one()
|
||||
{
|
||||
m_cond->notify_one();
|
||||
}
|
||||
|
||||
void notify_all()
|
||||
{
|
||||
m_cond->notify_all();
|
||||
}
|
||||
};
|
||||
|
||||
class CTimer
|
||||
{
|
||||
public:
|
||||
CTimer();
|
||||
~CTimer();
|
||||
|
||||
public:
|
||||
/// Causes the current thread to block until
|
||||
/// the specified time is reached.
|
||||
/// Sleep can be interrupted by calling interrupt()
|
||||
/// or woken up to recheck the scheduled time by tick()
|
||||
/// @param tp target time to sleep until
|
||||
///
|
||||
/// @return true if the specified time was reached
|
||||
/// false should never happen
|
||||
bool sleep_until(steady_clock::time_point tp);
|
||||
|
||||
/// Resets target wait time and interrupts waiting
|
||||
/// in sleep_until(..)
|
||||
void interrupt();
|
||||
|
||||
/// Wakes up waiting thread (sleep_until(..)) without
|
||||
/// changing the target waiting time to force a recheck
|
||||
/// of the current time in comparisson to the target time.
|
||||
void tick();
|
||||
|
||||
private:
|
||||
CEvent m_event;
|
||||
steady_clock::time_point m_tsSchedTime;
|
||||
};
|
||||
|
||||
|
||||
/// Print steady clock timepoint in a human readable way.
|
||||
/// days HH:MM:SS.us [STD]
|
||||
/// Example: 1D 02:12:56.123456
|
||||
///
|
||||
/// @param [in] steady clock timepoint
|
||||
/// @returns a string with a formatted time representation
|
||||
std::string FormatTime(const steady_clock::time_point& time);
|
||||
|
||||
/// Print steady clock timepoint relative to the current system time
|
||||
/// Date HH:MM:SS.us [SYS]
|
||||
/// @param [in] steady clock timepoint
|
||||
/// @returns a string with a formatted time representation
|
||||
std::string FormatTimeSys(const steady_clock::time_point& time);
|
||||
|
||||
enum eDurationUnit {DUNIT_S, DUNIT_MS, DUNIT_US};
|
||||
|
||||
template <eDurationUnit u>
|
||||
struct DurationUnitName;
|
||||
|
||||
template<>
|
||||
struct DurationUnitName<DUNIT_US>
|
||||
{
|
||||
static const char* name() { return "us"; }
|
||||
static double count(const steady_clock::duration& dur) { return static_cast<double>(count_microseconds(dur)); }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct DurationUnitName<DUNIT_MS>
|
||||
{
|
||||
static const char* name() { return "ms"; }
|
||||
static double count(const steady_clock::duration& dur) { return static_cast<double>(count_microseconds(dur))/1000.0; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct DurationUnitName<DUNIT_S>
|
||||
{
|
||||
static const char* name() { return "s"; }
|
||||
static double count(const steady_clock::duration& dur) { return static_cast<double>(count_microseconds(dur))/1000000.0; }
|
||||
};
|
||||
|
||||
template<eDurationUnit UNIT>
|
||||
inline std::string FormatDuration(const steady_clock::duration& dur)
|
||||
{
|
||||
return Sprint(DurationUnitName<UNIT>::count(dur)) + DurationUnitName<UNIT>::name();
|
||||
}
|
||||
|
||||
inline std::string FormatDuration(const steady_clock::duration& dur)
|
||||
{
|
||||
return FormatDuration<DUNIT_US>(dur);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CGlobEvent class
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CGlobEvent
|
||||
{
|
||||
public:
|
||||
/// Triggers the event and notifies waiting threads.
|
||||
/// Simply calls notify_one().
|
||||
static void triggerEvent();
|
||||
|
||||
/// Waits for the event to be triggered with 10ms timeout.
|
||||
/// Simply calls wait_for().
|
||||
static bool waitForEvent();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CThread class
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef ENABLE_STDCXX_SYNC
|
||||
typedef std::system_error CThreadException;
|
||||
using CThread = std::thread;
|
||||
namespace this_thread = std::this_thread;
|
||||
#else // pthreads wrapper version
|
||||
typedef CUDTException CThreadException;
|
||||
|
||||
class CThread
|
||||
{
|
||||
public:
|
||||
CThread();
|
||||
/// @throws std::system_error if the thread could not be started.
|
||||
CThread(void *(*start_routine) (void *), void *arg);
|
||||
|
||||
#if HAVE_FULL_CXX11
|
||||
CThread& operator=(CThread &other) = delete;
|
||||
CThread& operator=(CThread &&other);
|
||||
#else
|
||||
CThread& operator=(CThread &other);
|
||||
/// To be used only in StartThread function.
|
||||
/// Creates a new stread and assigns to this.
|
||||
/// @throw CThreadException
|
||||
void create_thread(void *(*start_routine) (void *), void *arg);
|
||||
#endif
|
||||
|
||||
public: // Observers
|
||||
/// Checks if the CThread object identifies an active thread of execution.
|
||||
/// A default constructed thread is not joinable.
|
||||
/// A thread that has finished executing code, but has not yet been joined
|
||||
/// is still considered an active thread of execution and is therefore joinable.
|
||||
bool joinable() const;
|
||||
|
||||
struct id
|
||||
{
|
||||
explicit id(const pthread_t t)
|
||||
: value(t)
|
||||
{}
|
||||
|
||||
const pthread_t value;
|
||||
inline bool operator==(const id& second) const
|
||||
{
|
||||
return pthread_equal(value, second.value) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
/// Returns the id of the current thread.
|
||||
/// In this implementation the ID is the pthread_t.
|
||||
const id get_id() const { return id(m_thread); }
|
||||
|
||||
public:
|
||||
/// Blocks the current thread until the thread identified by *this finishes its execution.
|
||||
/// If that thread has already terminated, then join() returns immediately.
|
||||
///
|
||||
/// @throws std::system_error if an error occurs
|
||||
void join();
|
||||
|
||||
public: // Internal
|
||||
/// Calls pthread_create, throws exception on failure.
|
||||
/// @throw CThreadException
|
||||
void create(void *(*start_routine) (void *), void *arg);
|
||||
|
||||
private:
|
||||
pthread_t m_thread;
|
||||
};
|
||||
|
||||
template <class Stream>
|
||||
inline Stream& operator<<(Stream& str, const CThread::id& cid)
|
||||
{
|
||||
#if defined(_WIN32) && (defined(PTW32_VERSION) || defined (__PTW32_VERSION))
|
||||
// This is a version specific for pthread-win32 implementation
|
||||
// Here pthread_t type is a structure that is not convertible
|
||||
// to a number at all.
|
||||
return str << pthread_getw32threadid_np(cid.value);
|
||||
#else
|
||||
return str << cid.value;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
const inline CThread::id get_id() { return CThread::id (pthread_self()); }
|
||||
|
||||
inline void sleep_for(const steady_clock::duration& t)
|
||||
{
|
||||
#if !defined(_WIN32)
|
||||
usleep(count_microseconds(t)); // microseconds
|
||||
#else
|
||||
Sleep((DWORD) count_milliseconds(t));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// StartThread function should be used to do CThread assignments:
|
||||
/// @code
|
||||
/// CThread a();
|
||||
/// a = CThread(func, args);
|
||||
/// @endcode
|
||||
///
|
||||
/// @returns true if thread was started successfully,
|
||||
/// false on failure
|
||||
///
|
||||
#ifdef ENABLE_STDCXX_SYNC
|
||||
typedef void* (&ThreadFunc) (void*);
|
||||
bool StartThread(CThread& th, ThreadFunc&& f, void* args, const std::string& name);
|
||||
#else
|
||||
bool StartThread(CThread& th, void* (*f) (void*), void* args, const std::string& name);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CThreadError class - thread local storage wrapper
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Set thread local error
|
||||
/// @param e new CUDTException
|
||||
void SetThreadLocalError(const CUDTException& e);
|
||||
|
||||
/// Get thread local error
|
||||
/// @returns CUDTException pointer
|
||||
CUDTException& GetThreadLocalError();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Random distribution functions.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Generate a uniform-distributed random integer from [minVal; maxVal].
|
||||
/// If HAVE_CXX11, uses std::uniform_distribution(std::random_device).
|
||||
/// @param[in] minVal minimum allowed value of the resulting random number.
|
||||
/// @param[in] maxVal maximum allowed value of the resulting random number.
|
||||
int genRandomInt(int minVal, int maxVal);
|
||||
|
||||
} // namespace sync
|
||||
} // namespace srt
|
||||
|
||||
#include "atomic_clock.h"
|
||||
|
||||
#endif // INC_SRT_SYNC_H
|
108
trunk/3rdparty/srt-1-fit/srtcore/sync_cxx11.cpp
vendored
Normal file
108
trunk/3rdparty/srt-1-fit/srtcore/sync_cxx11.cpp
vendored
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2020 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <math.h>
|
||||
#include <stdexcept>
|
||||
#include "sync.h"
|
||||
#include "srt_compat.h"
|
||||
#include "common.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Clock frequency helpers
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace {
|
||||
template <int val>
|
||||
int pow10();
|
||||
|
||||
template <>
|
||||
int pow10<10>()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <int val>
|
||||
int pow10()
|
||||
{
|
||||
return 1 + pow10<val / 10>();
|
||||
}
|
||||
}
|
||||
|
||||
int srt::sync::clockSubsecondPrecision()
|
||||
{
|
||||
const int64_t ticks_per_sec = (srt::sync::steady_clock::period::den / srt::sync::steady_clock::period::num);
|
||||
const int decimals = pow10<ticks_per_sec>();
|
||||
return decimals;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SyncCond (based on stl chrono C++11)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
srt::sync::Condition::Condition() {}
|
||||
|
||||
srt::sync::Condition::~Condition() {}
|
||||
|
||||
void srt::sync::Condition::init() {}
|
||||
|
||||
void srt::sync::Condition::destroy() {}
|
||||
|
||||
void srt::sync::Condition::wait(UniqueLock& lock)
|
||||
{
|
||||
m_cv.wait(lock);
|
||||
}
|
||||
|
||||
bool srt::sync::Condition::wait_for(UniqueLock& lock, const steady_clock::duration& rel_time)
|
||||
{
|
||||
// Another possible implementation is wait_until(steady_clock::now() + timeout);
|
||||
return m_cv.wait_for(lock, rel_time) != std::cv_status::timeout;
|
||||
}
|
||||
|
||||
bool srt::sync::Condition::wait_until(UniqueLock& lock, const steady_clock::time_point& timeout_time)
|
||||
{
|
||||
return m_cv.wait_until(lock, timeout_time) != std::cv_status::timeout;
|
||||
}
|
||||
|
||||
void srt::sync::Condition::notify_one()
|
||||
{
|
||||
m_cv.notify_one();
|
||||
}
|
||||
|
||||
void srt::sync::Condition::notify_all()
|
||||
{
|
||||
m_cv.notify_all();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CThreadError class - thread local storage error wrapper
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Threal local error will be used by CUDTUnited
|
||||
// with a static scope, therefore static thread_local
|
||||
static thread_local srt::CUDTException s_thErr;
|
||||
|
||||
void srt::sync::SetThreadLocalError(const srt::CUDTException& e)
|
||||
{
|
||||
s_thErr = e;
|
||||
}
|
||||
|
||||
srt::CUDTException& srt::sync::GetThreadLocalError()
|
||||
{
|
||||
return s_thErr;
|
||||
}
|
||||
|
572
trunk/3rdparty/srt-1-fit/srtcore/sync_posix.cpp
vendored
Normal file
572
trunk/3rdparty/srt-1-fit/srtcore/sync_posix.cpp
vendored
Normal file
|
@ -0,0 +1,572 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2019 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <math.h>
|
||||
#include <stdexcept>
|
||||
#include "sync.h"
|
||||
#include "utilities.h"
|
||||
#include "udt.h"
|
||||
#include "srt.h"
|
||||
#include "srt_compat.h"
|
||||
#include "logging.h"
|
||||
#include "common.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "win/wintime.h"
|
||||
#include <sys/timeb.h>
|
||||
#elif TARGET_OS_MAC
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
namespace srt_logging
|
||||
{
|
||||
extern Logger inlog;
|
||||
}
|
||||
using namespace srt_logging;
|
||||
|
||||
namespace srt
|
||||
{
|
||||
namespace sync
|
||||
{
|
||||
|
||||
static void rdtsc(uint64_t& x)
|
||||
{
|
||||
#if SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_IA32_RDTSC
|
||||
uint32_t lval, hval;
|
||||
// asm volatile ("push %eax; push %ebx; push %ecx; push %edx");
|
||||
// asm volatile ("xor %eax, %eax; cpuid");
|
||||
asm volatile("rdtsc" : "=a"(lval), "=d"(hval));
|
||||
// asm volatile ("pop %edx; pop %ecx; pop %ebx; pop %eax");
|
||||
x = hval;
|
||||
x = (x << 32) | lval;
|
||||
#elif SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_IA64_ITC
|
||||
asm("mov %0=ar.itc" : "=r"(x)::"memory");
|
||||
#elif SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_AMD64_RDTSC
|
||||
uint32_t lval, hval;
|
||||
asm("rdtsc" : "=a"(lval), "=d"(hval));
|
||||
x = hval;
|
||||
x = (x << 32) | lval;
|
||||
#elif SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_WINQPC
|
||||
// This function should not fail, because we checked the QPC
|
||||
// when calling to QueryPerformanceFrequency. If it failed,
|
||||
// the m_bUseMicroSecond was set to true.
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&x);
|
||||
#elif SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_MACH_ABSTIME
|
||||
x = mach_absolute_time();
|
||||
#elif SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_GETTIME_MONOTONIC
|
||||
// get_cpu_frequency() returns 1 us accuracy in this case
|
||||
timespec tm;
|
||||
clock_gettime(CLOCK_MONOTONIC, &tm);
|
||||
x = tm.tv_sec * uint64_t(1000000) + (tm.tv_nsec / 1000);
|
||||
#elif SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_POSIX_GETTIMEOFDAY
|
||||
// use system call to read time clock for other archs
|
||||
timeval t;
|
||||
gettimeofday(&t, 0);
|
||||
x = t.tv_sec * uint64_t(1000000) + t.tv_usec;
|
||||
#else
|
||||
#error Wrong SRT_SYNC_CLOCK
|
||||
#endif
|
||||
}
|
||||
|
||||
static int64_t get_cpu_frequency()
|
||||
{
|
||||
int64_t frequency = 1; // 1 tick per microsecond.
|
||||
|
||||
#if SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_WINQPC
|
||||
LARGE_INTEGER ccf; // in counts per second
|
||||
if (QueryPerformanceFrequency(&ccf))
|
||||
{
|
||||
frequency = ccf.QuadPart / 1000000; // counts per microsecond
|
||||
if (frequency == 0)
|
||||
{
|
||||
LOGC(inlog.Warn, log << "Win QPC frequency of " << ccf.QuadPart
|
||||
<< " counts/s is below the required 1 us accuracy. Please consider using C++11 timing (-DENABLE_STDCXX_SYNC=ON) instead.");
|
||||
frequency = 1; // set back to 1 to avoid division by zero.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can't throw an exception, it won't be handled.
|
||||
LOGC(inlog.Error, log << "IPE: QueryPerformanceFrequency failed with " << GetLastError());
|
||||
}
|
||||
|
||||
#elif SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_MACH_ABSTIME
|
||||
mach_timebase_info_data_t info;
|
||||
mach_timebase_info(&info);
|
||||
frequency = info.denom * int64_t(1000) / info.numer;
|
||||
|
||||
#elif SRT_SYNC_CLOCK >= SRT_SYNC_CLOCK_AMD64_RDTSC && SRT_SYNC_CLOCK <= SRT_SYNC_CLOCK_IA64_ITC
|
||||
// SRT_SYNC_CLOCK_AMD64_RDTSC or SRT_SYNC_CLOCK_IA32_RDTSC or SRT_SYNC_CLOCK_IA64_ITC
|
||||
uint64_t t1, t2;
|
||||
|
||||
rdtsc(t1);
|
||||
timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 100000000;
|
||||
nanosleep(&ts, NULL);
|
||||
rdtsc(t2);
|
||||
|
||||
// CPU clocks per microsecond
|
||||
frequency = int64_t(t2 - t1) / 100000;
|
||||
#endif
|
||||
|
||||
return frequency;
|
||||
}
|
||||
|
||||
static int count_subsecond_precision(int64_t ticks_per_us)
|
||||
{
|
||||
int signs = 6; // starting from 1 us
|
||||
while (ticks_per_us /= 10) ++signs;
|
||||
return signs;
|
||||
}
|
||||
|
||||
const int64_t s_clock_ticks_per_us = get_cpu_frequency();
|
||||
|
||||
const int s_clock_subsecond_precision = count_subsecond_precision(s_clock_ticks_per_us);
|
||||
|
||||
int clockSubsecondPrecision() { return s_clock_subsecond_precision; }
|
||||
|
||||
} // namespace sync
|
||||
} // namespace srt
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Sync utilities section
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static timespec us_to_timespec(const uint64_t time_us)
|
||||
{
|
||||
timespec timeout;
|
||||
timeout.tv_sec = time_us / 1000000;
|
||||
timeout.tv_nsec = (time_us % 1000000) * 1000;
|
||||
return timeout;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TimePoint section
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <>
|
||||
srt::sync::Duration<srt::sync::steady_clock> srt::sync::TimePoint<srt::sync::steady_clock>::time_since_epoch() const
|
||||
{
|
||||
return srt::sync::Duration<srt::sync::steady_clock>(m_timestamp);
|
||||
}
|
||||
|
||||
srt::sync::TimePoint<srt::sync::steady_clock> srt::sync::steady_clock::now()
|
||||
{
|
||||
uint64_t x = 0;
|
||||
rdtsc(x);
|
||||
return TimePoint<steady_clock>(x);
|
||||
}
|
||||
|
||||
int64_t srt::sync::count_microseconds(const steady_clock::duration& t)
|
||||
{
|
||||
return t.count() / s_clock_ticks_per_us;
|
||||
}
|
||||
|
||||
int64_t srt::sync::count_milliseconds(const steady_clock::duration& t)
|
||||
{
|
||||
return t.count() / s_clock_ticks_per_us / 1000;
|
||||
}
|
||||
|
||||
int64_t srt::sync::count_seconds(const steady_clock::duration& t)
|
||||
{
|
||||
return t.count() / s_clock_ticks_per_us / 1000000;
|
||||
}
|
||||
|
||||
srt::sync::steady_clock::duration srt::sync::microseconds_from(int64_t t_us)
|
||||
{
|
||||
return steady_clock::duration(t_us * s_clock_ticks_per_us);
|
||||
}
|
||||
|
||||
srt::sync::steady_clock::duration srt::sync::milliseconds_from(int64_t t_ms)
|
||||
{
|
||||
return steady_clock::duration((1000 * t_ms) * s_clock_ticks_per_us);
|
||||
}
|
||||
|
||||
srt::sync::steady_clock::duration srt::sync::seconds_from(int64_t t_s)
|
||||
{
|
||||
return steady_clock::duration((1000000 * t_s) * s_clock_ticks_per_us);
|
||||
}
|
||||
|
||||
srt::sync::Mutex::Mutex()
|
||||
{
|
||||
const int err = pthread_mutex_init(&m_mutex, 0);
|
||||
if (err)
|
||||
{
|
||||
throw CUDTException(MJ_SYSTEMRES, MN_MEMORY, 0);
|
||||
}
|
||||
}
|
||||
|
||||
srt::sync::Mutex::~Mutex()
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
}
|
||||
|
||||
int srt::sync::Mutex::lock()
|
||||
{
|
||||
return pthread_mutex_lock(&m_mutex);
|
||||
}
|
||||
|
||||
int srt::sync::Mutex::unlock()
|
||||
{
|
||||
return pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
bool srt::sync::Mutex::try_lock()
|
||||
{
|
||||
return (pthread_mutex_trylock(&m_mutex) == 0);
|
||||
}
|
||||
|
||||
srt::sync::ScopedLock::ScopedLock(Mutex& m)
|
||||
: m_mutex(m)
|
||||
{
|
||||
m_mutex.lock();
|
||||
}
|
||||
|
||||
srt::sync::ScopedLock::~ScopedLock()
|
||||
{
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
srt::sync::UniqueLock::UniqueLock(Mutex& m)
|
||||
: m_Mutex(m)
|
||||
{
|
||||
m_iLocked = m_Mutex.lock();
|
||||
}
|
||||
|
||||
srt::sync::UniqueLock::~UniqueLock()
|
||||
{
|
||||
if (m_iLocked == 0)
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void srt::sync::UniqueLock::lock()
|
||||
{
|
||||
if (m_iLocked != -1)
|
||||
throw CThreadException(MJ_SYSTEMRES, MN_THREAD, 0);
|
||||
|
||||
m_iLocked = m_Mutex.lock();
|
||||
}
|
||||
|
||||
void srt::sync::UniqueLock::unlock()
|
||||
{
|
||||
if (m_iLocked != 0)
|
||||
throw CThreadException(MJ_SYSTEMRES, MN_THREAD, 0);
|
||||
|
||||
m_Mutex.unlock();
|
||||
m_iLocked = -1;
|
||||
}
|
||||
|
||||
srt::sync::Mutex* srt::sync::UniqueLock::mutex()
|
||||
{
|
||||
return &m_Mutex;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Condition section (based on pthreads)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace srt
|
||||
{
|
||||
namespace sync
|
||||
{
|
||||
|
||||
Condition::Condition()
|
||||
#ifdef _WIN32
|
||||
: m_cv(PTHREAD_COND_INITIALIZER)
|
||||
#endif
|
||||
{}
|
||||
|
||||
Condition::~Condition() {}
|
||||
|
||||
void Condition::init()
|
||||
{
|
||||
pthread_condattr_t* attr = NULL;
|
||||
#if SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_GETTIME_MONOTONIC
|
||||
pthread_condattr_t CondAttribs;
|
||||
pthread_condattr_init(&CondAttribs);
|
||||
pthread_condattr_setclock(&CondAttribs, CLOCK_MONOTONIC);
|
||||
attr = &CondAttribs;
|
||||
#endif
|
||||
const int res = pthread_cond_init(&m_cv, attr);
|
||||
if (res != 0)
|
||||
throw std::runtime_error("pthread_cond_init monotonic failed");
|
||||
}
|
||||
|
||||
void Condition::destroy()
|
||||
{
|
||||
pthread_cond_destroy(&m_cv);
|
||||
}
|
||||
|
||||
void Condition::wait(UniqueLock& lock)
|
||||
{
|
||||
pthread_cond_wait(&m_cv, &lock.mutex()->ref());
|
||||
}
|
||||
|
||||
bool Condition::wait_for(UniqueLock& lock, const steady_clock::duration& rel_time)
|
||||
{
|
||||
timespec timeout;
|
||||
#if SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_GETTIME_MONOTONIC
|
||||
clock_gettime(CLOCK_MONOTONIC, &timeout);
|
||||
const uint64_t now_us = timeout.tv_sec * uint64_t(1000000) + (timeout.tv_nsec / 1000);
|
||||
#else
|
||||
timeval now;
|
||||
gettimeofday(&now, 0);
|
||||
const uint64_t now_us = now.tv_sec * uint64_t(1000000) + now.tv_usec;
|
||||
#endif
|
||||
timeout = us_to_timespec(now_us + count_microseconds(rel_time));
|
||||
return pthread_cond_timedwait(&m_cv, &lock.mutex()->ref(), &timeout) != ETIMEDOUT;
|
||||
}
|
||||
|
||||
bool Condition::wait_until(UniqueLock& lock, const steady_clock::time_point& timeout_time)
|
||||
{
|
||||
// This will work regardless as to which clock is in use. The time
|
||||
// should be specified as steady_clock::time_point, so there's no
|
||||
// question of the timer base.
|
||||
const steady_clock::time_point now = steady_clock::now();
|
||||
if (now >= timeout_time)
|
||||
return false; // timeout
|
||||
|
||||
// wait_for() is used because it will be converted to pthread-frienly timeout_time inside.
|
||||
return wait_for(lock, timeout_time - now);
|
||||
}
|
||||
|
||||
void Condition::notify_one()
|
||||
{
|
||||
pthread_cond_signal(&m_cv);
|
||||
}
|
||||
|
||||
void Condition::notify_all()
|
||||
{
|
||||
pthread_cond_broadcast(&m_cv);
|
||||
}
|
||||
|
||||
}; // namespace sync
|
||||
}; // namespace srt
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CThread class
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
srt::sync::CThread::CThread()
|
||||
{
|
||||
m_thread = pthread_t();
|
||||
}
|
||||
|
||||
srt::sync::CThread::CThread(void *(*start_routine) (void *), void *arg)
|
||||
{
|
||||
create(start_routine, arg);
|
||||
}
|
||||
|
||||
#if HAVE_FULL_CXX11
|
||||
srt::sync::CThread& srt::sync::CThread::operator=(CThread&& other)
|
||||
#else
|
||||
srt::sync::CThread& srt::sync::CThread::operator=(CThread& other)
|
||||
#endif
|
||||
{
|
||||
if (joinable())
|
||||
{
|
||||
// If the thread has already terminated, then
|
||||
// pthread_join() returns immediately.
|
||||
// But we have to check it has terminated before replacing it.
|
||||
LOGC(inlog.Error, log << "IPE: Assigning to a thread that is not terminated!");
|
||||
|
||||
#ifndef DEBUG
|
||||
#ifndef __ANDROID__
|
||||
// In case of production build the hanging thread should be terminated
|
||||
// to avoid hang ups and align with C++11 implementation.
|
||||
// There is no pthread_cancel on Android. See #1476. This error should not normally
|
||||
// happen, but if it happen, then detaching the thread.
|
||||
pthread_cancel(m_thread);
|
||||
#endif // __ANDROID__
|
||||
#else
|
||||
join();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Move thread handler from other
|
||||
m_thread = other.m_thread;
|
||||
other.m_thread = pthread_t();
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if !HAVE_FULL_CXX11
|
||||
void srt::sync::CThread::create_thread(void *(*start_routine) (void *), void *arg)
|
||||
{
|
||||
SRT_ASSERT(!joinable());
|
||||
create(start_routine, arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool srt::sync::CThread::joinable() const
|
||||
{
|
||||
return !pthread_equal(m_thread, pthread_t());
|
||||
}
|
||||
|
||||
void srt::sync::CThread::join()
|
||||
{
|
||||
void *retval;
|
||||
const int ret SRT_ATR_UNUSED = pthread_join(m_thread, &retval);
|
||||
if (ret != 0)
|
||||
{
|
||||
LOGC(inlog.Error, log << "pthread_join failed with " << ret);
|
||||
}
|
||||
#ifdef HEAVY_LOGGING
|
||||
else
|
||||
{
|
||||
HLOGC(inlog.Debug, log << "pthread_join SUCCEEDED");
|
||||
}
|
||||
#endif
|
||||
// After joining, joinable should be false
|
||||
m_thread = pthread_t();
|
||||
return;
|
||||
}
|
||||
|
||||
void srt::sync::CThread::create(void *(*start_routine) (void *), void *arg)
|
||||
{
|
||||
const int st = pthread_create(&m_thread, NULL, start_routine, arg);
|
||||
if (st != 0)
|
||||
{
|
||||
LOGC(inlog.Error, log << "pthread_create failed with " << st);
|
||||
throw CThreadException(MJ_SYSTEMRES, MN_THREAD, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CThreadError class - thread local storage error wrapper
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
namespace srt {
|
||||
namespace sync {
|
||||
|
||||
class CThreadError
|
||||
{
|
||||
public:
|
||||
CThreadError()
|
||||
{
|
||||
pthread_key_create(&m_ThreadSpecKey, ThreadSpecKeyDestroy);
|
||||
|
||||
// This is a global object and as such it should be called in the
|
||||
// main application thread or at worst in the thread that has first
|
||||
// run `srt_startup()` function and so requested the SRT library to
|
||||
// be dynamically linked. Most probably in this very thread the API
|
||||
// errors will be reported, so preallocate the ThreadLocalSpecific
|
||||
// object for this error description.
|
||||
|
||||
// This allows std::bac_alloc to crash the program during
|
||||
// the initialization of the SRT library (likely it would be
|
||||
// during the DL constructor, still way before any chance of
|
||||
// doing any operations here). This will prevent SRT from running
|
||||
// into trouble while trying to operate.
|
||||
CUDTException* ne = new CUDTException();
|
||||
pthread_setspecific(m_ThreadSpecKey, ne);
|
||||
}
|
||||
|
||||
~CThreadError()
|
||||
{
|
||||
// Likely all objects should be deleted in all
|
||||
// threads that have exited, but std::this_thread didn't exit
|
||||
// yet :).
|
||||
ThreadSpecKeyDestroy(pthread_getspecific(m_ThreadSpecKey));
|
||||
pthread_key_delete(m_ThreadSpecKey);
|
||||
}
|
||||
|
||||
void set(const CUDTException& e)
|
||||
{
|
||||
CUDTException* cur = get();
|
||||
// If this returns NULL, it means that there was an unexpected
|
||||
// memory allocation error. Simply ignore this request if so
|
||||
// happened, and then when trying to get the error description
|
||||
// the application will always get the memory allocation error.
|
||||
|
||||
// There's no point in doing anything else here; lack of memory
|
||||
// must be prepared for prematurely, and that was already done.
|
||||
if (!cur)
|
||||
return;
|
||||
|
||||
*cur = e;
|
||||
}
|
||||
|
||||
/*[[nullable]]*/ CUDTException* get()
|
||||
{
|
||||
if (!pthread_getspecific(m_ThreadSpecKey))
|
||||
{
|
||||
// This time if this can't be done due to memory allocation
|
||||
// problems, just allow this value to be NULL, which during
|
||||
// getting the error description will redirect to a memory
|
||||
// allocation error.
|
||||
|
||||
// It would be nice to somehow ensure that this object is
|
||||
// created in every thread of the application using SRT, but
|
||||
// POSIX thread API doesn't contain any possibility to have
|
||||
// a creation callback that would apply to every thread in
|
||||
// the application (as it is for C++11 thread_local storage).
|
||||
CUDTException* ne = new(std::nothrow) CUDTException();
|
||||
pthread_setspecific(m_ThreadSpecKey, ne);
|
||||
return ne;
|
||||
}
|
||||
return (CUDTException*)pthread_getspecific(m_ThreadSpecKey);
|
||||
}
|
||||
|
||||
static void ThreadSpecKeyDestroy(void* e)
|
||||
{
|
||||
delete (CUDTException*)e;
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_key_t m_ThreadSpecKey;
|
||||
};
|
||||
|
||||
// Threal local error will be used by CUDTUnited
|
||||
// that has a static scope
|
||||
|
||||
// This static makes this object file-private access so that
|
||||
// the access is granted only for the accessor functions.
|
||||
static CThreadError s_thErr;
|
||||
|
||||
void SetThreadLocalError(const CUDTException& e)
|
||||
{
|
||||
s_thErr.set(e);
|
||||
}
|
||||
|
||||
CUDTException& GetThreadLocalError()
|
||||
{
|
||||
// In POSIX version we take into account the possibility
|
||||
// of having an allocation error here. Therefore we need to
|
||||
// allow thie value to return NULL and have some fallback
|
||||
// for that case. The dynamic memory allocation failure should
|
||||
// be the only case as to why it is unable to get the pointer
|
||||
// to the error description.
|
||||
static CUDTException resident_alloc_error (MJ_SYSTEMRES, MN_MEMORY);
|
||||
CUDTException* curx = s_thErr.get();
|
||||
if (!curx)
|
||||
return resident_alloc_error;
|
||||
return *curx;
|
||||
}
|
||||
|
||||
} // namespace sync
|
||||
} // namespace srt
|
||||
|
233
trunk/3rdparty/srt-1-fit/srtcore/threadname.h
vendored
233
trunk/3rdparty/srt-1-fit/srtcore/threadname.h
vendored
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -13,75 +13,212 @@ written by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC__THREADNAME_H
|
||||
#define INC__THREADNAME_H
|
||||
#ifndef INC_SRT_THREADNAME_H
|
||||
#define INC_SRT_THREADNAME_H
|
||||
|
||||
#ifdef __linux__
|
||||
// NOTE:
|
||||
// HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H
|
||||
// HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H
|
||||
// HAVE_PTHREAD_GETNAME_NP
|
||||
// HAVE_PTHREAD_GETNAME_NP
|
||||
// Are detected and set in ../CMakeLists.txt.
|
||||
// OS Availability of pthread_getname_np(..) and pthread_setname_np(..)::
|
||||
// MacOS(10.6)
|
||||
// iOS(3.2)
|
||||
// AIX(7.1)
|
||||
// FreeBSD(version?), OpenBSD(Version?)
|
||||
// Linux-GLIBC(GLIBC-2.12).
|
||||
// Linux-MUSL(MUSL-1.1.20 Partial Implementation. See below).
|
||||
// MINGW-W64(4.0.6)
|
||||
|
||||
#include <sys/prctl.h>
|
||||
#if defined(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) \
|
||||
|| defined(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H)
|
||||
#include <pthread_np.h>
|
||||
#if defined(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) \
|
||||
&& !defined(HAVE_PTHREAD_GETNAME_NP)
|
||||
#define HAVE_PTHREAD_GETNAME_NP 1
|
||||
#endif
|
||||
#if defined(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) \
|
||||
&& !defined(HAVE_PTHREAD_SETNAME_NP)
|
||||
#define HAVE_PTHREAD_SETNAME_NP 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (defined(HAVE_PTHREAD_GETNAME_NP) && defined(HAVE_PTHREAD_GETNAME_NP)) \
|
||||
|| defined(__linux__)
|
||||
// NOTE:
|
||||
// Linux pthread_getname_np() and pthread_setname_np() became available
|
||||
// in GLIBC-2.12 and later.
|
||||
// Some Linux runtimes do not have pthread_getname_np(), but have
|
||||
// pthread_setname_np(), for instance MUSL at least as of v1.1.20.
|
||||
// So using the prctl() for Linux is more portable.
|
||||
#if defined(__linux__)
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "common.h"
|
||||
#include "sync.h"
|
||||
|
||||
namespace srt {
|
||||
|
||||
class ThreadName
|
||||
{
|
||||
char old_name[128];
|
||||
char new_name[128];
|
||||
bool good;
|
||||
|
||||
public:
|
||||
static const size_t BUFSIZE = 128;
|
||||
#if (defined(HAVE_PTHREAD_GETNAME_NP) && defined(HAVE_PTHREAD_GETNAME_NP)) \
|
||||
|| defined(__linux__)
|
||||
|
||||
static bool get(char* namebuf)
|
||||
class ThreadNameImpl
|
||||
{
|
||||
return prctl(PR_GET_NAME, (unsigned long)namebuf, 0, 0) != -1;
|
||||
}
|
||||
public:
|
||||
static const size_t BUFSIZE = 64;
|
||||
static const bool DUMMY_IMPL = false;
|
||||
|
||||
static bool set(const char* name)
|
||||
{
|
||||
return prctl(PR_SET_NAME, (unsigned long)name, 0, 0) != -1;
|
||||
}
|
||||
|
||||
|
||||
ThreadName(const char* name)
|
||||
{
|
||||
if ( (good = get(old_name)) )
|
||||
static bool get(char* namebuf)
|
||||
{
|
||||
snprintf(new_name, 127, "%s", name);
|
||||
new_name[127] = 0;
|
||||
prctl(PR_SET_NAME, (unsigned long)new_name, 0, 0);
|
||||
#if defined(__linux__)
|
||||
// since Linux 2.6.11. The buffer should allow space for up to 16
|
||||
// bytes; the returned string will be null-terminated.
|
||||
return prctl(PR_GET_NAME, (unsigned long)namebuf, 0, 0) != -1;
|
||||
#elif defined(HAVE_PTHREAD_GETNAME_NP)
|
||||
return pthread_getname_np(pthread_self(), namebuf, BUFSIZE) == 0;
|
||||
#else
|
||||
#error "unsupported platform"
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
~ThreadName()
|
||||
{
|
||||
if ( good )
|
||||
prctl(PR_SET_NAME, (unsigned long)old_name, 0, 0);
|
||||
}
|
||||
};
|
||||
static bool set(const char* name)
|
||||
{
|
||||
SRT_ASSERT(name != NULL);
|
||||
#if defined(__linux__)
|
||||
// The name can be up to 16 bytes long, including the terminating
|
||||
// null byte. (If the length of the string, including the terminating
|
||||
// null byte, exceeds 16 bytes, the string is silently truncated.)
|
||||
return prctl(PR_SET_NAME, (unsigned long)name, 0, 0) != -1;
|
||||
#elif defined(HAVE_PTHREAD_SETNAME_NP)
|
||||
#if defined(__APPLE__)
|
||||
return pthread_setname_np(name) == 0;
|
||||
#else
|
||||
return pthread_setname_np(pthread_self(), name) == 0;
|
||||
#endif
|
||||
#else
|
||||
#error "unsupported platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
explicit ThreadNameImpl(const std::string& name)
|
||||
: reset(false)
|
||||
{
|
||||
tid = pthread_self();
|
||||
|
||||
if (!get(old_name))
|
||||
return;
|
||||
|
||||
reset = set(name.c_str());
|
||||
if (reset)
|
||||
return;
|
||||
|
||||
// Try with a shorter name. 15 is the upper limit supported by Linux,
|
||||
// other platforms should support a larger value. So 15 should works
|
||||
// on all platforms.
|
||||
const size_t max_len = 15;
|
||||
if (name.size() > max_len)
|
||||
reset = set(name.substr(0, max_len).c_str());
|
||||
}
|
||||
|
||||
~ThreadNameImpl()
|
||||
{
|
||||
if (!reset)
|
||||
return;
|
||||
|
||||
// ensure it's called on the right thread
|
||||
if (tid == pthread_self())
|
||||
set(old_name);
|
||||
}
|
||||
|
||||
private:
|
||||
ThreadNameImpl(ThreadNameImpl& other);
|
||||
ThreadNameImpl& operator=(const ThreadNameImpl& other);
|
||||
|
||||
private:
|
||||
bool reset;
|
||||
pthread_t tid;
|
||||
char old_name[BUFSIZE];
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
// Fake class, which does nothing. You can also take a look how
|
||||
// this works in other systems that are not supported here and add
|
||||
// the support. This is a fallback for systems that do not support
|
||||
// thread names.
|
||||
class ThreadNameImpl
|
||||
{
|
||||
public:
|
||||
static const bool DUMMY_IMPL = true;
|
||||
static const size_t BUFSIZE = 64;
|
||||
|
||||
static bool get(char* output)
|
||||
{
|
||||
// The default implementation will simply try to get the thread ID
|
||||
std::ostringstream bs;
|
||||
bs << "T" << sync::this_thread::get_id();
|
||||
size_t s = bs.str().copy(output, BUFSIZE - 1);
|
||||
output[s] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set(const char*) { return false; }
|
||||
|
||||
ThreadNameImpl(const std::string&) {}
|
||||
|
||||
~ThreadNameImpl() // just to make it "non-trivially-destructible" for compatibility with normal version
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // platform dependent impl
|
||||
|
||||
// Why delegate to impl:
|
||||
// 1. to make sure implementation on different platforms have the same interface.
|
||||
// 2. it's simple to add some wrappers like get(const std::string &).
|
||||
ThreadNameImpl impl;
|
||||
|
||||
class ThreadName
|
||||
{
|
||||
public:
|
||||
static const bool DUMMY_IMPL = ThreadNameImpl::DUMMY_IMPL;
|
||||
static const size_t BUFSIZE = ThreadNameImpl::BUFSIZE;
|
||||
|
||||
static bool get(char*) { return false; }
|
||||
static bool set(const char*) { return false; }
|
||||
/// @brief Print thread ID to the provided buffer.
|
||||
/// The size of the destination buffer is assumed to be at least ThreadName::BUFSIZE.
|
||||
/// @param [out] output destination buffer to get thread name
|
||||
/// @return true on success, false on failure
|
||||
static bool get(char* output) {
|
||||
return ThreadNameImpl::get(output);
|
||||
}
|
||||
|
||||
ThreadName(const char*)
|
||||
{
|
||||
}
|
||||
|
||||
~ThreadName() // just to make it "non-trivially-destructible" for compatibility with normal version
|
||||
static bool get(std::string& name)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
bool ret = get(buf);
|
||||
if (ret)
|
||||
name = buf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool set(const std::string& name) { return ThreadNameImpl::set(name.c_str()); }
|
||||
|
||||
explicit ThreadName(const std::string& name)
|
||||
: impl(name)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
ThreadName(const ThreadName&);
|
||||
ThreadName(const char*);
|
||||
ThreadName& operator=(const ThreadName& other);
|
||||
};
|
||||
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
267
trunk/3rdparty/srt-1-fit/srtcore/tsbpd_time.cpp
vendored
Normal file
267
trunk/3rdparty/srt-1-fit/srtcore/tsbpd_time.cpp
vendored
Normal file
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2021 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
#include "tsbpd_time.h"
|
||||
|
||||
#include "logging.h"
|
||||
#include "logger_defs.h"
|
||||
#include "packet.h"
|
||||
|
||||
using namespace srt_logging;
|
||||
using namespace srt::sync;
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
#if SRT_DEBUG_TRACE_DRIFT
|
||||
class drift_logger
|
||||
{
|
||||
typedef srt::sync::steady_clock steady_clock;
|
||||
|
||||
public:
|
||||
drift_logger() {}
|
||||
|
||||
~drift_logger()
|
||||
{
|
||||
ScopedLock lck(m_mtx);
|
||||
m_fout.close();
|
||||
}
|
||||
|
||||
void trace(unsigned ackack_timestamp,
|
||||
int rtt_us,
|
||||
int64_t drift_sample,
|
||||
int64_t drift,
|
||||
int64_t overdrift,
|
||||
const srt::sync::steady_clock::time_point& pkt_base,
|
||||
const srt::sync::steady_clock::time_point& tsbpd_base)
|
||||
{
|
||||
using namespace srt::sync;
|
||||
ScopedLock lck(m_mtx);
|
||||
create_file();
|
||||
|
||||
// std::string str_tnow = srt::sync::FormatTime(steady_clock::now());
|
||||
// str_tnow.resize(str_tnow.size() - 7); // remove trailing ' [STDY]' part
|
||||
|
||||
std::string str_tbase = srt::sync::FormatTime(tsbpd_base);
|
||||
str_tbase.resize(str_tbase.size() - 7); // remove trailing ' [STDY]' part
|
||||
|
||||
std::string str_pkt_base = srt::sync::FormatTime(pkt_base);
|
||||
str_pkt_base.resize(str_pkt_base.size() - 7); // remove trailing ' [STDY]' part
|
||||
|
||||
// m_fout << str_tnow << ",";
|
||||
m_fout << count_microseconds(steady_clock::now() - m_start_time) << ",";
|
||||
m_fout << ackack_timestamp << ",";
|
||||
m_fout << rtt_us << ",";
|
||||
m_fout << drift_sample << ",";
|
||||
m_fout << drift << ",";
|
||||
m_fout << overdrift << ",";
|
||||
m_fout << str_pkt_base << ",";
|
||||
m_fout << str_tbase << "\n";
|
||||
m_fout.flush();
|
||||
}
|
||||
|
||||
private:
|
||||
void print_header()
|
||||
{
|
||||
m_fout << "usElapsedStd,usAckAckTimestampStd,";
|
||||
m_fout << "usRTTStd,usDriftSampleStd,usDriftStd,usOverdriftStd,tsPktBase,TSBPDBase\n";
|
||||
}
|
||||
|
||||
void create_file()
|
||||
{
|
||||
if (m_fout.is_open())
|
||||
return;
|
||||
|
||||
m_start_time = srt::sync::steady_clock::now();
|
||||
std::string str_tnow = srt::sync::FormatTimeSys(m_start_time);
|
||||
str_tnow.resize(str_tnow.size() - 7); // remove trailing ' [SYST]' part
|
||||
while (str_tnow.find(':') != std::string::npos)
|
||||
{
|
||||
str_tnow.replace(str_tnow.find(':'), 1, 1, '_');
|
||||
}
|
||||
const std::string fname = "drift_trace_" + str_tnow + ".csv";
|
||||
m_fout.open(fname, std::ofstream::out);
|
||||
if (!m_fout)
|
||||
std::cerr << "IPE: Failed to open " << fname << "!!!\n";
|
||||
|
||||
print_header();
|
||||
}
|
||||
|
||||
private:
|
||||
srt::sync::Mutex m_mtx;
|
||||
std::ofstream m_fout;
|
||||
srt::sync::steady_clock::time_point m_start_time;
|
||||
};
|
||||
|
||||
drift_logger g_drift_logger;
|
||||
|
||||
#endif // SRT_DEBUG_TRACE_DRIFT
|
||||
|
||||
bool CTsbpdTime::addDriftSample(uint32_t usPktTimestamp, const time_point& tsPktArrival, int usRTTSample)
|
||||
{
|
||||
if (!m_bTsbPdMode)
|
||||
return false;
|
||||
|
||||
ScopedLock lck(m_mtxRW);
|
||||
|
||||
// Remember the first RTT sample measured. Ideally we need RTT0 - the one from the handshaking phase,
|
||||
// because TSBPD base is initialized there. But HS-based RTT is not yet implemented.
|
||||
// Take the first one assuming it is close to RTT0.
|
||||
if (m_iFirstRTT == -1)
|
||||
{
|
||||
m_iFirstRTT = usRTTSample;
|
||||
}
|
||||
|
||||
// A change in network delay has to be taken into account. The only way to get some estimation of it
|
||||
// is to estimate RTT change and assume that the change of the one way network delay is
|
||||
// approximated by the half of the RTT change.
|
||||
const duration tdRTTDelta = usRTTSample >= 0 ? microseconds_from((usRTTSample - m_iFirstRTT) / 2) : duration(0);
|
||||
const time_point tsPktBaseTime = getPktTsbPdBaseTime(usPktTimestamp);
|
||||
const steady_clock::duration tdDrift = tsPktArrival - tsPktBaseTime - tdRTTDelta;
|
||||
|
||||
const bool updated = m_DriftTracer.update(count_microseconds(tdDrift));
|
||||
|
||||
if (updated)
|
||||
{
|
||||
IF_HEAVY_LOGGING(const steady_clock::time_point oldbase = m_tsTsbPdTimeBase);
|
||||
steady_clock::duration overdrift = microseconds_from(m_DriftTracer.overdrift());
|
||||
m_tsTsbPdTimeBase += overdrift;
|
||||
|
||||
HLOGC(brlog.Debug,
|
||||
log << "DRIFT=" << FormatDuration(tdDrift) << " AVG=" << (m_DriftTracer.drift() / 1000.0)
|
||||
<< "ms, TB: " << FormatTime(oldbase) << " EXCESS: " << FormatDuration(overdrift)
|
||||
<< " UPDATED TO: " << FormatTime(m_tsTsbPdTimeBase));
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(brlog.Debug,
|
||||
log << "DRIFT=" << FormatDuration(tdDrift) << " TB REMAINS: " << FormatTime(m_tsTsbPdTimeBase));
|
||||
}
|
||||
|
||||
#if SRT_DEBUG_TRACE_DRIFT
|
||||
g_drift_logger.trace(usPktTimestamp,
|
||||
usRTTSample,
|
||||
count_microseconds(tdDrift),
|
||||
m_DriftTracer.drift(),
|
||||
m_DriftTracer.overdrift(),
|
||||
tsPktBaseTime,
|
||||
m_tsTsbPdTimeBase);
|
||||
#endif
|
||||
return updated;
|
||||
}
|
||||
|
||||
void CTsbpdTime::setTsbPdMode(const steady_clock::time_point& timebase, bool wrap, duration delay)
|
||||
{
|
||||
m_bTsbPdMode = true;
|
||||
m_bTsbPdWrapCheck = wrap;
|
||||
|
||||
// Timebase passed here comes is calculated as:
|
||||
// Tnow - hspkt.m_iTimeStamp
|
||||
// where hspkt is the packet with SRT_CMD_HSREQ message.
|
||||
//
|
||||
// This function is called in the HSREQ reception handler only.
|
||||
m_tsTsbPdTimeBase = timebase;
|
||||
m_tdTsbPdDelay = delay;
|
||||
}
|
||||
|
||||
void CTsbpdTime::applyGroupTime(const steady_clock::time_point& timebase,
|
||||
bool wrp,
|
||||
uint32_t delay,
|
||||
const steady_clock::duration& udrift)
|
||||
{
|
||||
// Same as setTsbPdMode, but predicted to be used for group members.
|
||||
// This synchronizes the time from the INTERNAL TIMEBASE of an existing
|
||||
// socket's internal timebase. This is required because the initial time
|
||||
// base stays always the same, whereas the internal timebase undergoes
|
||||
// adjustment as the 32-bit timestamps in the sockets wrap. The socket
|
||||
// newly added to the group must get EXACTLY the same internal timebase
|
||||
// or otherwise the TsbPd time calculation will ship different results
|
||||
// on different member sockets.
|
||||
|
||||
m_bTsbPdMode = true;
|
||||
|
||||
m_tsTsbPdTimeBase = timebase;
|
||||
m_bTsbPdWrapCheck = wrp;
|
||||
m_tdTsbPdDelay = microseconds_from(delay);
|
||||
m_DriftTracer.forceDrift(count_microseconds(udrift));
|
||||
}
|
||||
|
||||
void CTsbpdTime::applyGroupDrift(const steady_clock::time_point& timebase,
|
||||
bool wrp,
|
||||
const steady_clock::duration& udrift)
|
||||
{
|
||||
// This is only when a drift was updated on one of the group members.
|
||||
HLOGC(brlog.Debug,
|
||||
log << "rcv-buffer: group synch uDRIFT: " << m_DriftTracer.drift() << " -> " << FormatDuration(udrift)
|
||||
<< " TB: " << FormatTime(m_tsTsbPdTimeBase) << " -> " << FormatTime(timebase));
|
||||
|
||||
m_tsTsbPdTimeBase = timebase;
|
||||
m_bTsbPdWrapCheck = wrp;
|
||||
|
||||
m_DriftTracer.forceDrift(count_microseconds(udrift));
|
||||
}
|
||||
|
||||
CTsbpdTime::time_point CTsbpdTime::getTsbPdTimeBase(uint32_t timestamp_us) const
|
||||
{
|
||||
// A data packet within [TSBPD_WRAP_PERIOD; 2 * TSBPD_WRAP_PERIOD] would end TSBPD wrap-aware state.
|
||||
// Some incoming control packets may not update the TSBPD base (calling updateTsbPdTimeBase(..)),
|
||||
// but may come before a data packet with a timestamp in this range. Therefore the whole range should be tracked.
|
||||
const int64_t carryover_us =
|
||||
(m_bTsbPdWrapCheck && timestamp_us <= 2 * TSBPD_WRAP_PERIOD) ? int64_t(CPacket::MAX_TIMESTAMP) + 1 : 0;
|
||||
|
||||
return (m_tsTsbPdTimeBase + microseconds_from(carryover_us));
|
||||
}
|
||||
|
||||
CTsbpdTime::time_point CTsbpdTime::getPktTsbPdTime(uint32_t usPktTimestamp) const
|
||||
{
|
||||
return getPktTsbPdBaseTime(usPktTimestamp) + m_tdTsbPdDelay + microseconds_from(m_DriftTracer.drift());
|
||||
}
|
||||
|
||||
CTsbpdTime::time_point CTsbpdTime::getPktTsbPdBaseTime(uint32_t usPktTimestamp) const
|
||||
{
|
||||
return getTsbPdTimeBase(usPktTimestamp) + microseconds_from(usPktTimestamp);
|
||||
}
|
||||
|
||||
void CTsbpdTime::updateTsbPdTimeBase(uint32_t usPktTimestamp)
|
||||
{
|
||||
if (m_bTsbPdWrapCheck)
|
||||
{
|
||||
// Wrap check period.
|
||||
if ((usPktTimestamp >= TSBPD_WRAP_PERIOD) && (usPktTimestamp <= (TSBPD_WRAP_PERIOD * 2)))
|
||||
{
|
||||
/* Exiting wrap check period (if for packet delivery head) */
|
||||
m_bTsbPdWrapCheck = false;
|
||||
m_tsTsbPdTimeBase += microseconds_from(int64_t(CPacket::MAX_TIMESTAMP) + 1);
|
||||
LOGC(tslog.Debug,
|
||||
log << "tsbpd wrap period ends with ts=" << usPktTimestamp << " - NEW TIME BASE: "
|
||||
<< FormatTime(m_tsTsbPdTimeBase) << " drift: " << m_DriftTracer.drift() << "us");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if timestamp is within the TSBPD_WRAP_PERIOD before reaching the MAX_TIMESTAMP.
|
||||
if (usPktTimestamp > (CPacket::MAX_TIMESTAMP - TSBPD_WRAP_PERIOD))
|
||||
{
|
||||
// Approching wrap around point, start wrap check period (if for packet delivery head)
|
||||
m_bTsbPdWrapCheck = true;
|
||||
LOGC(tslog.Debug,
|
||||
log << "tsbpd wrap period begins with ts=" << usPktTimestamp
|
||||
<< " TIME BASE: " << FormatTime(m_tsTsbPdTimeBase) << " drift: " << m_DriftTracer.drift() << "us.");
|
||||
}
|
||||
}
|
||||
|
||||
void CTsbpdTime::getInternalTimeBase(time_point& w_tb, bool& w_wrp, duration& w_udrift) const
|
||||
{
|
||||
ScopedLock lck(m_mtxRW);
|
||||
w_tb = m_tsTsbPdTimeBase;
|
||||
w_udrift = microseconds_from(m_DriftTracer.drift());
|
||||
w_wrp = m_bTsbPdWrapCheck;
|
||||
}
|
||||
|
||||
} // namespace srt
|
163
trunk/3rdparty/srt-1-fit/srtcore/tsbpd_time.h
vendored
Normal file
163
trunk/3rdparty/srt-1-fit/srtcore/tsbpd_time.h
vendored
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2021 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INC_SRT_TSBPD_TIME_H
|
||||
#define INC_SRT_TSBPD_TIME_H
|
||||
|
||||
#include "platform_sys.h"
|
||||
#include "sync.h"
|
||||
#include "utilities.h"
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
/// @brief TimeStamp-Based Packet Delivery Mode (TSBPD) time conversion logic.
|
||||
/// Used by the receiver to calculate delivery time of data packets.
|
||||
/// See SRT Internet Draft Section "Timestamp-Based Packet Delivery".
|
||||
class CTsbpdTime
|
||||
{
|
||||
typedef srt::sync::steady_clock steady_clock;
|
||||
typedef steady_clock::time_point time_point;
|
||||
typedef steady_clock::duration duration;
|
||||
typedef srt::sync::Mutex Mutex;
|
||||
|
||||
public:
|
||||
CTsbpdTime()
|
||||
: m_iFirstRTT(-1)
|
||||
, m_bTsbPdMode(false)
|
||||
, m_tdTsbPdDelay(0)
|
||||
, m_bTsbPdWrapCheck(false)
|
||||
{
|
||||
}
|
||||
|
||||
/// Set TimeStamp-Based Packet Delivery Mode (receiver).
|
||||
/// @param [in] timebase local time base (uSec) of packet time stamps including buffering delay.
|
||||
/// @param [in] wrap wrapping period.
|
||||
/// @param [in] delay negotiated TsbPD delay (buffering latency).
|
||||
void setTsbPdMode(const time_point& timebase, bool wrap, duration delay);
|
||||
|
||||
/// @brief Check if TSBPD logic is enabled.
|
||||
/// @return true if TSBPD is enabled.
|
||||
bool isEnabled() const { return m_bTsbPdMode; }
|
||||
|
||||
/// @brief Apply new state derived from other members of a socket group.
|
||||
/// @param timebase TSBPD base time.
|
||||
/// @param wrp wrap period (enabled or not).
|
||||
/// @param delay TSBPD delay.
|
||||
/// @param udrift clock drift.
|
||||
void applyGroupTime(const time_point& timebase, bool wrp, uint32_t delay, const duration& udrift);
|
||||
|
||||
/// @brief Apply new clock state (TSBPD base and drift) derived from other members of a socket group.
|
||||
/// @param timebase TSBPD base time.
|
||||
/// @param wrp state of the wrapping period (enabled or disabled).
|
||||
/// @param udrift clock drift.
|
||||
void applyGroupDrift(const time_point& timebase, bool wrp, const duration& udrift);
|
||||
|
||||
/// @brief Add new drift sample from an ACK-ACKACK pair.
|
||||
/// ACKACK packets are sent immediately (except for UDP buffering).
|
||||
/// Therefore their timestamp roughly corresponds to the time of sending
|
||||
/// and can be used to estimate clock drift.
|
||||
///
|
||||
/// @param [in] pktTimestamp Timestamp of the arrived ACKACK packet.
|
||||
/// @param [in] tsPktArrival packet arrival time.
|
||||
/// @param [in] usRTTSample RTT sample from an ACK-ACKACK pair. If no sample, pass '-1'.
|
||||
///
|
||||
/// @return true if TSBPD base time has changed, false otherwise.
|
||||
bool addDriftSample(uint32_t pktTimestamp, const time_point& tsPktArrival, int usRTTSample);
|
||||
|
||||
/// @brief Handle timestamp of data packet when 32-bit integer carryover is about to happen.
|
||||
/// When packet timestamp approaches CPacket::MAX_TIMESTAMP, the TSBPD base time should be
|
||||
/// shifted accordingly to correctly handle new packets with timestamps starting from zero.
|
||||
/// @param usPktTimestamp timestamp field value of a data packet.
|
||||
void updateTsbPdTimeBase(uint32_t usPktTimestamp);
|
||||
|
||||
/// @brief Get TSBPD base time adjusted for carryover, which occurs when
|
||||
/// a packet's timestamp exceeds the UINT32_MAX and continues from zero.
|
||||
/// @param [in] usPktTimestamp 32-bit value of packet timestamp field (microseconds).
|
||||
///
|
||||
/// @return TSBPD base time for a provided packet timestamp.
|
||||
time_point getTsbPdTimeBase(uint32_t usPktTimestamp) const;
|
||||
|
||||
/// @brief Get packet TSBPD time without buffering delay and clock drift, which is
|
||||
/// the target time for delivering the packet to an upstream application.
|
||||
/// Essentially: getTsbPdTimeBase(usPktTimestamp) + usPktTimestamp
|
||||
/// @param [in] usPktTimestamp 32-bit value of packet timestamp field (microseconds).
|
||||
///
|
||||
/// @return Packet TSBPD base time without buffering delay.
|
||||
time_point getPktTsbPdBaseTime(uint32_t usPktTimestamp) const;
|
||||
|
||||
/// @brief Get packet TSBPD time with buffering delay and clock drift, which is
|
||||
/// the target time for delivering the packet to an upstream application
|
||||
/// (including drift and carryover effects, if any).
|
||||
/// Essentially: getPktTsbPdBaseTime(usPktTimestamp) + m_tdTsbPdDelay + drift()
|
||||
/// @param [in] usPktTimestamp 32-bit value of packet timestamp field (microseconds).
|
||||
///
|
||||
/// @return Packet TSBPD time with buffering delay.
|
||||
time_point getPktTsbPdTime(uint32_t usPktTimestamp) const;
|
||||
|
||||
/// @brief Get current drift value.
|
||||
/// @return current drift value.
|
||||
int64_t drift() const { return m_DriftTracer.drift(); }
|
||||
|
||||
/// @brief Get current overdrift value.
|
||||
/// @return current overdrift value.
|
||||
int64_t overdrift() const { return m_DriftTracer.overdrift(); }
|
||||
|
||||
/// @brief Get internal state to apply to another member of a socket group.
|
||||
/// @param w_tb TsbPd base time.
|
||||
/// @param w_udrift drift value.
|
||||
/// @param w_wrp wrap check.
|
||||
void getInternalTimeBase(time_point& w_tb, bool& w_wrp, duration& w_udrift) const;
|
||||
|
||||
private:
|
||||
int m_iFirstRTT; // First measured RTT sample.
|
||||
bool m_bTsbPdMode; // Receiver buffering and TSBPD is active when true.
|
||||
duration m_tdTsbPdDelay; // Negotiated buffering delay.
|
||||
|
||||
/// @brief Local time base for TsbPd.
|
||||
/// @note m_tsTsbPdTimeBase is changed in the following cases:
|
||||
/// 1. Initialized upon SRT_CMD_HSREQ packet as the difference with the current time:
|
||||
/// = (NOW - PACKET_TIMESTAMP), at the time of HSREQ reception.
|
||||
/// 2. Shifted forward on timestamp overflow (@see CTsbpdTime::updateTsbPdTimeBase), when overflow
|
||||
/// of the timestamp field value of a data packet is detected.
|
||||
/// += CPacket::MAX_TIMESTAMP + 1
|
||||
/// 3. Clock drift (@see CTsbpdTime::addDriftSample, executed exclusively
|
||||
/// from ACKACK handler). This is updated with (positive or negative) TSBPD_DRIFT_MAX_VALUE
|
||||
/// once the value of average drift exceeds this value in either direction.
|
||||
/// += (+/-)TSBPD_DRIFT_MAX_VALUE
|
||||
///
|
||||
/// @note The TSBPD base time is expected to hold the following condition:
|
||||
/// (PACKET_TIMESTAMP + m_tsTsbPdTimeBase + drift) == NOW.
|
||||
/// Then it can be used to estimate the origin time of a data packet, and calculate its delivery time
|
||||
/// with buffering delay applied.
|
||||
time_point m_tsTsbPdTimeBase;
|
||||
|
||||
/// @note Packet timestamps wrap around every 01h11m35s (32-bit in usec).
|
||||
/// A wrap check period starts 30 seconds (TSBPD_WRAP_PERIOD) before the wrap point.
|
||||
/// During the wrap check period, packet timestamps smaller than 30 seconds
|
||||
/// are considered to have been wrapped around.
|
||||
/// The wrap check period ends 30 seconds after the wrap point,
|
||||
/// after which the TSBPD base time is adjusted.
|
||||
bool m_bTsbPdWrapCheck; // true: check packet time stamp wraparound (overflow).
|
||||
static const uint32_t TSBPD_WRAP_PERIOD = (30 * 1000000); // 30 seconds (in usec) for timestamp wrapping period.
|
||||
|
||||
/// Maximum clock drift (microseconds) above which TsbPD base time is already adjusted.
|
||||
static const int TSBPD_DRIFT_MAX_VALUE = 5000;
|
||||
/// Number of samples (ACKACK packets) on which to perform drift calculation and compensation.
|
||||
static const int TSBPD_DRIFT_MAX_SAMPLES = 1000;
|
||||
DriftTracer<TSBPD_DRIFT_MAX_SAMPLES, TSBPD_DRIFT_MAX_VALUE> m_DriftTracer;
|
||||
|
||||
/// Protect simultaneous change of state (read/write).
|
||||
mutable Mutex m_mtxRW;
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif // INC_SRT_TSBPD_TIME_H
|
337
trunk/3rdparty/srt-1-fit/srtcore/udt.h
vendored
337
trunk/3rdparty/srt-1-fit/srtcore/udt.h
vendored
|
@ -64,16 +64,16 @@ modified by
|
|||
* file doesn't contain _FUNCTIONS_ predicted to be used in C - see udtc.h
|
||||
*/
|
||||
|
||||
#ifndef __UDT_H__
|
||||
#define __UDT_H__
|
||||
#ifndef INC_SRT_UDT_H
|
||||
#define INC_SRT_UDT_H
|
||||
|
||||
#include "srt.h"
|
||||
|
||||
/*
|
||||
* SRT_ENABLE_THREADCHECK (THIS IS SET IN MAKEFILE NOT HERE)
|
||||
* SRT_ENABLE_THREADCHECK IS SET IN MAKEFILE, NOT HERE
|
||||
*/
|
||||
#if defined(SRT_ENABLE_THREADCHECK)
|
||||
#include <threadcheck.h>
|
||||
#include "threadcheck.h"
|
||||
#else
|
||||
#define THREAD_STATE_INIT(name)
|
||||
#define THREAD_EXIT()
|
||||
|
@ -82,13 +82,6 @@ modified by
|
|||
#define INCREMENT_THREAD_ITERATIONS()
|
||||
#endif
|
||||
|
||||
/* Obsolete way to define MINGW */
|
||||
#ifndef __MINGW__
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#define __MINGW__ 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
|
@ -96,10 +89,6 @@ modified by
|
|||
#include <vector>
|
||||
#endif
|
||||
|
||||
|
||||
// Legacy/backward/deprecated
|
||||
#define UDT_API SRT_API
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//if compiling on VC6.0 or pre-WindowsXP systems
|
||||
|
@ -108,83 +97,6 @@ modified by
|
|||
//if compiling with MinGW, it only works on XP or above
|
||||
//use -D_WIN32_WINNT=0x0501
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __cplusplus
|
||||
// This facility is used only for select() function.
|
||||
// This is considered obsolete and the epoll() functionality rather should be used.
|
||||
typedef std::set<SRTSOCKET> ud_set;
|
||||
#define UD_CLR(u, uset) ((uset)->erase(u))
|
||||
#define UD_ISSET(u, uset) ((uset)->find(u) != (uset)->end())
|
||||
#define UD_SET(u, uset) ((uset)->insert(u))
|
||||
#define UD_ZERO(uset) ((uset)->clear())
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Legacy names
|
||||
|
||||
#define UDT_MSS SRTO_MSS
|
||||
#define UDT_SNDSYN SRTO_SNDSYN
|
||||
#define UDT_RCVSYN SRTO_RCVSYN
|
||||
#define UDT_FC SRTO_FC
|
||||
#define UDT_SNDBUF SRTO_SNDBUF
|
||||
#define UDT_RCVBUF SRTO_RCVBUF
|
||||
#define UDT_LINGER SRTO_LINGER
|
||||
#define UDP_SNDBUF SRTO_UDP_SNDBUF
|
||||
#define UDP_RCVBUF SRTO_UDP_RCVBUF
|
||||
#define UDT_MAXMSG SRTO_MAXMSG
|
||||
#define UDT_MSGTTL SRTO_MSGTTL
|
||||
#define UDT_RENDEZVOUS SRTO_RENDEZVOUS
|
||||
#define UDT_SNDTIMEO SRTO_SNDTIMEO
|
||||
#define UDT_RCVTIMEO SRTO_RCVTIMEO
|
||||
#define UDT_REUSEADDR SRTO_REUSEADDR
|
||||
#define UDT_MAXBW SRTO_MAXBW
|
||||
#define UDT_STATE SRTO_STATE
|
||||
#define UDT_EVENT SRTO_EVENT
|
||||
#define UDT_SNDDATA SRTO_SNDDATA
|
||||
#define UDT_RCVDATA SRTO_RCVDATA
|
||||
#define SRT_SENDER SRTO_SENDER
|
||||
#define SRT_TSBPDMODE SRTO_TSBPDMODE
|
||||
#define SRT_TSBPDDELAY SRTO_TSBPDDELAY
|
||||
#define SRT_INPUTBW SRTO_INPUTBW
|
||||
#define SRT_OHEADBW SRTO_OHEADBW
|
||||
#define SRT_PASSPHRASE SRTO_PASSPHRASE
|
||||
#define SRT_PBKEYLEN SRTO_PBKEYLEN
|
||||
#define SRT_KMSTATE SRTO_KMSTATE
|
||||
#define SRT_IPTTL SRTO_IPTTL
|
||||
#define SRT_IPTOS SRTO_IPTOS
|
||||
#define SRT_TLPKTDROP SRTO_TLPKTDROP
|
||||
#define SRT_TSBPDMAXLAG SRTO_TSBPDMAXLAG
|
||||
#define SRT_RCVNAKREPORT SRTO_NAKREPORT
|
||||
#define SRT_CONNTIMEO SRTO_CONNTIMEO
|
||||
#define SRT_SNDPBKEYLEN SRTO_SNDPBKEYLEN
|
||||
#define SRT_RCVPBKEYLEN SRTO_RCVPBKEYLEN
|
||||
#define SRT_SNDPEERKMSTATE SRTO_SNDPEERKMSTATE
|
||||
#define SRT_RCVKMSTATE SRTO_RCVKMSTATE
|
||||
|
||||
#define UDT_EPOLL_OPT SRT_EPOLL_OPT
|
||||
#define UDT_EPOLL_IN SRT_EPOLL_IN
|
||||
#define UDT_EPOLL_OUT SRT_EPOLL_OUT
|
||||
#define UDT_EPOLL_ERR SRT_EPOLL_ERR
|
||||
|
||||
/* Binary backward compatibility obsolete options */
|
||||
#define SRT_NAKREPORT SRT_RCVNAKREPORT
|
||||
|
||||
#if !defined(SRT_DISABLE_LEGACY_UDTSTATUS)
|
||||
#define UDTSTATUS SRT_SOCKSTATUS
|
||||
#define INIT SRTS_INIT
|
||||
#define OPENED SRTS_OPENED
|
||||
#define LISTENING SRTS_LISTENING
|
||||
#define CONNECTING SRTS_CONNECTING
|
||||
#define CONNECTED SRTS_CONNECTED
|
||||
#define BROKEN SRTS_BROKEN
|
||||
#define CLOSING SRTS_CLOSING
|
||||
#define CLOSED SRTS_CLOSED
|
||||
#define NONEXIST SRTS_NONEXIST
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct CPerfMon
|
||||
|
@ -236,166 +148,75 @@ typedef SRTSOCKET UDTSOCKET; //legacy alias
|
|||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// Class CUDTException exposed for C++ API.
|
||||
// This is actually useless, unless you'd use a DIRECT C++ API,
|
||||
// however there's no such API so far. The current C++ API for UDT/SRT
|
||||
// is predicted to NEVER LET ANY EXCEPTION out of implementation,
|
||||
// so it's useless to catch this exception anyway.
|
||||
|
||||
class UDT_API CUDTException
|
||||
{
|
||||
public:
|
||||
|
||||
CUDTException(CodeMajor major = MJ_SUCCESS, CodeMinor minor = MN_NONE, int err = -1);
|
||||
CUDTException(const CUDTException& e);
|
||||
|
||||
~CUDTException();
|
||||
|
||||
/// Get the description of the exception.
|
||||
/// @return Text message for the exception description.
|
||||
|
||||
const char* getErrorMessage();
|
||||
|
||||
/// Get the system errno for the exception.
|
||||
/// @return errno.
|
||||
|
||||
int getErrorCode() const;
|
||||
|
||||
/// Get the system network errno for the exception.
|
||||
/// @return errno.
|
||||
|
||||
int getErrno() const;
|
||||
/// Clear the error code.
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
CodeMajor m_iMajor; // major exception categories
|
||||
CodeMinor m_iMinor; // for specific error reasons
|
||||
int m_iErrno; // errno returned by the system if there is any
|
||||
std::string m_strMsg; // text error message
|
||||
|
||||
std::string m_strAPI; // the name of UDT function that returns the error
|
||||
std::string m_strDebug; // debug information, set to the original place that causes the error
|
||||
|
||||
public: // Legacy Error Code
|
||||
|
||||
static const int EUNKNOWN = SRT_EUNKNOWN;
|
||||
static const int SUCCESS = SRT_SUCCESS;
|
||||
static const int ECONNSETUP = SRT_ECONNSETUP;
|
||||
static const int ENOSERVER = SRT_ENOSERVER;
|
||||
static const int ECONNREJ = SRT_ECONNREJ;
|
||||
static const int ESOCKFAIL = SRT_ESOCKFAIL;
|
||||
static const int ESECFAIL = SRT_ESECFAIL;
|
||||
static const int ECONNFAIL = SRT_ECONNFAIL;
|
||||
static const int ECONNLOST = SRT_ECONNLOST;
|
||||
static const int ENOCONN = SRT_ENOCONN;
|
||||
static const int ERESOURCE = SRT_ERESOURCE;
|
||||
static const int ETHREAD = SRT_ETHREAD;
|
||||
static const int ENOBUF = SRT_ENOBUF;
|
||||
static const int EFILE = SRT_EFILE;
|
||||
static const int EINVRDOFF = SRT_EINVRDOFF;
|
||||
static const int ERDPERM = SRT_ERDPERM;
|
||||
static const int EINVWROFF = SRT_EINVWROFF;
|
||||
static const int EWRPERM = SRT_EWRPERM;
|
||||
static const int EINVOP = SRT_EINVOP;
|
||||
static const int EBOUNDSOCK = SRT_EBOUNDSOCK;
|
||||
static const int ECONNSOCK = SRT_ECONNSOCK;
|
||||
static const int EINVPARAM = SRT_EINVPARAM;
|
||||
static const int EINVSOCK = SRT_EINVSOCK;
|
||||
static const int EUNBOUNDSOCK = SRT_EUNBOUNDSOCK;
|
||||
static const int ESTREAMILL = SRT_EINVALMSGAPI;
|
||||
static const int EDGRAMILL = SRT_EINVALBUFFERAPI;
|
||||
static const int ENOLISTEN = SRT_ENOLISTEN;
|
||||
static const int ERDVNOSERV = SRT_ERDVNOSERV;
|
||||
static const int ERDVUNBOUND = SRT_ERDVUNBOUND;
|
||||
static const int EINVALMSGAPI = SRT_EINVALMSGAPI;
|
||||
static const int EINVALBUFFERAPI = SRT_EINVALBUFFERAPI;
|
||||
static const int EDUPLISTEN = SRT_EDUPLISTEN;
|
||||
static const int ELARGEMSG = SRT_ELARGEMSG;
|
||||
static const int EINVPOLLID = SRT_EINVPOLLID;
|
||||
static const int EASYNCFAIL = SRT_EASYNCFAIL;
|
||||
static const int EASYNCSND = SRT_EASYNCSND;
|
||||
static const int EASYNCRCV = SRT_EASYNCRCV;
|
||||
static const int ETIMEOUT = SRT_ETIMEOUT;
|
||||
static const int ECONGEST = SRT_ECONGEST;
|
||||
static const int EPEERERR = SRT_EPEERERR;
|
||||
};
|
||||
namespace srt { class CUDTException; }
|
||||
|
||||
namespace UDT
|
||||
{
|
||||
|
||||
typedef CUDTException ERRORINFO;
|
||||
//typedef UDT_SOCKOPT SOCKOPT;
|
||||
typedef srt::CUDTException ERRORINFO;
|
||||
typedef CPerfMon TRACEINFO;
|
||||
typedef CBytePerfMon TRACEBSTATS;
|
||||
typedef ud_set UDSET;
|
||||
|
||||
UDT_API extern const SRTSOCKET INVALID_SOCK;
|
||||
// This facility is used only for select() function.
|
||||
// This is considered obsolete and the epoll() functionality rather should be used.
|
||||
typedef std::set<SRTSOCKET> UDSET;
|
||||
#define UD_CLR(u, uset) ((uset)->erase(u))
|
||||
#define UD_ISSET(u, uset) ((uset)->find(u) != (uset)->end())
|
||||
#define UD_SET(u, uset) ((uset)->insert(u))
|
||||
#define UD_ZERO(uset) ((uset)->clear())
|
||||
|
||||
SRT_API extern const SRTSOCKET INVALID_SOCK;
|
||||
#undef ERROR
|
||||
UDT_API extern const int ERROR;
|
||||
SRT_API extern const int ERROR;
|
||||
|
||||
UDT_API int startup();
|
||||
UDT_API int cleanup();
|
||||
UDT_API UDTSOCKET socket(int af, int type, int protocol);
|
||||
UDT_API int bind(UDTSOCKET u, const struct sockaddr* name, int namelen);
|
||||
UDT_API int bind2(UDTSOCKET u, UDPSOCKET udpsock);
|
||||
UDT_API int listen(UDTSOCKET u, int backlog);
|
||||
UDT_API UDTSOCKET accept(UDTSOCKET u, struct sockaddr* addr, int* addrlen);
|
||||
UDT_API int connect(UDTSOCKET u, const struct sockaddr* name, int namelen);
|
||||
UDT_API int close(UDTSOCKET u);
|
||||
UDT_API int getpeername(UDTSOCKET u, struct sockaddr* name, int* namelen);
|
||||
UDT_API int getsockname(UDTSOCKET u, struct sockaddr* name, int* namelen);
|
||||
UDT_API int getsockopt(UDTSOCKET u, int level, SRT_SOCKOPT optname, void* optval, int* optlen);
|
||||
UDT_API int setsockopt(UDTSOCKET u, int level, SRT_SOCKOPT optname, const void* optval, int optlen);
|
||||
UDT_API int send(UDTSOCKET u, const char* buf, int len, int flags);
|
||||
UDT_API int recv(UDTSOCKET u, char* buf, int len, int flags);
|
||||
SRT_API int startup();
|
||||
SRT_API int cleanup();
|
||||
SRT_API SRTSOCKET socket();
|
||||
inline SRTSOCKET socket(int , int , int ) { return socket(); }
|
||||
SRT_API int bind(SRTSOCKET u, const struct sockaddr* name, int namelen);
|
||||
SRT_API int bind2(SRTSOCKET u, UDPSOCKET udpsock);
|
||||
SRT_API int listen(SRTSOCKET u, int backlog);
|
||||
SRT_API SRTSOCKET accept(SRTSOCKET u, struct sockaddr* addr, int* addrlen);
|
||||
SRT_API int connect(SRTSOCKET u, const struct sockaddr* name, int namelen);
|
||||
SRT_API int close(SRTSOCKET u);
|
||||
SRT_API int getpeername(SRTSOCKET u, struct sockaddr* name, int* namelen);
|
||||
SRT_API int getsockname(SRTSOCKET u, struct sockaddr* name, int* namelen);
|
||||
SRT_API int getsockopt(SRTSOCKET u, int level, SRT_SOCKOPT optname, void* optval, int* optlen);
|
||||
SRT_API int setsockopt(SRTSOCKET u, int level, SRT_SOCKOPT optname, const void* optval, int optlen);
|
||||
SRT_API int send(SRTSOCKET u, const char* buf, int len, int flags);
|
||||
SRT_API int recv(SRTSOCKET u, char* buf, int len, int flags);
|
||||
|
||||
UDT_API int sendmsg(UDTSOCKET u, const char* buf, int len, int ttl = -1, bool inorder = false, uint64_t srctime = 0);
|
||||
UDT_API int recvmsg(UDTSOCKET u, char* buf, int len, uint64_t& srctime);
|
||||
UDT_API int recvmsg(UDTSOCKET u, char* buf, int len);
|
||||
SRT_API int sendmsg(SRTSOCKET u, const char* buf, int len, int ttl = -1, bool inorder = false, int64_t srctime = 0);
|
||||
SRT_API int recvmsg(SRTSOCKET u, char* buf, int len, uint64_t& srctime);
|
||||
SRT_API int recvmsg(SRTSOCKET u, char* buf, int len);
|
||||
|
||||
UDT_API int64_t sendfile(UDTSOCKET u, std::fstream& ifs, int64_t& offset, int64_t size, int block = 364000);
|
||||
UDT_API int64_t recvfile(UDTSOCKET u, std::fstream& ofs, int64_t& offset, int64_t size, int block = 7280000);
|
||||
UDT_API int64_t sendfile2(UDTSOCKET u, const char* path, int64_t* offset, int64_t size, int block = 364000);
|
||||
UDT_API int64_t recvfile2(UDTSOCKET u, const char* path, int64_t* offset, int64_t size, int block = 7280000);
|
||||
SRT_API int64_t sendfile(SRTSOCKET u, std::fstream& ifs, int64_t& offset, int64_t size, int block = 364000);
|
||||
SRT_API int64_t recvfile(SRTSOCKET u, std::fstream& ofs, int64_t& offset, int64_t size, int block = 7280000);
|
||||
SRT_API int64_t sendfile2(SRTSOCKET u, const char* path, int64_t* offset, int64_t size, int block = 364000);
|
||||
SRT_API int64_t recvfile2(SRTSOCKET u, const char* path, int64_t* offset, int64_t size, int block = 7280000);
|
||||
|
||||
// select and selectEX are DEPRECATED; please use epoll.
|
||||
UDT_API int select(int nfds, UDSET* readfds, UDSET* writefds, UDSET* exceptfds, const struct timeval* timeout);
|
||||
UDT_API int selectEx(const std::vector<UDTSOCKET>& fds, std::vector<UDTSOCKET>* readfds,
|
||||
std::vector<UDTSOCKET>* writefds, std::vector<UDTSOCKET>* exceptfds, int64_t msTimeOut);
|
||||
SRT_API int select(int nfds, UDSET* readfds, UDSET* writefds, UDSET* exceptfds, const struct timeval* timeout);
|
||||
SRT_API int selectEx(const std::vector<SRTSOCKET>& fds, std::vector<SRTSOCKET>* readfds,
|
||||
std::vector<SRTSOCKET>* writefds, std::vector<SRTSOCKET>* exceptfds, int64_t msTimeOut);
|
||||
|
||||
UDT_API int epoll_create();
|
||||
UDT_API int epoll_add_usock(int eid, UDTSOCKET u, const int* events = NULL);
|
||||
UDT_API int epoll_add_ssock(int eid, SYSSOCKET s, const int* events = NULL);
|
||||
UDT_API int epoll_remove_usock(int eid, UDTSOCKET u);
|
||||
UDT_API int epoll_remove_ssock(int eid, SYSSOCKET s);
|
||||
UDT_API int epoll_update_usock(int eid, UDTSOCKET u, const int* events = NULL);
|
||||
UDT_API int epoll_update_ssock(int eid, SYSSOCKET s, const int* events = NULL);
|
||||
UDT_API int epoll_wait(int eid, std::set<UDTSOCKET>* readfds, std::set<UDTSOCKET>* writefds, int64_t msTimeOut,
|
||||
SRT_API int epoll_create();
|
||||
SRT_API int epoll_add_usock(int eid, SRTSOCKET u, const int* events = NULL);
|
||||
SRT_API int epoll_add_ssock(int eid, SYSSOCKET s, const int* events = NULL);
|
||||
SRT_API int epoll_remove_usock(int eid, SRTSOCKET u);
|
||||
SRT_API int epoll_remove_ssock(int eid, SYSSOCKET s);
|
||||
SRT_API int epoll_update_usock(int eid, SRTSOCKET u, const int* events = NULL);
|
||||
SRT_API int epoll_update_ssock(int eid, SYSSOCKET s, const int* events = NULL);
|
||||
SRT_API int epoll_wait(int eid, std::set<SRTSOCKET>* readfds, std::set<SRTSOCKET>* writefds, int64_t msTimeOut,
|
||||
std::set<SYSSOCKET>* lrfds = NULL, std::set<SYSSOCKET>* wrfds = NULL);
|
||||
UDT_API int epoll_wait2(int eid, UDTSOCKET* readfds, int* rnum, UDTSOCKET* writefds, int* wnum, int64_t msTimeOut,
|
||||
SRT_API int epoll_wait2(int eid, SRTSOCKET* readfds, int* rnum, SRTSOCKET* writefds, int* wnum, int64_t msTimeOut,
|
||||
SYSSOCKET* lrfds = NULL, int* lrnum = NULL, SYSSOCKET* lwfds = NULL, int* lwnum = NULL);
|
||||
UDT_API int epoll_uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut);
|
||||
UDT_API int epoll_release(int eid);
|
||||
UDT_API ERRORINFO& getlasterror();
|
||||
UDT_API int getlasterror_code();
|
||||
UDT_API const char* getlasterror_desc();
|
||||
UDT_API int bstats(UDTSOCKET u, TRACEBSTATS* perf, bool clear = true);
|
||||
UDT_API SRT_SOCKSTATUS getsockstate(UDTSOCKET u);
|
||||
|
||||
// This is a C++ SRT API extension. This is not a part of legacy UDT API.
|
||||
UDT_API void setloglevel(srt_logging::LogLevel::type ll);
|
||||
UDT_API void addlogfa(srt_logging::LogFA fa);
|
||||
UDT_API void dellogfa(srt_logging::LogFA fa);
|
||||
UDT_API void resetlogfa(std::set<srt_logging::LogFA> fas);
|
||||
UDT_API void resetlogfa(const int* fara, size_t fara_size);
|
||||
UDT_API void setlogstream(std::ostream& stream);
|
||||
UDT_API void setloghandler(void* opaque, SRT_LOG_HANDLER_FN* handler);
|
||||
UDT_API void setlogflags(int flags);
|
||||
|
||||
UDT_API bool setstreamid(UDTSOCKET u, const std::string& sid);
|
||||
UDT_API std::string getstreamid(UDTSOCKET u);
|
||||
SRT_API int epoll_uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut);
|
||||
SRT_API int epoll_release(int eid);
|
||||
SRT_API ERRORINFO& getlasterror();
|
||||
SRT_API int getlasterror_code();
|
||||
SRT_API const char* getlasterror_desc();
|
||||
SRT_API int bstats(SRTSOCKET u, SRT_TRACEBSTATS* perf, bool clear = true);
|
||||
SRT_API SRT_SOCKSTATUS getsockstate(SRTSOCKET u);
|
||||
|
||||
} // namespace UDT
|
||||
|
||||
|
@ -405,7 +226,47 @@ UDT_API std::string getstreamid(UDTSOCKET u);
|
|||
// own logger FA objects, or create their own. The object of this type
|
||||
// is required to initialize the logger FA object.
|
||||
namespace srt_logging { struct LogConfig; }
|
||||
UDT_API extern srt_logging::LogConfig srt_logger_config;
|
||||
SRT_API extern srt_logging::LogConfig srt_logger_config;
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
// This is a C++ SRT API extension. This is not a part of legacy UDT API.
|
||||
SRT_API void setloglevel(srt_logging::LogLevel::type ll);
|
||||
SRT_API void addlogfa(srt_logging::LogFA fa);
|
||||
SRT_API void dellogfa(srt_logging::LogFA fa);
|
||||
SRT_API void resetlogfa(std::set<srt_logging::LogFA> fas);
|
||||
SRT_API void resetlogfa(const int* fara, size_t fara_size);
|
||||
SRT_API void setlogstream(std::ostream& stream);
|
||||
SRT_API void setloghandler(void* opaque, SRT_LOG_HANDLER_FN* handler);
|
||||
SRT_API void setlogflags(int flags);
|
||||
|
||||
SRT_API bool setstreamid(SRTSOCKET u, const std::string& sid);
|
||||
SRT_API std::string getstreamid(SRTSOCKET u);
|
||||
|
||||
// Namespace alias
|
||||
namespace logging {
|
||||
using namespace srt_logging;
|
||||
}
|
||||
|
||||
} // namespace srt
|
||||
|
||||
// Planned deprecated removal: rel1.6.0
|
||||
// There's also no portable way possible to enforce a deprecation
|
||||
// compiler warning, so leaving as is.
|
||||
namespace UDT
|
||||
{
|
||||
// Backward-compatible aliases, just for a case someone was using it.
|
||||
using srt::setloglevel;
|
||||
using srt::addlogfa;
|
||||
using srt::dellogfa;
|
||||
using srt::resetlogfa;
|
||||
using srt::setlogstream;
|
||||
using srt::setloghandler;
|
||||
using srt::setlogflags;
|
||||
using srt::setstreamid;
|
||||
using srt::getstreamid;
|
||||
}
|
||||
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
|
405
trunk/3rdparty/srt-1-fit/srtcore/utilities.h
vendored
Executable file → Normal file
405
trunk/3rdparty/srt-1-fit/srtcore/utilities.h
vendored
Executable file → Normal file
|
@ -13,72 +13,14 @@ written by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC__SRT_UTILITIES_H
|
||||
#define INC__SRT_UTILITIES_H
|
||||
|
||||
|
||||
#ifdef __GNUG__
|
||||
#define ATR_UNUSED __attribute__((unused))
|
||||
#define ATR_DEPRECATED __attribute__((deprecated))
|
||||
#else
|
||||
#define ATR_UNUSED
|
||||
#define ATR_DEPRECATED
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) && __cplusplus > 199711L
|
||||
#define HAVE_CXX11 1
|
||||
|
||||
// For gcc 4.7, claim C++11 is supported, as long as experimental C++0x is on,
|
||||
// however it's only the "most required C++11 support".
|
||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 7 // 4.7 only!
|
||||
#define ATR_NOEXCEPT
|
||||
#define ATR_CONSTEXPR
|
||||
#define ATR_OVERRIDE
|
||||
#define ATR_FINAL
|
||||
#else
|
||||
#define HAVE_FULL_CXX11 1
|
||||
#define ATR_NOEXCEPT noexcept
|
||||
#define ATR_CONSTEXPR constexpr
|
||||
#define ATR_OVERRIDE override
|
||||
#define ATR_FINAL final
|
||||
#endif
|
||||
|
||||
// Microsoft Visual Studio supports C++11, but not fully,
|
||||
// and still did not change the value of __cplusplus. Treat
|
||||
// this special way.
|
||||
// _MSC_VER == 1800 means Microsoft Visual Studio 2013.
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1800
|
||||
#define HAVE_CXX11 1
|
||||
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
|
||||
#define HAVE_FULL_CXX11 1
|
||||
#define ATR_NOEXCEPT noexcept
|
||||
#define ATR_CONSTEXPR constexpr
|
||||
#define ATR_OVERRIDE override
|
||||
#define ATR_FINAL final
|
||||
#else
|
||||
#define ATR_NOEXCEPT
|
||||
#define ATR_CONSTEXPR
|
||||
#define ATR_OVERRIDE
|
||||
#define ATR_FINAL
|
||||
#endif
|
||||
#else
|
||||
#define HAVE_CXX11 0
|
||||
#define ATR_NOEXCEPT // throw() - bad idea
|
||||
#define ATR_CONSTEXPR
|
||||
#define ATR_OVERRIDE
|
||||
#define ATR_FINAL
|
||||
|
||||
#endif
|
||||
|
||||
#if !HAVE_CXX11 && defined(REQUIRE_CXX11) && REQUIRE_CXX11 == 1
|
||||
#error "The currently compiled application required C++11, but your compiler doesn't support it."
|
||||
#endif
|
||||
|
||||
#ifndef INC_SRT_UTILITIES_H
|
||||
#define INC_SRT_UTILITIES_H
|
||||
|
||||
// Windows warning disabler
|
||||
#define _CRT_SECURE_NO_WARNINGS 1
|
||||
|
||||
#include "platform_sys.h"
|
||||
#include "srt_attr_defs.h" // defines HAVE_CXX11
|
||||
|
||||
// Happens that these are defined, undefine them in advance
|
||||
#undef min
|
||||
|
@ -88,10 +30,11 @@ written by
|
|||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#if HAVE_CXX11
|
||||
#include <type_traits>
|
||||
|
@ -100,6 +43,7 @@ written by
|
|||
#include <cstdlib>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
// -------------- UTILITIES ------------------------
|
||||
|
||||
|
@ -113,7 +57,7 @@ written by
|
|||
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__CYGWIN__) || defined(__GNU__)
|
||||
#if defined(__linux__) || defined(__CYGWIN__) || defined(__GNU__) || defined(__GLIBC__)
|
||||
|
||||
# include <endian.h>
|
||||
|
||||
|
@ -171,7 +115,7 @@ written by
|
|||
|
||||
# include <sys/endian.h>
|
||||
|
||||
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
|
||||
|
||||
# include <sys/endian.h>
|
||||
|
||||
|
@ -196,6 +140,46 @@ written by
|
|||
# define le64toh(x) letoh64(x)
|
||||
#endif
|
||||
|
||||
#elif defined(SUNOS)
|
||||
|
||||
// SunOS/Solaris
|
||||
|
||||
#include <sys/byteorder.h>
|
||||
#include <sys/isa_defs.h>
|
||||
|
||||
#define __LITTLE_ENDIAN 1234
|
||||
#define __BIG_ENDIAN 4321
|
||||
|
||||
# if defined(_BIG_ENDIAN)
|
||||
#define __BYTE_ORDER __BIG_ENDIAN
|
||||
#define be64toh(x) (x)
|
||||
#define be32toh(x) (x)
|
||||
#define be16toh(x) (x)
|
||||
#define le16toh(x) ((uint16_t)BSWAP_16(x))
|
||||
#define le32toh(x) BSWAP_32(x)
|
||||
#define le64toh(x) BSWAP_64(x)
|
||||
#define htobe16(x) (x)
|
||||
#define htole16(x) ((uint16_t)BSWAP_16(x))
|
||||
#define htobe32(x) (x)
|
||||
#define htole32(x) BSWAP_32(x)
|
||||
#define htobe64(x) (x)
|
||||
#define htole64(x) BSWAP_64(x)
|
||||
# else
|
||||
#define __BYTE_ORDER __LITTLE_ENDIAN
|
||||
#define be64toh(x) BSWAP_64(x)
|
||||
#define be32toh(x) ntohl(x)
|
||||
#define be16toh(x) ntohs(x)
|
||||
#define le16toh(x) (x)
|
||||
#define le32toh(x) (x)
|
||||
#define le64toh(x) (x)
|
||||
#define htobe16(x) htons(x)
|
||||
#define htole16(x) (x)
|
||||
#define htobe32(x) htonl(x)
|
||||
#define htole32(x) (x)
|
||||
#define htobe64(x) BSWAP_64(x)
|
||||
#define htole64(x) (x)
|
||||
# endif
|
||||
|
||||
#elif defined(__WINDOWS__)
|
||||
|
||||
# include <winsock2.h>
|
||||
|
@ -317,7 +301,7 @@ template<size_t R>
|
|||
struct BitsetMask<R, R, true>
|
||||
{
|
||||
static const bool correct = true;
|
||||
static const uint32_t value = 1 << R;
|
||||
static const uint32_t value = 1u << R;
|
||||
};
|
||||
|
||||
// This is a trap for a case that BitsetMask::correct in the master template definition
|
||||
|
@ -426,6 +410,88 @@ struct DynamicStruct
|
|||
};
|
||||
|
||||
|
||||
/// Fixed-size array template class.
|
||||
namespace srt {
|
||||
|
||||
template <class T>
|
||||
class FixedArray
|
||||
{
|
||||
public:
|
||||
FixedArray(size_t size)
|
||||
: m_size(size)
|
||||
, m_entries(new T[size])
|
||||
{
|
||||
}
|
||||
|
||||
~FixedArray()
|
||||
{
|
||||
delete [] m_entries;
|
||||
}
|
||||
|
||||
public:
|
||||
const T& operator[](size_t index) const
|
||||
{
|
||||
if (index >= m_size)
|
||||
raise_expection(index);
|
||||
|
||||
return m_entries[index];
|
||||
}
|
||||
|
||||
T& operator[](size_t index)
|
||||
{
|
||||
if (index >= m_size)
|
||||
raise_expection(index);
|
||||
|
||||
return m_entries[index];
|
||||
}
|
||||
|
||||
const T& operator[](int index) const
|
||||
{
|
||||
if (index < 0 || static_cast<size_t>(index) >= m_size)
|
||||
raise_expection(index);
|
||||
|
||||
return m_entries[index];
|
||||
}
|
||||
|
||||
T& operator[](int index)
|
||||
{
|
||||
if (index < 0 || static_cast<size_t>(index) >= m_size)
|
||||
raise_expection(index);
|
||||
|
||||
return m_entries[index];
|
||||
}
|
||||
|
||||
size_t size() const { return m_size; }
|
||||
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
|
||||
iterator begin() { return m_entries; }
|
||||
iterator end() { return m_entries + m_size; }
|
||||
|
||||
const_iterator cbegin() const { return m_entries; }
|
||||
const_iterator cend() const { return m_entries + m_size; }
|
||||
|
||||
T* data() { return m_entries; }
|
||||
|
||||
private:
|
||||
FixedArray(const FixedArray<T>& );
|
||||
FixedArray<T>& operator=(const FixedArray<T>&);
|
||||
|
||||
void raise_expection(int i) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Index " << i << "out of range";
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_size;
|
||||
T* const m_entries;
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
// ------------------------------------------------------------
|
||||
|
||||
|
||||
|
@ -435,47 +501,25 @@ inline bool IsSet(int32_t bitset, int32_t flagset)
|
|||
return (bitset & flagset) == flagset;
|
||||
}
|
||||
|
||||
// Homecooked version of ref_t. It's a copy of std::reference_wrapper
|
||||
// voided of unwanted properties and renamed to ref_t.
|
||||
|
||||
|
||||
#if HAVE_CXX11
|
||||
#include <functional>
|
||||
#endif
|
||||
|
||||
template<typename Type>
|
||||
class ref_t
|
||||
// std::addressof in C++11,
|
||||
// needs to be provided for C++03
|
||||
template <class RefType>
|
||||
inline RefType* AddressOf(RefType& r)
|
||||
{
|
||||
Type* m_data;
|
||||
return (RefType*)(&(unsigned char&)(r));
|
||||
}
|
||||
|
||||
public:
|
||||
typedef Type type;
|
||||
template <class T>
|
||||
struct explicit_t
|
||||
{
|
||||
T inobject;
|
||||
explicit_t(const T& uo): inobject(uo) {}
|
||||
|
||||
#if HAVE_CXX11
|
||||
explicit ref_t(Type& __indata)
|
||||
: m_data(std::addressof(__indata))
|
||||
{ }
|
||||
#else
|
||||
explicit ref_t(Type& __indata)
|
||||
: m_data((Type*)(&(char&)(__indata)))
|
||||
{ }
|
||||
#endif
|
||||
operator T() const { return inobject; }
|
||||
|
||||
ref_t(const ref_t<Type>& inref)
|
||||
: m_data(inref.m_data)
|
||||
{ }
|
||||
|
||||
#if HAVE_CXX11
|
||||
ref_t(const std::reference_wrapper<Type>& i): m_data(std::addressof(i.get())) {}
|
||||
#endif
|
||||
|
||||
Type& operator*() { return *m_data; }
|
||||
|
||||
Type& get() const
|
||||
{ return *m_data; }
|
||||
|
||||
Type operator->() const
|
||||
{ return *m_data; }
|
||||
private:
|
||||
template <class X>
|
||||
explicit_t(const X& another);
|
||||
};
|
||||
|
||||
// This is required for Printable function if you have a container of pairs,
|
||||
|
@ -492,15 +536,6 @@ namespace srt_pair_op
|
|||
|
||||
#if HAVE_CXX11
|
||||
|
||||
// This alias was created so that 'Ref' (not 'ref') is used everywhere.
|
||||
// Normally the C++11 'ref' fits perfectly here, however in C++03 mode
|
||||
// it would have to be newly created. This would then cause a conflict
|
||||
// between C++03 SRT and C++11 applications as well as between C++ standard
|
||||
// library and SRT when SRT is compiled in C++11 mode (as it happens on
|
||||
// Darwin/clang).
|
||||
template <class In>
|
||||
inline auto Ref(In& i) -> decltype(std::ref(i)) { return std::ref(i); }
|
||||
|
||||
template <class In>
|
||||
inline auto Move(In& i) -> decltype(std::move(i)) { return std::move(i); }
|
||||
|
||||
|
@ -530,8 +565,6 @@ inline std::string Sprint(Args&&... args)
|
|||
template <class T>
|
||||
using UniquePtr = std::unique_ptr<T>;
|
||||
|
||||
// Some utilities borrowed from tumux, as this is using options
|
||||
// similar way.
|
||||
template <class Container, class Value = typename Container::value_type, typename... Args> inline
|
||||
std::string Printable(const Container& in, Value /*pseudoargument*/, Args&&... args)
|
||||
{
|
||||
|
@ -577,12 +610,6 @@ auto map_getp(const Map& m, const Key& key) -> typename Map::mapped_type const*
|
|||
|
||||
#else
|
||||
|
||||
template <class Type>
|
||||
ref_t<Type> Ref(Type& arg)
|
||||
{
|
||||
return ref_t<Type>(arg);
|
||||
}
|
||||
|
||||
// The unique_ptr requires C++11, and the rvalue-reference feature,
|
||||
// so here we're simulate the behavior using the old std::auto_ptr.
|
||||
|
||||
|
@ -610,14 +637,14 @@ public:
|
|||
|
||||
// All constructor declarations must be repeated.
|
||||
// "Constructor delegation" is also only C++11 feature.
|
||||
explicit UniquePtr(element_type* __p = 0) throw() : Base(__p) {}
|
||||
UniquePtr(UniquePtr& __a) throw() : Base(__a) { }
|
||||
template<typename _Tp1>
|
||||
UniquePtr(UniquePtr<_Tp1>& __a) throw() : Base(__a) {}
|
||||
explicit UniquePtr(element_type* p = 0) throw() : Base(p) {}
|
||||
UniquePtr(UniquePtr& a) throw() : Base(a) { }
|
||||
template<typename Type1>
|
||||
UniquePtr(UniquePtr<Type1>& a) throw() : Base(a) {}
|
||||
|
||||
UniquePtr& operator=(UniquePtr& __a) throw() { return Base::operator=(__a); }
|
||||
template<typename _Tp1>
|
||||
UniquePtr& operator=(UniquePtr<_Tp1>& __a) throw() { return Base::operator=(__a); }
|
||||
UniquePtr& operator=(UniquePtr& a) throw() { return Base::operator=(a); }
|
||||
template<typename Type1>
|
||||
UniquePtr& operator=(UniquePtr<Type1>& a) throw() { return Base::operator=(a); }
|
||||
|
||||
// Good, now we need to add some parts of the API of unique_ptr.
|
||||
|
||||
|
@ -630,7 +657,15 @@ public:
|
|||
operator bool () { return 0!= get(); }
|
||||
};
|
||||
|
||||
// A primitive one-argument version of Printable
|
||||
// A primitive one-argument versions of Sprint and Printable
|
||||
template <class Arg1>
|
||||
inline std::string Sprint(const Arg1& arg)
|
||||
{
|
||||
std::ostringstream sout;
|
||||
sout << arg;
|
||||
return sout.str();
|
||||
}
|
||||
|
||||
template <class Container> inline
|
||||
std::string Printable(const Container& in)
|
||||
{
|
||||
|
@ -675,6 +710,44 @@ typename Map::mapped_type const* map_getp(const Map& m, const Key& key)
|
|||
|
||||
#endif
|
||||
|
||||
// Printable with prefix added for every element.
|
||||
// Useful when printing a container of sockets or sequence numbers.
|
||||
template <class Container> inline
|
||||
std::string PrintableMod(const Container& in, const std::string& prefix)
|
||||
{
|
||||
using namespace srt_pair_op;
|
||||
typedef typename Container::value_type Value;
|
||||
std::ostringstream os;
|
||||
os << "[ ";
|
||||
for (typename Container::const_iterator y = in.begin(); y != in.end(); ++y)
|
||||
os << prefix << Value(*y) << " ";
|
||||
os << "]";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
template<typename InputIterator, typename OutputIterator, typename TransFunction>
|
||||
inline void FilterIf(InputIterator bg, InputIterator nd,
|
||||
OutputIterator out, TransFunction fn)
|
||||
{
|
||||
for (InputIterator i = bg; i != nd; ++i)
|
||||
{
|
||||
std::pair<typename TransFunction::result_type, bool> result = fn(*i);
|
||||
if (!result.second)
|
||||
continue;
|
||||
*out++ = result.first;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Value, class ArgValue>
|
||||
inline void insert_uniq(std::vector<Value>& v, const ArgValue& val)
|
||||
{
|
||||
typename std::vector<Value>::iterator i = std::find(v.begin(), v.end(), val);
|
||||
if (i != v.end())
|
||||
return;
|
||||
|
||||
v.push_back(val);
|
||||
}
|
||||
|
||||
template <class Signature>
|
||||
struct CallbackHolder
|
||||
{
|
||||
|
@ -696,7 +769,8 @@ struct CallbackHolder
|
|||
// Casting function-to-function, however, should not. Unfortunately
|
||||
// newer compilers disallow that, too (when a signature differs), but
|
||||
// then they should better use the C++11 way, much more reliable and safer.
|
||||
void* (*testfn)(void*) ATR_UNUSED = (void*(*)(void*))f;
|
||||
void* (*testfn)(void*) = (void*(*)(void*))f;
|
||||
(void)(testfn);
|
||||
#endif
|
||||
opaque = o;
|
||||
fn = f;
|
||||
|
@ -767,11 +841,13 @@ public:
|
|||
m_qDriftSum += driftval;
|
||||
++m_uDriftSpan;
|
||||
|
||||
// I moved it here to calculate accumulated overdrift.
|
||||
if (CLEAR_ON_UPDATE)
|
||||
m_qOverdrift = 0;
|
||||
|
||||
if (m_uDriftSpan < MAX_SPAN)
|
||||
return false;
|
||||
|
||||
if (CLEAR_ON_UPDATE)
|
||||
m_qOverdrift = 0;
|
||||
|
||||
// Calculate the median of all drift values.
|
||||
// In most cases, the divisor should be == MAX_SPAN.
|
||||
|
@ -799,6 +875,12 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
// For group overrides
|
||||
void forceDrift(int64_t driftval)
|
||||
{
|
||||
m_qDrift = driftval;
|
||||
}
|
||||
|
||||
// These values can be read at any time, however if you want
|
||||
// to depend on the fact that they have been changed lately,
|
||||
// you have to check the return value from update().
|
||||
|
@ -869,15 +951,15 @@ struct MapProxy
|
|||
}
|
||||
};
|
||||
|
||||
/// Print some hash-based stamp of the first 16 bytes in the buffer
|
||||
inline std::string BufferStamp(const char* mem, size_t size)
|
||||
{
|
||||
using namespace std;
|
||||
char spread[16];
|
||||
|
||||
int n = 16-size;
|
||||
if (n > 0)
|
||||
memset(spread+16-n, 0, n);
|
||||
memcpy(spread, mem, min(size_t(16), size));
|
||||
if (size < 16)
|
||||
memset((spread + size), 0, 16 - size);
|
||||
memcpy((spread), mem, min(size_t(16), size));
|
||||
|
||||
// Now prepare 4 cells for uint32_t.
|
||||
union
|
||||
|
@ -885,7 +967,7 @@ inline std::string BufferStamp(const char* mem, size_t size)
|
|||
uint32_t sum;
|
||||
char cells[4];
|
||||
};
|
||||
memset(cells, 0, 4);
|
||||
memset((cells), 0, 4);
|
||||
|
||||
for (size_t x = 0; x < 4; ++x)
|
||||
for (size_t y = 0; y < 4; ++y)
|
||||
|
@ -894,9 +976,7 @@ inline std::string BufferStamp(const char* mem, size_t size)
|
|||
}
|
||||
|
||||
// Convert to hex string
|
||||
|
||||
ostringstream os;
|
||||
|
||||
os << hex << uppercase << setfill('0') << setw(8) << sum;
|
||||
|
||||
return os.str();
|
||||
|
@ -963,7 +1043,56 @@ ATR_CONSTEXPR size_t Size(const V (&)[N]) ATR_NOEXCEPT { return N; }
|
|||
template <size_t DEPRLEN, typename ValueType>
|
||||
inline ValueType avg_iir(ValueType old_value, ValueType new_value)
|
||||
{
|
||||
return (old_value*(DEPRLEN-1) + new_value)/DEPRLEN;
|
||||
return (old_value * (DEPRLEN - 1) + new_value) / DEPRLEN;
|
||||
}
|
||||
|
||||
template <size_t DEPRLEN, typename ValueType>
|
||||
inline ValueType avg_iir_w(ValueType old_value, ValueType new_value, size_t new_val_weight)
|
||||
{
|
||||
return (old_value * (DEPRLEN - new_val_weight) + new_value * new_val_weight) / DEPRLEN;
|
||||
}
|
||||
|
||||
// Property accessor definitions
|
||||
//
|
||||
// "Property" is a special method that accesses given field.
|
||||
// This relies only on a convention, which is the following:
|
||||
//
|
||||
// V x = object.prop(); <-- get the property's value
|
||||
// object.prop(x); <-- set the property a value
|
||||
//
|
||||
// Properties might be also chained when setting:
|
||||
//
|
||||
// object.prop1(v1).prop2(v2).prop3(v3);
|
||||
//
|
||||
// Properties may be defined various even very complicated
|
||||
// ways, which is simply providing a method with body. In order
|
||||
// to define a property simplest possible way, that is, refer
|
||||
// directly to the field that keeps it, here are the following macros:
|
||||
//
|
||||
// Prefix: SRTU_PROPERTY_
|
||||
// Followed by:
|
||||
// - access type: RO, WO, RW, RR, RRW
|
||||
// - chain flag: optional _CHAIN
|
||||
// Where access type is:
|
||||
// - RO - read only. Defines reader accessor. The accessor method will be const.
|
||||
// - RR - read reference. The accessor isn't const to allow reference passthrough.
|
||||
// - WO - write only. Defines writer accessor.
|
||||
// - RW - combines RO and WO.
|
||||
// - RRW - combines RR and WO.
|
||||
//
|
||||
// The _CHAIN marker is optional for macros providing writable accessors
|
||||
// for properties. The difference is that while simple write accessors return
|
||||
// void, the chaining accessors return the reference to the object for which
|
||||
// the write accessor was called so that you can call the next accessor (or
|
||||
// any other method as well) for the result.
|
||||
|
||||
#define SRTU_PROPERTY_RR(type, name, field) type name() { return field; }
|
||||
#define SRTU_PROPERTY_RO(type, name, field) type name() const { return field; }
|
||||
#define SRTU_PROPERTY_WO(type, name, field) void set_##name(type arg) { field = arg; }
|
||||
#define SRTU_PROPERTY_WO_CHAIN(otype, type, name, field) otype& set_##name(type arg) { field = arg; return *this; }
|
||||
#define SRTU_PROPERTY_RW(type, name, field) SRTU_PROPERTY_RO(type, name, field); SRTU_PROPERTY_WO(type, name, field)
|
||||
#define SRTU_PROPERTY_RRW(type, name, field) SRTU_PROPERTY_RR(type, name, field); SRTU_PROPERTY_WO(type, name, field)
|
||||
#define SRTU_PROPERTY_RW_CHAIN(otype, type, name, field) SRTU_PROPERTY_RO(type, name, field); SRTU_PROPERTY_WO_CHAIN(otype, type, name, field)
|
||||
#define SRTU_PROPERTY_RRW_CHAIN(otype, type, name, field) SRTU_PROPERTY_RR(type, name, field); SRTU_PROPERTY_WO_CHAIN(otype, type, name, field)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,8 +13,8 @@ written by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC__SRT_VERSION_H
|
||||
#define INC__SRT_VERSION_H
|
||||
#ifndef INC_SRT_VERSION_H
|
||||
#define INC_SRT_VERSION_H
|
||||
|
||||
// To construct version value
|
||||
#define SRT_MAKE_VERSION(major, minor, patch) \
|
||||
|
@ -24,11 +24,11 @@ written by
|
|||
#define SRT_VERSION_MAJOR @SRT_VERSION_MAJOR@
|
||||
#define SRT_VERSION_MINOR @SRT_VERSION_MINOR@
|
||||
#define SRT_VERSION_PATCH @SRT_VERSION_PATCH@
|
||||
#cmakedefine SRT_VERSION_BUILD @APPVEYOR_BUILD_NUMBER_STRING@
|
||||
#cmakedefine SRT_VERSION_BUILD @CI_BUILD_NUMBER_STRING@
|
||||
|
||||
#define SRT_VERSION_STRING "@SRT_VERSION@"
|
||||
#define SRT_VERSION_VALUE \
|
||||
SRT_MAKE_VERSION_VALUE( \
|
||||
SRT_VERSION_MAJOR, SRT_VERSION_MINOR, SRT_VERSION_PATCH )
|
||||
|
||||
#endif // INC__SRT_VERSION_H
|
||||
#endif // INC_SRT_VERSION_H
|
||||
|
|
48
trunk/3rdparty/srt-1-fit/srtcore/window.cpp
vendored
48
trunk/3rdparty/srt-1-fit/srtcore/window.cpp
vendored
|
@ -50,6 +50,8 @@ modified by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include "common.h"
|
||||
|
@ -57,7 +59,10 @@ modified by
|
|||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
using namespace srt::sync;
|
||||
|
||||
namespace srt
|
||||
{
|
||||
namespace ACKWindowTools
|
||||
{
|
||||
|
||||
|
@ -65,7 +70,7 @@ void store(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int32_t s
|
|||
{
|
||||
r_aSeq[r_iHead].iACKSeqNo = seq;
|
||||
r_aSeq[r_iHead].iACK = ack;
|
||||
r_aSeq[r_iHead].TimeStamp = CTimer::getTime();
|
||||
r_aSeq[r_iHead].tsTimeStamp = steady_clock::now();
|
||||
|
||||
r_iHead = (r_iHead + 1) % size;
|
||||
|
||||
|
@ -74,27 +79,26 @@ void store(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int32_t s
|
|||
r_iTail = (r_iTail + 1) % size;
|
||||
}
|
||||
|
||||
int acknowledge(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int32_t seq, int32_t& r_ack)
|
||||
int acknowledge(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int32_t seq, int32_t& r_ack, const steady_clock::time_point& currtime)
|
||||
{
|
||||
// Head has not exceeded the physical boundary of the window
|
||||
if (r_iHead >= r_iTail)
|
||||
{
|
||||
// Head has not exceeded the physical boundary of the window
|
||||
|
||||
for (int i = r_iTail, n = r_iHead; i < n; ++ i)
|
||||
{
|
||||
// looking for indentical ACK Seq. No.
|
||||
// Looking for an identical ACK Seq. No.
|
||||
if (seq == r_aSeq[i].iACKSeqNo)
|
||||
{
|
||||
// return the Data ACK it carried
|
||||
// Return the Data ACK it carried
|
||||
r_ack = r_aSeq[i].iACK;
|
||||
|
||||
// calculate RTT
|
||||
int rtt = int(CTimer::getTime() - r_aSeq[i].TimeStamp);
|
||||
// Calculate RTT estimate
|
||||
const int rtt = count_microseconds(currtime - r_aSeq[i].tsTimeStamp);
|
||||
|
||||
if (i + 1 == r_iHead)
|
||||
{
|
||||
r_iTail = r_iHead = 0;
|
||||
r_aSeq[0].iACKSeqNo = -1;
|
||||
r_aSeq[0].iACKSeqNo = SRT_SEQNO_NONE;
|
||||
}
|
||||
else
|
||||
r_iTail = (i + 1) % size;
|
||||
|
@ -103,22 +107,22 @@ int acknowledge(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int3
|
|||
}
|
||||
}
|
||||
|
||||
// Bad input, the ACK node has been overwritten
|
||||
// The record about ACK is not found in the buffer, RTT can not be calculated
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Head has exceeded the physical window boundary, so it is behind tail
|
||||
for (int j = r_iTail, n = r_iHead + size; j < n; ++ j)
|
||||
{
|
||||
// looking for indentical ACK seq. no.
|
||||
// Looking for an identical ACK Seq. No.
|
||||
if (seq == r_aSeq[j % size].iACKSeqNo)
|
||||
{
|
||||
// return Data ACK
|
||||
// Return the Data ACK it carried
|
||||
j %= size;
|
||||
r_ack = r_aSeq[j].iACK;
|
||||
|
||||
// calculate RTT
|
||||
int rtt = int(CTimer::getTime() - r_aSeq[j].TimeStamp);
|
||||
// Calculate RTT estimate
|
||||
const int rtt = count_microseconds(currtime - r_aSeq[j].tsTimeStamp);
|
||||
|
||||
if (j == r_iHead)
|
||||
{
|
||||
|
@ -132,14 +136,16 @@ int acknowledge(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int3
|
|||
}
|
||||
}
|
||||
|
||||
// bad input, the ACK node has been overwritten
|
||||
// The record about ACK is not found in the buffer, RTT can not be calculated
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AckTools
|
||||
} // namespace srt
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CPktTimeWindowTools::initializeWindowArrays(int* r_pktWindow, int* r_probeWindow, int* r_bytesWindow, size_t asize, size_t psize)
|
||||
void srt::CPktTimeWindowTools::initializeWindowArrays(int* r_pktWindow, int* r_probeWindow, int* r_bytesWindow, size_t asize, size_t psize)
|
||||
{
|
||||
for (size_t i = 0; i < asize; ++ i)
|
||||
r_pktWindow[i] = 1000000; //1 sec -> 1 pkt/sec
|
||||
|
@ -148,11 +154,11 @@ void CPktTimeWindowTools::initializeWindowArrays(int* r_pktWindow, int* r_probeW
|
|||
r_probeWindow[k] = 1000; //1 msec -> 1000 pkts/sec
|
||||
|
||||
for (size_t i = 0; i < asize; ++ i)
|
||||
r_bytesWindow[i] = CPacket::SRT_MAX_PAYLOAD_SIZE; //based on 1 pkt/sec set in r_pktWindow[i]
|
||||
r_bytesWindow[i] = srt::CPacket::SRT_MAX_PAYLOAD_SIZE; //based on 1 pkt/sec set in r_pktWindow[i]
|
||||
}
|
||||
|
||||
|
||||
int CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica, const int* abytes, size_t asize, int& bytesps)
|
||||
int srt::CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica, const int* abytes, size_t asize, int& bytesps)
|
||||
{
|
||||
// get median value, but cannot change the original value order in the window
|
||||
std::copy(window, window + asize, replica);
|
||||
|
@ -185,7 +191,7 @@ int CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica, cons
|
|||
// claculate speed, or return 0 if not enough valid value
|
||||
if (count > (asize >> 1))
|
||||
{
|
||||
bytes += (CPacket::SRT_DATA_HDR_SIZE * count); //Add protocol headers to bytes received
|
||||
bytes += (srt::CPacket::SRT_DATA_HDR_SIZE * count); //Add protocol headers to bytes received
|
||||
bytesps = (unsigned long)ceil(1000000.0 / (double(sum) / double(bytes)));
|
||||
return (int)ceil(1000000.0 / (sum / count));
|
||||
}
|
||||
|
@ -196,7 +202,7 @@ int CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica, cons
|
|||
}
|
||||
}
|
||||
|
||||
int CPktTimeWindowTools::getBandwidth_in(const int* window, int* replica, size_t psize)
|
||||
int srt::CPktTimeWindowTools::getBandwidth_in(const int* window, int* replica, size_t psize)
|
||||
{
|
||||
// This calculation does more-less the following:
|
||||
//
|
||||
|
|
123
trunk/3rdparty/srt-1-fit/srtcore/window.h
vendored
123
trunk/3rdparty/srt-1-fit/srtcore/window.h
vendored
|
@ -50,28 +50,31 @@ modified by
|
|||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_WINDOW_H__
|
||||
#define __UDT_WINDOW_H__
|
||||
#ifndef INC_SRT_WINDOW_H
|
||||
#define INC_SRT_WINDOW_H
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
#include "udt.h"
|
||||
#include "packet.h"
|
||||
#include "udt.h"
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
namespace ACKWindowTools
|
||||
{
|
||||
struct Seq
|
||||
{
|
||||
int32_t iACKSeqNo; // Seq. No. for the ACK packet
|
||||
int32_t iACK; // Data Seq. No. carried by the ACK packet
|
||||
uint64_t TimeStamp; // The timestamp when the ACK was sent
|
||||
int32_t iACKSeqNo; // Seq. No. of the ACK packet
|
||||
int32_t iACK; // Data packet Seq. No. carried by the ACK packet
|
||||
sync::steady_clock::time_point tsTimeStamp; // The timestamp when the ACK was sent
|
||||
};
|
||||
|
||||
void store(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int32_t seq, int32_t ack);
|
||||
int acknowledge(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int32_t seq, int32_t& r_ack);
|
||||
int acknowledge(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int32_t seq, int32_t& r_ack, const sync::steady_clock::time_point& currtime);
|
||||
}
|
||||
|
||||
template <size_t SIZE>
|
||||
|
@ -83,28 +86,30 @@ public:
|
|||
m_iHead(0),
|
||||
m_iTail(0)
|
||||
{
|
||||
m_aSeq[0].iACKSeqNo = -1;
|
||||
m_aSeq[0].iACKSeqNo = SRT_SEQNO_NONE;
|
||||
}
|
||||
|
||||
~CACKWindow() {}
|
||||
|
||||
/// Write an ACK record into the window.
|
||||
/// @param [in] seq ACK seq. no.
|
||||
/// @param [in] ack DATA ACK no.
|
||||
/// @param [in] seq Seq. No. of the ACK packet
|
||||
/// @param [in] ack Data packet Seq. No. carried by the ACK packet
|
||||
|
||||
void store(int32_t seq, int32_t ack)
|
||||
{
|
||||
return ACKWindowTools::store(m_aSeq, SIZE, m_iHead, m_iTail, seq, ack);
|
||||
}
|
||||
|
||||
/// Search the ACK-2 "seq" in the window, find out the DATA "ack" and caluclate RTT .
|
||||
/// @param [in] seq ACK-2 seq. no.
|
||||
/// @param [out] ack the DATA ACK no. that matches the ACK-2 no.
|
||||
/// @return RTT.
|
||||
/// Search the ACKACK "seq" in the window, find out the data packet "ack"
|
||||
/// and calculate RTT estimate based on the ACK/ACKACK pair
|
||||
/// @param [in] seq Seq. No. of the ACK packet carried within ACKACK
|
||||
/// @param [out] ack Acknowledged data packet Seq. No. from the ACK packet that matches the ACKACK
|
||||
/// @param [in] currtime The timestamp of ACKACK packet reception by the receiver
|
||||
/// @return RTT
|
||||
|
||||
int acknowledge(int32_t seq, int32_t& r_ack)
|
||||
int acknowledge(int32_t seq, int32_t& r_ack, const sync::steady_clock::time_point& currtime)
|
||||
{
|
||||
return ACKWindowTools::acknowledge(m_aSeq, SIZE, m_iHead, m_iTail, seq, r_ack);
|
||||
return ACKWindowTools::acknowledge(m_aSeq, SIZE, m_iHead, m_iTail, seq, r_ack, currtime);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -112,7 +117,7 @@ private:
|
|||
typedef ACKWindowTools::Seq Seq;
|
||||
|
||||
Seq m_aSeq[SIZE];
|
||||
int m_iHead; // Pointer to the lastest ACK record
|
||||
int m_iHead; // Pointer to the latest ACK record
|
||||
int m_iTail; // Pointer to the oldest ACK record
|
||||
|
||||
private:
|
||||
|
@ -143,24 +148,22 @@ public:
|
|||
m_iProbeWindowPtr(0),
|
||||
m_iLastSentTime(0),
|
||||
m_iMinPktSndInt(1000000),
|
||||
m_LastArrTime(),
|
||||
m_CurrArrTime(),
|
||||
m_ProbeTime(),
|
||||
m_Probe1Sequence(-1)
|
||||
m_tsLastArrTime(sync::steady_clock::now()),
|
||||
m_tsCurrArrTime(),
|
||||
m_tsProbeTime(),
|
||||
m_Probe1Sequence(SRT_SEQNO_NONE)
|
||||
{
|
||||
pthread_mutex_init(&m_lockPktWindow, NULL);
|
||||
pthread_mutex_init(&m_lockProbeWindow, NULL);
|
||||
m_LastArrTime = CTimer::getTime();
|
||||
// Exception: up to CUDT ctor
|
||||
sync::setupMutex(m_lockPktWindow, "PktWindow");
|
||||
sync::setupMutex(m_lockProbeWindow, "ProbeWindow");
|
||||
CPktTimeWindowTools::initializeWindowArrays(m_aPktWindow, m_aProbeWindow, m_aBytesWindow, ASIZE, PSIZE);
|
||||
}
|
||||
|
||||
~CPktTimeWindow()
|
||||
{
|
||||
pthread_mutex_destroy(&m_lockPktWindow);
|
||||
pthread_mutex_destroy(&m_lockProbeWindow);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
/// read the minimum packet sending interval.
|
||||
/// @return minimum packet sending interval (microseconds).
|
||||
|
||||
|
@ -169,19 +172,19 @@ public:
|
|||
/// Calculate the packets arrival speed.
|
||||
/// @return Packet arrival speed (packets per second).
|
||||
|
||||
int getPktRcvSpeed(ref_t<int> bytesps) const
|
||||
int getPktRcvSpeed(int& w_bytesps) const
|
||||
{
|
||||
// Lock access to the packet Window
|
||||
CGuard cg(m_lockPktWindow);
|
||||
sync::ScopedLock cg(m_lockPktWindow);
|
||||
|
||||
int pktReplica[ASIZE]; // packet information window (inter-packet time)
|
||||
return getPktRcvSpeed_in(m_aPktWindow, pktReplica, m_aBytesWindow, ASIZE, *bytesps);
|
||||
return getPktRcvSpeed_in(m_aPktWindow, pktReplica, m_aBytesWindow, ASIZE, (w_bytesps));
|
||||
}
|
||||
|
||||
int getPktRcvSpeed() const
|
||||
{
|
||||
int bytesps;
|
||||
return getPktRcvSpeed(Ref(bytesps));
|
||||
return getPktRcvSpeed((bytesps));
|
||||
}
|
||||
|
||||
/// Estimate the bandwidth.
|
||||
|
@ -190,7 +193,7 @@ public:
|
|||
int getBandwidth() const
|
||||
{
|
||||
// Lock access to the packet Window
|
||||
CGuard cg(m_lockProbeWindow);
|
||||
sync::ScopedLock cg(m_lockProbeWindow);
|
||||
|
||||
int probeReplica[PSIZE];
|
||||
return getBandwidth_in(m_aProbeWindow, probeReplica, PSIZE);
|
||||
|
@ -213,12 +216,12 @@ public:
|
|||
|
||||
void onPktArrival(int pktsz = 0)
|
||||
{
|
||||
CGuard cg(m_lockPktWindow);
|
||||
sync::ScopedLock cg(m_lockPktWindow);
|
||||
|
||||
m_CurrArrTime = CTimer::getTime();
|
||||
m_tsCurrArrTime = sync::steady_clock::now();
|
||||
|
||||
// record the packet interval between the current and the last one
|
||||
m_aPktWindow[m_iPktWindowPtr] = int(m_CurrArrTime - m_LastArrTime);
|
||||
m_aPktWindow[m_iPktWindowPtr] = (int) sync::count_microseconds(m_tsCurrArrTime - m_tsLastArrTime);
|
||||
m_aBytesWindow[m_iPktWindowPtr] = pktsz;
|
||||
|
||||
// the window is logically circular
|
||||
|
@ -227,7 +230,7 @@ public:
|
|||
m_iPktWindowPtr = 0;
|
||||
|
||||
// remember last packet arrival time
|
||||
m_LastArrTime = m_CurrArrTime;
|
||||
m_tsLastArrTime = m_tsCurrArrTime;
|
||||
}
|
||||
|
||||
/// Shortcut to test a packet for possible probe 1 or 2
|
||||
|
@ -259,11 +262,11 @@ public:
|
|||
// Reset the starting probe into "undefined", when
|
||||
// a packet has come as retransmitted before the
|
||||
// measurement at arrival of 17th could be taken.
|
||||
m_Probe1Sequence = -1;
|
||||
m_Probe1Sequence = SRT_SEQNO_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
m_ProbeTime = CTimer::getTime();
|
||||
m_tsProbeTime = sync::steady_clock::now();
|
||||
m_Probe1Sequence = pkt.m_iSeqNo; // Record the sequence where 16th packet probe was taken
|
||||
}
|
||||
|
||||
|
@ -279,26 +282,26 @@ public:
|
|||
// expected packet pair, behave as if the 17th packet was lost.
|
||||
|
||||
// no start point yet (or was reset) OR not very next packet
|
||||
if (m_Probe1Sequence == -1 || CSeqNo::incseq(m_Probe1Sequence) != pkt.m_iSeqNo)
|
||||
if (m_Probe1Sequence == SRT_SEQNO_NONE || CSeqNo::incseq(m_Probe1Sequence) != pkt.m_iSeqNo)
|
||||
return;
|
||||
|
||||
// Grab the current time before trying to acquire
|
||||
// a mutex. This might add extra delay and therefore
|
||||
// screw up the measurement.
|
||||
const uint64_t now = CTimer::getTime();
|
||||
const sync::steady_clock::time_point now = sync::steady_clock::now();
|
||||
|
||||
// Lock access to the packet Window
|
||||
CGuard cg(m_lockProbeWindow);
|
||||
sync::ScopedLock cg(m_lockProbeWindow);
|
||||
|
||||
m_CurrArrTime = now;
|
||||
m_tsCurrArrTime = now;
|
||||
|
||||
// Reset the starting probe to prevent checking if the
|
||||
// measurement was already taken.
|
||||
m_Probe1Sequence = -1;
|
||||
m_Probe1Sequence = SRT_SEQNO_NONE;
|
||||
|
||||
// record the probing packets interval
|
||||
// Adjust the time for what a complete packet would have take
|
||||
const int64_t timediff = m_CurrArrTime - m_ProbeTime;
|
||||
const int64_t timediff = sync::count_microseconds(m_tsCurrArrTime - m_tsProbeTime);
|
||||
const int64_t timediff_times_pl_size = timediff * CPacket::SRT_MAX_PAYLOAD_SIZE;
|
||||
|
||||
// Let's take it simpler than it is coded here:
|
||||
|
@ -312,11 +315,11 @@ public:
|
|||
// the ETH+IP+UDP+SRT header part elliminates the constant packet delivery time influence.
|
||||
//
|
||||
const size_t pktsz = pkt.getLength();
|
||||
m_aProbeWindow[m_iProbeWindowPtr] = pktsz ? timediff_times_pl_size / pktsz : int(timediff);
|
||||
m_aProbeWindow[m_iProbeWindowPtr] = pktsz ? int(timediff_times_pl_size / pktsz) : int(timediff);
|
||||
|
||||
// OLD CODE BEFORE BSTATS:
|
||||
// record the probing packets interval
|
||||
// m_aProbeWindow[m_iProbeWindowPtr] = int(m_CurrArrTime - m_ProbeTime);
|
||||
// m_aProbeWindow[m_iProbeWindowPtr] = int(m_tsCurrArrTime - m_tsProbeTime);
|
||||
|
||||
// the window is logically circular
|
||||
++ m_iProbeWindowPtr;
|
||||
|
@ -324,29 +327,29 @@ public:
|
|||
m_iProbeWindowPtr = 0;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
int m_aPktWindow[ASIZE]; // packet information window (inter-packet time)
|
||||
int m_aBytesWindow[ASIZE]; //
|
||||
int m_iPktWindowPtr; // position pointer of the packet info. window.
|
||||
mutable pthread_mutex_t m_lockPktWindow; // used to synchronize access to the packet window
|
||||
int m_aPktWindow[ASIZE]; // Packet information window (inter-packet time)
|
||||
int m_aBytesWindow[ASIZE];
|
||||
int m_iPktWindowPtr; // Position pointer of the packet info. window
|
||||
mutable sync::Mutex m_lockPktWindow; // Used to synchronize access to the packet window
|
||||
|
||||
int m_aProbeWindow[PSIZE]; // record inter-packet time for probing packet pairs
|
||||
int m_iProbeWindowPtr; // position pointer to the probing window
|
||||
mutable pthread_mutex_t m_lockProbeWindow; // used to synchronize access to the probe window
|
||||
int m_aProbeWindow[PSIZE]; // Record inter-packet time for probing packet pairs
|
||||
int m_iProbeWindowPtr; // Position pointer to the probing window
|
||||
mutable sync::Mutex m_lockProbeWindow; // Used to synchronize access to the probe window
|
||||
|
||||
int m_iLastSentTime; // last packet sending time
|
||||
int m_iMinPktSndInt; // Minimum packet sending interval
|
||||
int m_iLastSentTime; // Last packet sending time
|
||||
int m_iMinPktSndInt; // Minimum packet sending interval
|
||||
|
||||
uint64_t m_LastArrTime; // last packet arrival time
|
||||
uint64_t m_CurrArrTime; // current packet arrival time
|
||||
uint64_t m_ProbeTime; // arrival time of the first probing packet
|
||||
int32_t m_Probe1Sequence; // sequence number for which the arrival time was notified
|
||||
sync::steady_clock::time_point m_tsLastArrTime; // Last packet arrival time
|
||||
sync::steady_clock::time_point m_tsCurrArrTime; // Current packet arrival time
|
||||
sync::steady_clock::time_point m_tsProbeTime; // Arrival time of the first probing packet
|
||||
int32_t m_Probe1Sequence; // Sequence number for which the arrival time was notified
|
||||
|
||||
private:
|
||||
CPktTimeWindow(const CPktTimeWindow&);
|
||||
CPktTimeWindow &operator=(const CPktTimeWindow&);
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue