123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949 |
- /*
- * 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 01/22/2011
- modified by
- Haivision Systems Inc.
- *****************************************************************************/
- #include "platform_sys.h"
- #include "list.h"
- #include "packet.h"
- #include "logging.h"
- // Use "inline namespace" in C++11
- namespace srt_logging
- {
- extern Logger qrlog;
- extern Logger qslog;
- extern Logger tslog;
- }
- using srt_logging::qrlog;
- using srt_logging::qslog;
- using srt_logging::tslog;
- using namespace srt::sync;
- srt::CSndLossList::CSndLossList(int size)
- : m_caSeq()
- , m_iHead(-1)
- , m_iLength(0)
- , m_iSize(size)
- , m_iLastInsertPos(-1)
- , m_ListLock()
- {
- m_caSeq = new Seq[size];
- // -1 means there is no data in the node
- for (int i = 0; i < size; ++i)
- {
- m_caSeq[i].seqstart = SRT_SEQNO_NONE;
- m_caSeq[i].seqend = SRT_SEQNO_NONE;
- }
- // sender list needs mutex protection
- setupMutex(m_ListLock, "LossList");
- }
- srt::CSndLossList::~CSndLossList()
- {
- delete[] m_caSeq;
- releaseMutex(m_ListLock);
- }
- void srt::CSndLossList::traceState() const
- {
- int pos = m_iHead;
- while (pos != SRT_SEQNO_NONE)
- {
- std::cout << pos << ":[" << m_caSeq[pos].seqstart;
- if (m_caSeq[pos].seqend != SRT_SEQNO_NONE)
- std::cout << ", " << m_caSeq[pos].seqend;
- std::cout << "], ";
- pos = m_caSeq[pos].inext;
- }
- std::cout << "\n";
- }
- int srt::CSndLossList::insert(int32_t seqno1, int32_t seqno2)
- {
- if (seqno1 < 0 || seqno2 < 0 ) {
- LOGC(qslog.Error, log << "IPE: Tried to insert negative seqno " << seqno1 << ":" << seqno2
- << " into sender's loss list. Ignoring.");
- return 0;
- }
- const int inserted_range = CSeqNo::seqlen(seqno1, seqno2);
- if (inserted_range <= 0 || inserted_range >= m_iSize) {
- LOGC(qslog.Error, log << "IPE: Tried to insert too big range of seqno: " << inserted_range << ". Ignoring. "
- << "seqno " << seqno1 << ":" << seqno2);
- return 0;
- }
- ScopedLock listguard(m_ListLock);
- if (m_iLength == 0)
- {
- insertHead(0, seqno1, seqno2);
- return m_iLength;
- }
- // Find the insert position in the non-empty list
- const int origlen = m_iLength;
- const int offset = CSeqNo::seqoff(m_caSeq[m_iHead].seqstart, seqno1);
- if (offset >= m_iSize)
- {
- LOGC(qslog.Error, log << "IPE: New loss record is too far from the first record. Ignoring. "
- << "First loss seqno " << m_caSeq[m_iHead].seqstart
- << ", insert seqno " << seqno1 << ":" << seqno2);
- return 0;
- }
- int loc = (m_iHead + offset + m_iSize) % m_iSize;
- if (loc < 0)
- {
- const int offset_seqno2 = CSeqNo::seqoff(m_caSeq[m_iHead].seqstart, seqno2);
- const int loc_seqno2 = (m_iHead + offset_seqno2 + m_iSize) % m_iSize;
- if (loc_seqno2 < 0)
- {
- // The size of the CSndLossList should be at least the size of the flow window.
- // It means that all the packets sender has sent should fit within m_iSize.
- // If the new loss does not fit, there is some error.
- LOGC(qslog.Error, log << "IPE: New loss record is too old. Ignoring. "
- << "First loss seqno " << m_caSeq[m_iHead].seqstart
- << ", insert seqno " << seqno1 << ":" << seqno2);
- return 0;
- }
- loc = loc_seqno2;
- }
- if (offset < 0)
- {
- insertHead(loc, seqno1, seqno2);
- }
- else if (offset > 0)
- {
- if (seqno1 == m_caSeq[loc].seqstart)
- {
- const bool updated = updateElement(loc, seqno1, seqno2);
- if (!updated)
- return 0;
- }
- else
- {
- // Find the prior node.
- // It should be the highest sequence number less than seqno1.
- // 1. Start the search either from m_iHead, or from m_iLastInsertPos
- int i = m_iHead;
- if ((m_iLastInsertPos != -1) && (CSeqNo::seqcmp(m_caSeq[m_iLastInsertPos].seqstart, seqno1) < 0))
- i = m_iLastInsertPos;
- // 2. Find the highest sequence number less than seqno1.
- while (m_caSeq[i].inext != -1 && CSeqNo::seqcmp(m_caSeq[m_caSeq[i].inext].seqstart, seqno1) < 0)
- i = m_caSeq[i].inext;
- // 3. Check if seqno1 overlaps with (seqbegin, seqend)
- const int seqend = m_caSeq[i].seqend == SRT_SEQNO_NONE ? m_caSeq[i].seqstart : m_caSeq[i].seqend;
- if (CSeqNo::seqcmp(seqend, seqno1) < 0 && CSeqNo::incseq(seqend) != seqno1)
- {
- // No overlap
- // TODO: Here we should actually insert right after i, not at loc.
- insertAfter(loc, i, seqno1, seqno2);
- }
- else
- {
- // TODO: Replace with updateElement(i, seqno1, seqno2).
- // Some changes to updateElement(..) are required.
- m_iLastInsertPos = i;
- if (CSeqNo::seqcmp(seqend, seqno2) >= 0)
- return 0;
- // overlap, coalesce with prior node, insert(3, 7) to [2, 5], ... becomes [2, 7]
- m_iLength += CSeqNo::seqlen(seqend, seqno2) - 1;
- m_caSeq[i].seqend = seqno2;
- loc = i;
- }
- }
- }
- else // offset == 0, loc == m_iHead
- {
- const bool updated = updateElement(m_iHead, seqno1, seqno2);
- if (!updated)
- return 0;
- }
- coalesce(loc);
- return m_iLength - origlen;
- }
- void srt::CSndLossList::removeUpTo(int32_t seqno)
- {
- ScopedLock listguard(m_ListLock);
- if (0 == m_iLength)
- return;
- // Remove all from the head pointer to a node with a larger seq. no. or the list is empty
- int offset = CSeqNo::seqoff(m_caSeq[m_iHead].seqstart, seqno);
- int loc = (m_iHead + offset + m_iSize) % m_iSize;
- if (0 == offset)
- {
- // It is the head. Remove the head and point to the next node
- loc = (loc + 1) % m_iSize;
- if (SRT_SEQNO_NONE == m_caSeq[m_iHead].seqend)
- loc = m_caSeq[m_iHead].inext;
- else
- {
- m_caSeq[loc].seqstart = CSeqNo::incseq(seqno);
- if (CSeqNo::seqcmp(m_caSeq[m_iHead].seqend, CSeqNo::incseq(seqno)) > 0)
- m_caSeq[loc].seqend = m_caSeq[m_iHead].seqend;
- m_caSeq[m_iHead].seqend = SRT_SEQNO_NONE;
- m_caSeq[loc].inext = m_caSeq[m_iHead].inext;
- }
- m_caSeq[m_iHead].seqstart = SRT_SEQNO_NONE;
- if (m_iLastInsertPos == m_iHead)
- m_iLastInsertPos = -1;
- m_iHead = loc;
- m_iLength--;
- }
- else if (offset > 0)
- {
- int h = m_iHead;
- if (seqno == m_caSeq[loc].seqstart)
- {
- // target node is not empty, remove part/all of the seqno in the node.
- int temp = loc;
- loc = (loc + 1) % m_iSize;
- if (SRT_SEQNO_NONE == m_caSeq[temp].seqend)
- m_iHead = m_caSeq[temp].inext;
- else
- {
- // remove part, e.g., [3, 7] becomes [], [4, 7] after remove(3)
- m_caSeq[loc].seqstart = CSeqNo::incseq(seqno);
- if (CSeqNo::seqcmp(m_caSeq[temp].seqend, m_caSeq[loc].seqstart) > 0)
- m_caSeq[loc].seqend = m_caSeq[temp].seqend;
- m_iHead = loc;
- m_caSeq[loc].inext = m_caSeq[temp].inext;
- m_caSeq[temp].inext = loc;
- m_caSeq[temp].seqend = SRT_SEQNO_NONE;
- }
- }
- else
- {
- // target node is empty, check prior node
- int i = m_iHead;
- while ((-1 != m_caSeq[i].inext) && (CSeqNo::seqcmp(m_caSeq[m_caSeq[i].inext].seqstart, seqno) < 0))
- i = m_caSeq[i].inext;
- loc = (loc + 1) % m_iSize;
- if (SRT_SEQNO_NONE == m_caSeq[i].seqend)
- m_iHead = m_caSeq[i].inext;
- else if (CSeqNo::seqcmp(m_caSeq[i].seqend, seqno) > 0)
- {
- // remove part/all seqno in the prior node
- m_caSeq[loc].seqstart = CSeqNo::incseq(seqno);
- if (CSeqNo::seqcmp(m_caSeq[i].seqend, m_caSeq[loc].seqstart) > 0)
- m_caSeq[loc].seqend = m_caSeq[i].seqend;
- m_caSeq[i].seqend = seqno;
- m_caSeq[loc].inext = m_caSeq[i].inext;
- m_caSeq[i].inext = loc;
- m_iHead = loc;
- }
- else
- m_iHead = m_caSeq[i].inext;
- }
- // Remove all nodes prior to the new head
- while (h != m_iHead)
- {
- if (m_caSeq[h].seqend != SRT_SEQNO_NONE)
- {
- m_iLength -= CSeqNo::seqlen(m_caSeq[h].seqstart, m_caSeq[h].seqend);
- m_caSeq[h].seqend = SRT_SEQNO_NONE;
- }
- else
- m_iLength--;
- m_caSeq[h].seqstart = SRT_SEQNO_NONE;
- if (m_iLastInsertPos == h)
- m_iLastInsertPos = -1;
- h = m_caSeq[h].inext;
- }
- }
- }
- int srt::CSndLossList::getLossLength() const
- {
- ScopedLock listguard(m_ListLock);
- return m_iLength;
- }
- int32_t srt::CSndLossList::popLostSeq()
- {
- ScopedLock listguard(m_ListLock);
- if (0 == m_iLength)
- {
- SRT_ASSERT(m_iHead == -1);
- return SRT_SEQNO_NONE;
- }
- if (m_iLastInsertPos == m_iHead)
- m_iLastInsertPos = -1;
- // return the first loss seq. no.
- const int32_t seqno = m_caSeq[m_iHead].seqstart;
- // head moves to the next node
- if (SRT_SEQNO_NONE == m_caSeq[m_iHead].seqend)
- {
- //[3, SRT_SEQNO_NONE] becomes [], and head moves to next node in the list
- m_caSeq[m_iHead].seqstart = SRT_SEQNO_NONE;
- m_iHead = m_caSeq[m_iHead].inext;
- }
- else
- {
- // shift to next node, e.g., [3, 7] becomes [], [4, 7]
- int loc = (m_iHead + 1) % m_iSize;
- m_caSeq[loc].seqstart = CSeqNo::incseq(seqno);
- if (CSeqNo::seqcmp(m_caSeq[m_iHead].seqend, m_caSeq[loc].seqstart) > 0)
- m_caSeq[loc].seqend = m_caSeq[m_iHead].seqend;
- m_caSeq[m_iHead].seqstart = SRT_SEQNO_NONE;
- m_caSeq[m_iHead].seqend = SRT_SEQNO_NONE;
- m_caSeq[loc].inext = m_caSeq[m_iHead].inext;
- m_iHead = loc;
- }
- m_iLength--;
- return seqno;
- }
- void srt::CSndLossList::insertHead(int pos, int32_t seqno1, int32_t seqno2)
- {
- SRT_ASSERT(pos >= 0);
- m_caSeq[pos].seqstart = seqno1;
- SRT_ASSERT(m_caSeq[pos].seqend == SRT_SEQNO_NONE);
- if (seqno2 != seqno1)
- m_caSeq[pos].seqend = seqno2;
- // new node becomes head
- m_caSeq[pos].inext = m_iHead;
- m_iHead = pos;
- m_iLastInsertPos = pos;
- m_iLength += CSeqNo::seqlen(seqno1, seqno2);
- }
- void srt::CSndLossList::insertAfter(int pos, int pos_after, int32_t seqno1, int32_t seqno2)
- {
- m_caSeq[pos].seqstart = seqno1;
- SRT_ASSERT(m_caSeq[pos].seqend == SRT_SEQNO_NONE);
- if (seqno2 != seqno1)
- m_caSeq[pos].seqend = seqno2;
- m_caSeq[pos].inext = m_caSeq[pos_after].inext;
- m_caSeq[pos_after].inext = pos;
- m_iLastInsertPos = pos;
- m_iLength += CSeqNo::seqlen(seqno1, seqno2);
- }
- void srt::CSndLossList::coalesce(int loc)
- {
- // coalesce with next node. E.g., [3, 7], ..., [6, 9] becomes [3, 9]
- while ((m_caSeq[loc].inext != -1) && (m_caSeq[loc].seqend != SRT_SEQNO_NONE))
- {
- const int i = m_caSeq[loc].inext;
- if (CSeqNo::seqcmp(m_caSeq[i].seqstart, CSeqNo::incseq(m_caSeq[loc].seqend)) > 0)
- break;
- // coalesce if there is overlap
- if (m_caSeq[i].seqend != SRT_SEQNO_NONE)
- {
- if (CSeqNo::seqcmp(m_caSeq[i].seqend, m_caSeq[loc].seqend) > 0)
- {
- if (CSeqNo::seqcmp(m_caSeq[loc].seqend, m_caSeq[i].seqstart) >= 0)
- m_iLength -= CSeqNo::seqlen(m_caSeq[i].seqstart, m_caSeq[loc].seqend);
- m_caSeq[loc].seqend = m_caSeq[i].seqend;
- }
- else
- m_iLength -= CSeqNo::seqlen(m_caSeq[i].seqstart, m_caSeq[i].seqend);
- }
- else
- {
- if (m_caSeq[i].seqstart == CSeqNo::incseq(m_caSeq[loc].seqend))
- m_caSeq[loc].seqend = m_caSeq[i].seqstart;
- else
- m_iLength--;
- }
- m_caSeq[i].seqstart = SRT_SEQNO_NONE;
- m_caSeq[i].seqend = SRT_SEQNO_NONE;
- m_caSeq[loc].inext = m_caSeq[i].inext;
- }
- }
- bool srt::CSndLossList::updateElement(int pos, int32_t seqno1, int32_t seqno2)
- {
- m_iLastInsertPos = pos;
- if (seqno2 == SRT_SEQNO_NONE || seqno2 == seqno1)
- return false;
- if (m_caSeq[pos].seqend == SRT_SEQNO_NONE)
- {
- m_iLength += CSeqNo::seqlen(seqno1, seqno2) - 1;
- m_caSeq[pos].seqend = seqno2;
- return true;
- }
- // seqno2 <= m_caSeq[pos].seqend
- if (CSeqNo::seqcmp(seqno2, m_caSeq[pos].seqend) <= 0)
- return false;
- // seqno2 > m_caSeq[pos].seqend
- m_iLength += CSeqNo::seqlen(m_caSeq[pos].seqend, seqno2) - 1;
- m_caSeq[pos].seqend = seqno2;
- return true;
- }
- ////////////////////////////////////////////////////////////////////////////////
- srt::CRcvLossList::CRcvLossList(int size)
- : m_caSeq()
- , m_iHead(-1)
- , m_iTail(-1)
- , m_iLength(0)
- , m_iSize(size)
- , m_iLargestSeq(SRT_SEQNO_NONE)
- {
- m_caSeq = new Seq[m_iSize];
- // -1 means there is no data in the node
- for (int i = 0; i < size; ++i)
- {
- m_caSeq[i].seqstart = SRT_SEQNO_NONE;
- m_caSeq[i].seqend = SRT_SEQNO_NONE;
- }
- }
- srt::CRcvLossList::~CRcvLossList()
- {
- delete[] m_caSeq;
- }
- int srt::CRcvLossList::insert(int32_t seqno1, int32_t seqno2)
- {
- // Data to be inserted must be larger than all those in the list
- if (m_iLargestSeq != SRT_SEQNO_NONE && CSeqNo::seqcmp(seqno1, m_iLargestSeq) <= 0)
- {
- if (CSeqNo::seqcmp(seqno2, m_iLargestSeq) > 0)
- {
- LOGC(qrlog.Warn,
- log << "RCV-LOSS/insert: seqno1=" << seqno1 << " too small, adjust to "
- << CSeqNo::incseq(m_iLargestSeq));
- seqno1 = CSeqNo::incseq(m_iLargestSeq);
- }
- else
- {
- LOGC(qrlog.Warn,
- log << "RCV-LOSS/insert: (" << seqno1 << "," << seqno2
- << ") to be inserted is too small: m_iLargestSeq=" << m_iLargestSeq << ", m_iLength=" << m_iLength
- << ", m_iHead=" << m_iHead << ", m_iTail=" << m_iTail << " -- REJECTING");
- return 0;
- }
- }
- m_iLargestSeq = seqno2;
- if (0 == m_iLength)
- {
- // insert data into an empty list
- m_iHead = 0;
- m_iTail = 0;
- m_caSeq[m_iHead].seqstart = seqno1;
- if (seqno2 != seqno1)
- m_caSeq[m_iHead].seqend = seqno2;
- m_caSeq[m_iHead].inext = -1;
- m_caSeq[m_iHead].iprior = -1;
- const int n = CSeqNo::seqlen(seqno1, seqno2);
- m_iLength += n;
- return n;
- }
- // otherwise searching for the position where the node should be
- const int offset = CSeqNo::seqoff(m_caSeq[m_iHead].seqstart, seqno1);
- if (offset < 0)
- {
- LOGC(qrlog.Error,
- log << "RCV-LOSS/insert: IPE: new LOSS %(" << seqno1 << "-" << seqno2 << ") PREDATES HEAD %"
- << m_caSeq[m_iHead].seqstart << " -- REJECTING");
- return -1;
- }
- int loc = (m_iHead + offset) % m_iSize;
- if ((SRT_SEQNO_NONE != m_caSeq[m_iTail].seqend) && (CSeqNo::incseq(m_caSeq[m_iTail].seqend) == seqno1))
- {
- // coalesce with prior node, e.g., [2, 5], [6, 7] becomes [2, 7]
- loc = m_iTail;
- m_caSeq[loc].seqend = seqno2;
- }
- else
- {
- // create new node
- m_caSeq[loc].seqstart = seqno1;
- if (seqno2 != seqno1)
- m_caSeq[loc].seqend = seqno2;
- m_caSeq[m_iTail].inext = loc;
- m_caSeq[loc].iprior = m_iTail;
- m_caSeq[loc].inext = -1;
- m_iTail = loc;
- }
- const int n = CSeqNo::seqlen(seqno1, seqno2);
- m_iLength += n;
- return n;
- }
- bool srt::CRcvLossList::remove(int32_t seqno)
- {
- if (m_iLargestSeq == SRT_SEQNO_NONE || CSeqNo::seqcmp(seqno, m_iLargestSeq) > 0)
- m_iLargestSeq = seqno;
- if (0 == m_iLength)
- return false;
- // locate the position of "seqno" in the list
- int offset = CSeqNo::seqoff(m_caSeq[m_iHead].seqstart, seqno);
- if (offset < 0)
- return false;
- int loc = (m_iHead + offset) % m_iSize;
- if (seqno == m_caSeq[loc].seqstart)
- {
- // This is a seq. no. that starts the loss sequence
- if (SRT_SEQNO_NONE == m_caSeq[loc].seqend)
- {
- // there is only 1 loss in the sequence, delete it from the node
- if (m_iHead == loc)
- {
- m_iHead = m_caSeq[m_iHead].inext;
- if (-1 != m_iHead)
- m_caSeq[m_iHead].iprior = -1;
- else
- m_iTail = -1;
- }
- else
- {
- m_caSeq[m_caSeq[loc].iprior].inext = m_caSeq[loc].inext;
- if (-1 != m_caSeq[loc].inext)
- m_caSeq[m_caSeq[loc].inext].iprior = m_caSeq[loc].iprior;
- else
- m_iTail = m_caSeq[loc].iprior;
- }
- m_caSeq[loc].seqstart = SRT_SEQNO_NONE;
- }
- else
- {
- // there are more than 1 loss in the sequence
- // move the node to the next and update the starter as the next loss inSeqNo(seqno)
- // find next node
- int i = (loc + 1) % m_iSize;
- // remove the "seqno" and change the starter as next seq. no.
- m_caSeq[i].seqstart = CSeqNo::incseq(m_caSeq[loc].seqstart);
- // process the sequence end
- if (CSeqNo::seqcmp(m_caSeq[loc].seqend, CSeqNo::incseq(m_caSeq[loc].seqstart)) > 0)
- m_caSeq[i].seqend = m_caSeq[loc].seqend;
- // remove the current node
- m_caSeq[loc].seqstart = SRT_SEQNO_NONE;
- m_caSeq[loc].seqend = SRT_SEQNO_NONE;
- // update list pointer
- m_caSeq[i].inext = m_caSeq[loc].inext;
- m_caSeq[i].iprior = m_caSeq[loc].iprior;
- if (m_iHead == loc)
- m_iHead = i;
- else
- m_caSeq[m_caSeq[i].iprior].inext = i;
- if (m_iTail == loc)
- m_iTail = i;
- else
- m_caSeq[m_caSeq[i].inext].iprior = i;
- }
- m_iLength--;
- return true;
- }
- // There is no loss sequence in the current position
- // the "seqno" may be contained in a previous node
- // searching previous node
- int i = (loc - 1 + m_iSize) % m_iSize;
- while (SRT_SEQNO_NONE == m_caSeq[i].seqstart)
- i = (i - 1 + m_iSize) % m_iSize;
- // not contained in this node, return
- if ((SRT_SEQNO_NONE == m_caSeq[i].seqend) || (CSeqNo::seqcmp(seqno, m_caSeq[i].seqend) > 0))
- return false;
- if (seqno == m_caSeq[i].seqend)
- {
- // it is the sequence end
- if (seqno == CSeqNo::incseq(m_caSeq[i].seqstart))
- m_caSeq[i].seqend = SRT_SEQNO_NONE;
- else
- m_caSeq[i].seqend = CSeqNo::decseq(seqno);
- }
- else
- {
- // split the sequence
- // construct the second sequence from CSeqNo::incseq(seqno) to the original sequence end
- // located at "loc + 1"
- loc = (loc + 1) % m_iSize;
- m_caSeq[loc].seqstart = CSeqNo::incseq(seqno);
- if (CSeqNo::seqcmp(m_caSeq[i].seqend, m_caSeq[loc].seqstart) > 0)
- m_caSeq[loc].seqend = m_caSeq[i].seqend;
- // the first (original) sequence is between the original sequence start to CSeqNo::decseq(seqno)
- if (seqno == CSeqNo::incseq(m_caSeq[i].seqstart))
- m_caSeq[i].seqend = SRT_SEQNO_NONE;
- else
- m_caSeq[i].seqend = CSeqNo::decseq(seqno);
- // update the list pointer
- m_caSeq[loc].inext = m_caSeq[i].inext;
- m_caSeq[i].inext = loc;
- m_caSeq[loc].iprior = i;
- if (m_iTail == i)
- m_iTail = loc;
- else
- m_caSeq[m_caSeq[loc].inext].iprior = loc;
- }
- m_iLength--;
- return true;
- }
- bool srt::CRcvLossList::remove(int32_t seqno1, int32_t seqno2)
- {
- if (CSeqNo::seqcmp(seqno1, seqno2) > 0)
- {
- return false;
- }
- for (int32_t i = seqno1; CSeqNo::seqcmp(i, seqno2) <= 0; i = CSeqNo::incseq(i))
- {
- remove(i);
- }
- return true;
- }
- int32_t srt::CRcvLossList::removeUpTo(int32_t seqno_last)
- {
- int32_t first = getFirstLostSeq();
- if (first == SRT_SEQNO_NONE)
- {
- //HLOGC(tslog.Debug, log << "rcv-loss: DROP to %" << seqno_last << " - empty list");
- return first; // empty, so nothing to remove
- }
- if (CSeqNo::seqcmp(seqno_last, first) < 0)
- {
- //HLOGC(tslog.Debug, log << "rcv-loss: DROP to %" << seqno_last << " - first %" << first << " is newer, exitting");
- return first; // seqno_last older than first - nothing to remove
- }
- HLOGC(tslog.Debug, log << "rcv-loss: DROP to %" << seqno_last << " ...");
- // NOTE: seqno_last is past-the-end here. Removed are only seqs
- // that are earlier than this.
- for (int32_t i = first; CSeqNo::seqcmp(i, seqno_last) <= 0; i = CSeqNo::incseq(i))
- {
- //HLOGC(tslog.Debug, log << "... removing %" << i);
- remove(i);
- }
- return first;
- }
- bool srt::CRcvLossList::find(int32_t seqno1, int32_t seqno2) const
- {
- if (0 == m_iLength)
- return false;
- int p = m_iHead;
- while (-1 != p)
- {
- if ((CSeqNo::seqcmp(m_caSeq[p].seqstart, seqno1) == 0) ||
- ((CSeqNo::seqcmp(m_caSeq[p].seqstart, seqno1) > 0) && (CSeqNo::seqcmp(m_caSeq[p].seqstart, seqno2) <= 0)) ||
- ((CSeqNo::seqcmp(m_caSeq[p].seqstart, seqno1) < 0) && (m_caSeq[p].seqend != SRT_SEQNO_NONE) &&
- CSeqNo::seqcmp(m_caSeq[p].seqend, seqno1) >= 0))
- return true;
- p = m_caSeq[p].inext;
- }
- return false;
- }
- int srt::CRcvLossList::getLossLength() const
- {
- return m_iLength;
- }
- int32_t srt::CRcvLossList::getFirstLostSeq() const
- {
- if (0 == m_iLength)
- return SRT_SEQNO_NONE;
- return m_caSeq[m_iHead].seqstart;
- }
- void srt::CRcvLossList::getLossArray(int32_t* array, int& len, int limit)
- {
- len = 0;
- int i = m_iHead;
- while ((len < limit - 1) && (-1 != i))
- {
- array[len] = m_caSeq[i].seqstart;
- if (SRT_SEQNO_NONE != m_caSeq[i].seqend)
- {
- // there are more than 1 loss in the sequence
- array[len] |= LOSSDATA_SEQNO_RANGE_FIRST;
- ++len;
- array[len] = m_caSeq[i].seqend;
- }
- ++len;
- i = m_caSeq[i].inext;
- }
- }
- srt::CRcvFreshLoss::CRcvFreshLoss(int32_t seqlo, int32_t seqhi, int initial_age)
- : ttl(initial_age)
- , timestamp(steady_clock::now())
- {
- seq[0] = seqlo;
- seq[1] = seqhi;
- }
- srt::CRcvFreshLoss::Emod srt::CRcvFreshLoss::revoke(int32_t sequence)
- {
- int32_t diffbegin = CSeqNo::seqcmp(sequence, seq[0]);
- int32_t diffend = CSeqNo::seqcmp(sequence, seq[1]);
- if (diffbegin < 0 || diffend > 0)
- {
- return NONE; // not within the range at all.
- }
- if (diffbegin == 0)
- {
- if (diffend == 0) // exactly at begin and end
- {
- return DELETE;
- }
- // only exactly at begin. Shrink the range
- seq[0] = CSeqNo::incseq(seq[0]);
- return STRIPPED;
- }
- if (diffend == 0) // exactly at end
- {
- seq[1] = CSeqNo::decseq(seq[1]);
- return STRIPPED;
- }
- return SPLIT;
- }
- srt::CRcvFreshLoss::Emod srt::CRcvFreshLoss::revoke(int32_t lo, int32_t hi)
- {
- // This should only if the range lo-hi is anyhow covered by seq[0]-seq[1].
- // Note: if the checked item contains sequences that are OLDER
- // than the oldest sequence in this range, they should be deleted,
- // even though this wasn't explicitly requested.
- // LOHI: <lo, hi>
- // ITEM: <lo, hi> <--- delete
- // If the sequence range is older than the range to be revoked,
- // delete it anyway.
- if (lo != SRT_SEQNO_NONE && CSeqNo::seqcmp(lo, seq[1]) > 0)
- return DELETE;
- // IF <lo> is NONE, then rely simply on that item.hi <% arg.hi,
- // which is a condition at the end.
- // LOHI: <lo, hi>
- // ITEM: <lo, hi> <-- NOTFOUND
- // This element is newer than the given sequence, so match failed.
- if (CSeqNo::seqcmp(hi, seq[0]) < 0)
- return NONE;
- // LOHI: <lo, hi>
- // ITEM: <lo, ! hi>
- // RESULT: <lo, hi>
- // 2. If the 'hi' is in the middle (less than seq[1]), delete partially.
- // That is, take care of this range for itself and return STRIPPED.
- if (CSeqNo::seqcmp(hi, seq[1]) < 0)
- {
- seq[0] = CSeqNo::incseq(hi);
- return STRIPPED;
- }
- // LOHI: <lo, hi>
- // ITEM: <lo, ! hi>
- // RESULT: DELETE.
- // 3. Otherwise delete the record, even if this was covering only part of this range.
- // This is not possible that the sequences OLDER THAN THIS are not required to be
- // revoken together with this one.
- return DELETE;
- }
- bool srt::CRcvFreshLoss::removeOne(std::deque<CRcvFreshLoss>& w_container, int32_t sequence, int* pw_had_ttl)
- {
- for (size_t i = 0; i < w_container.size(); ++i)
- {
- const int had_ttl = w_container[i].ttl;
- Emod wh = w_container[i].revoke(sequence);
- if (wh == NONE)
- continue; // Not found. Search again.
- if (wh == DELETE) // ... oo ... x ... o ... => ... oo ... o ...
- {
- // Removed the only element in the record - remove the record.
- w_container.erase(w_container.begin() + i);
- }
- else if (wh == SPLIT) // ... ooxooo ... => ... oo ... ooo ...
- {
- // Create a new element that will hold the upper part of the range,
- // and the found one modify to be the lower part of the range.
- // Keep the current end-of-sequence value for the second element
- int32_t next_end = w_container[i].seq[1];
- // seq-1 set to the end of this element
- w_container[i].seq[1] = CSeqNo::decseq(sequence);
- // seq+1 set to the begin of the next element
- int32_t next_begin = CSeqNo::incseq(sequence);
- // Use position of the NEXT element because insertion happens BEFORE pointed element.
- // Use the same TTL (will stay the same in the other one).
- w_container.insert(w_container.begin() + i + 1,
- CRcvFreshLoss(next_begin, next_end, w_container[i].ttl));
- }
- // For STRIPPED: ... xooo ... => ... ooo ...
- // i.e. there's nothing to do.
- // Every loss is unique. We're done here.
- if (pw_had_ttl)
- *pw_had_ttl = had_ttl;
- return true;
- }
- if (pw_had_ttl)
- *pw_had_ttl = 0;
- return false;
- }
|