From 968c9f9613558be99e4e58e9908a6feeade479f2 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 2 Aug 2024 14:10:20 +0200 Subject: [PATCH] [core] Set ACK position based on RCV buffer first nonread seqno (#2931). --- srtcore/buffer_rcv.cpp | 6 ++++++ srtcore/buffer_rcv.h | 5 +++++ srtcore/core.cpp | 22 ++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/srtcore/buffer_rcv.cpp b/srtcore/buffer_rcv.cpp index 2ec42487d..363bd7e9c 100644 --- a/srtcore/buffer_rcv.cpp +++ b/srtcore/buffer_rcv.cpp @@ -760,6 +760,12 @@ CRcvBuffer::PacketInfo CRcvBuffer::getFirstReadablePacketInfo(time_point time_no return unreadableInfo; } +int32_t CRcvBuffer::getFirstNonreadSeqNo() const +{ + const int offset = offPos(m_iStartPos, m_iFirstNonreadPos); + return CSeqNo::incseq(m_iStartSeqNo, offset); +} + void CRcvBuffer::countBytes(int pkts, int bytes) { ScopedLock lock(m_BytesCountLock); diff --git a/srtcore/buffer_rcv.h b/srtcore/buffer_rcv.h index f783ac2a2..c5fca428b 100644 --- a/srtcore/buffer_rcv.h +++ b/srtcore/buffer_rcv.h @@ -187,6 +187,11 @@ class CRcvBuffer PacketInfo getFirstReadablePacketInfo(time_point time_now) const; + /// @brief Get the sequence number of the first packet that can't be read + /// (either because it is missing, or because it is a part of a bigger message + /// that is not fully available yet). + int32_t getFirstNonreadSeqNo() const; + /// Get information on packets available to be read. /// @returns a pair of sequence numbers (first available; first unavailable). /// diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 908bf748c..9715a209e 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -8023,6 +8023,27 @@ void srt::CUDT::sendCtrl(UDTMessageType pkttype, const int32_t* lparam, void* rp // [[using locked(m_RcvBufferLock)]] bool srt::CUDT::getFirstNoncontSequence(int32_t& w_seq, string& w_log_reason) { + if (m_config.bTSBPD || !m_config.bMessageAPI) + { + // The getFirstNonreadSeqNo() function retuens the sequence number of the first packet + // that cannot be read. In cases when a message can consist of several data packets, + // an existing packet of partially available message also cannot be read. + // If TSBPD mode is enabled, a message must consist of a single data packet only. + w_seq = m_pRcvBuffer->getFirstNonreadSeqNo(); + + const int32_t iNextSeqNo = CSeqNo::incseq(m_iRcvCurrSeqNo); + SRT_ASSERT(CSeqNo::seqcmp(w_seq, iNextSeqNo) <= 0); + w_log_reason = iNextSeqNo != w_seq ? "first lost" : "expected next"; + + if (CSeqNo::seqcmp(w_seq, iNextSeqNo) > 0) + { + LOGC(xtlog.Error, log << "IPE: NONCONT-SEQUENCE: RCV buffer first non-read %" << w_seq << ", RCV latest seqno %" << m_iRcvCurrSeqNo); + w_seq = iNextSeqNo; + } + + return true; + } + { ScopedLock losslock (m_RcvLossLock); const int32_t seq = m_pRcvLossList->getFirstLostSeq(); @@ -8070,6 +8091,7 @@ int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size) // since the last full ACK. It should unblock the sender to proceed further. const bool bNeedFullAck = (m_bBufferWasFull && getAvailRcvBufferSizeNoLock() > 0); int32_t ack; // First unacknowledged packet sequence number (acknowledge up to ack). + if (!getFirstNoncontSequence((ack), (reason))) return nbsent;