Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core] Fix hang up on not enough space in the RCV buffer. #2745

Merged
merged 10 commits into from Aug 8, 2023
20 changes: 12 additions & 8 deletions srtcore/core.cpp
Expand Up @@ -7904,7 +7904,7 @@ int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size)
SRT_ASSERT(ctrlpkt.getMsgTimeStamp() != 0);
int nbsent = 0;
int local_prevack = 0;

bool sendAckAgain = false; //Send ack again after a buffer full was detected
#if ENABLE_HEAVY_LOGGING
struct SaveBack
{
Expand All @@ -7927,12 +7927,16 @@ int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size)
// The TSBPD thread may change the first lost sequence record (TLPKTDROP).
// To avoid it the m_RcvBufferLock has to be acquired.
UniqueLock bufflock(m_RcvBufferLock);

if(m_bBufferWasFull && getAvailRcvBufferSizeNoLock() > 0)
{
sendAckAgain = true;
m_bBufferWasFull = false;
maxsharabayko marked this conversation as resolved.
Show resolved Hide resolved
}
int32_t ack; // First unacknowledged packet sequence number (acknowledge up to ack).
if (!getFirstNoncontSequence((ack), (reason)))
return nbsent;

if (m_iRcvLastAckAck == ack)
if (m_iRcvLastAckAck == ack && !sendAckAgain)
{
HLOGC(xtlog.Debug,
log << CONID() << "sendCtrl(UMSG_ACK): last ACK %" << ack << "(" << reason << ") == last ACKACK");
Expand Down Expand Up @@ -8101,7 +8105,7 @@ int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size)
// [[using locked(m_RcvBufferLock)]];

// Send out the ACK only if has not been received by the sender before
if (CSeqNo::seqcmp(m_iRcvLastAck, m_iRcvLastAckAck) > 0)
if (CSeqNo::seqcmp(m_iRcvLastAck, m_iRcvLastAckAck) > 0 || sendAckAgain)
{
// NOTE: The BSTATS feature turns on extra fields above size 6
// also known as ACKD_TOTAL_SIZE_VER100.
Expand All @@ -8117,10 +8121,10 @@ int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size)
data[ACKD_RTT] = m_iSRTT;
data[ACKD_RTTVAR] = m_iRTTVar;
data[ACKD_BUFFERLEFT] = (int) getAvailRcvBufferSizeNoLock();
// a minimum flow window of 2 is used, even if buffer is full, to break potential deadlock
if (data[ACKD_BUFFERLEFT] < 2)
data[ACKD_BUFFERLEFT] = 2;

if (data[ACKD_BUFFERLEFT] == 0)
{
m_bBufferWasFull = true;
}
maxsharabayko marked this conversation as resolved.
Show resolved Hide resolved
if (steady_clock::now() - m_tsLastAckTime > m_tdACKInterval)
{
int rcvRate;
Expand Down
2 changes: 1 addition & 1 deletion srtcore/core.h
Expand Up @@ -934,7 +934,7 @@ class CUDT
int32_t m_iAckSeqNo; // Last ACK sequence number
sync::atomic<int32_t> m_iRcvCurrSeqNo; // (RCV) Largest received sequence number. RcvQTh, TSBPDTh.
int32_t m_iRcvCurrPhySeqNo; // Same as m_iRcvCurrSeqNo, but physical only (disregarding a filter)

bool m_bBufferWasFull; // Indicate that RX buffer was full last time a ack was sent
maxsharabayko marked this conversation as resolved.
Show resolved Hide resolved
int32_t m_iPeerISN; // Initial Sequence Number of the peer side

uint32_t m_uPeerSrtVersion;
Expand Down