/*
* rcvbuf.cc
* Copyright (C) 2001 by the University of Southern California
* $Id: rcvbuf.cc,v 1.2 2005/08/25 18:58:08 johnh Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
*
* The copyright of this module includes the following
* linking-with-specific-other-licenses addition:
*
* In addition, as a special exception, the copyright holders of
* this module give you permission to combine (via static or
* dynamic linking) this module with free software programs or
* libraries that are released under the GNU LGPL and with code
* included in the standard release of ns-2 under the Apache 2.0
* license or under otherwise-compatible licenses with advertising
* requirements (or modified versions of such code, with unchanged
* license). You may copy and distribute such a system following the
* terms of the GNU GPL for this module and the licenses of the
* other code concerned, provided that you include the source code of
* that other code when and as the GNU GPL requires distribution of
* source code.
*
* Note that people who make modified versions of this module
* are not obligated to grant this special exception for their
* modified versions; it is their choice whether to do so. The GNU
* General Public License gives permission to release a modified
* version without this exception; this exception also makes it
* possible to release a modified version which carries forward this
* exception.
*
*/
/*
* Pragmatic General Multicast (PGM), Reliable Multicast
* Light-Weight Multicast Services (LMS), Reliable Multicast
*
* rcvbuf.cc
*
* Utility class used by receivers to provide for packet loss detection,
* and to compute latency statistics for recovered packets.
*
* Christos Papadopoulos
*/
#include "config.h"
#include <stdio.h>
#include "rcvbuf.h"
RcvBuffer::RcvBuffer ()
{
nextpkt_ = 0;
maxpkt_ = -1;
duplicates_ = 0;
delay_sum_ = 0.0;
max_delay_ = 0.0;
min_delay_ = 1e6;
pkts_recovered_ = 0;
tail_ = gap_ = 0;
}
//
// add pkt to buffer with seqno i, received at time tnow
//
void RcvBuffer::add_pkt (int i, double tnow)
{
Gap *g, *pg;
if (exists_pkt (i))
{
duplicates_++;
return;
}
// common case first: got what we expected
if (i == nextpkt_)
{
nextpkt_++;
if (i == maxpkt_ + 1)
maxpkt_++;
return;
}
// new gap
if (i > nextpkt_)
{
g = new Gap;
g->start_ = nextpkt_;
g->end_ = i-1;
g->time_ = tnow;
g->next_ = 0;
if (!gap_)
gap_ = tail_ = g;
else {
tail_->next_ = g;
tail_ = g;
}
nextpkt_ = i+1;
return;
}
// i < nextpkt_ (a retransmission)
pkts_recovered_++;
// is packet part of the first gap?
if (gap_->start_ <= i && i <= gap_->end_)
{
double d = tnow - gap_->time_;
if (d > max_delay_)
max_delay_ = d;
if (d < min_delay_)
min_delay_ = d;
delay_sum_ += d;
if (i == maxpkt_ + 1)
{
maxpkt_++;
if (++gap_->start_ > gap_->end_)
{
g = gap_;
gap_ = gap_->next_;
if (gap_)
maxpkt_ = gap_->start_ - 1;
else {
maxpkt_ = nextpkt_ - 1;
tail_ = 0;
}
delete g;
}
return;
}
g = gap_;
}
else {
double d;
// locate gap this packet belongs to
pg = gap_;
g = gap_->next_;
while (!(i >= g->start_ && i <= g->end_))
{
pg = g;
g = g->next_;
}
d = tnow - g->time_;
delay_sum_ += d;
if (d > max_delay_) max_delay_ = d;
if (d < min_delay_) min_delay_ = d;
// first packet in gap
if (g->start_ == i)
{
if (++g->start_ > g->end_)
{
pg->next_ = g->next_;
if (tail_ == g)
tail_ = pg;
delete g;
}
return;
}
}
// last packet in gap
if (g->end_ == i)
{
g->end_--;
return;
}
// a packet in the middle of gap
pg = new Gap;
pg->start_ = i+1;
pg->end_ = g->end_;
pg->time_ = g->time_;
pg->next_ = g->next_;
g->next_ = pg;
g->end_ = i-1;
if (tail_ == g)
tail_ = pg;
}
//
// Return 0 if packet does not exist in the
// buffer, 1 if it does
//
int RcvBuffer::exists_pkt (int i)
{
if (i <= maxpkt_) return 1;
if (i >= nextpkt_) return 0;
Gap *g;
for (g = gap_; g; g = g->next_)
if (g->start_ <= i && i <= g->end_)
return 0;
return 1;
}
void RcvBuffer::print ()
{
Gap *g;
printf ("maxpkt: %d ", maxpkt_);
for (g = gap_; g; g = g->next_)
printf ("(%d, %d) ", g->start_, g->end_);
printf ("nextpkt: %d\n", nextpkt_);
}
syntax highlighted by Code2HTML, v. 0.9.1