Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

Sacker Class Reference

#include <tcp-sink.h>

Inheritance diagram for Sacker:

Inheritance graph
[legend]
Collaboration diagram for Sacker:

Collaboration graph
[legend]
List of all members.

Public Member Functions

 Sacker ()
 ~Sacker ()
void append_ack (hdr_cmn *, hdr_tcp *, int oldSeqno) const
void reset ()
void configure (TcpSink *)
void update_ts (int seqno, double ts)
int update (int seqno, int numBytes)
void update_ecn_unacked (int value)
int Seqno () const
double ts_to_echo ()
int ecn_unacked ()
int Maxseen () const
void resize_buffers (int sz)

Protected Member Functions

void trace (TracedVar *)

Protected Attributes

int base_nblocks_
int * dsacks_
SackStacksf_
int next_
int maxseen_
int wndmask_
int ecn_unacked_
int * seen_
double ts_to_echo_
int is_dup_

Constructor & Destructor Documentation

Sacker::Sacker  )  [inline]
 

Definition at line 85 of file tcp-sink.h.

References base_nblocks_, and sf_.

00085 : base_nblocks_(-1), sf_(0) { };

Sacker::~Sacker  ) 
 

Definition at line 572 of file tcp-sink.cc.

References sf_.

00573 {
00574         delete sf_;
00575 }


Member Function Documentation

void Sacker::append_ack hdr_cmn ,
hdr_tcp ,
int  oldSeqno
const [virtual]
 

Reimplemented from Acker.

Definition at line 577 of file tcp-sink.cc.

References base_nblocks_, SackStack::cnt(), SackStack::head_left(), SackStack::head_right(), Scheduler::instance(), Acker::is_dup_, Acker::maxseen_, SackStack::pop(), SackStack::push(), SackStack::reset(), hdr_tcp::sa_left(), hdr_tcp::sa_length(), hdr_tcp::sa_right(), Acker::seen_, Acker::Seqno(), sf_, hdr_cmn::size(), and Acker::wndmask_.

00578 {
00579         // ch and h are the common and tcp headers of the Ack being constructed
00580         // old_seqno is the sequence # of the packet we just got
00581         
00582         int sack_index, i, sack_right, sack_left;
00583         int recent_sack_left, recent_sack_right;
00584           
00585         int seqno = Seqno();
00586         // the last in-order packet seen (i.e. the cumulative ACK # - 1)
00587 
00588         sack_index = 0;
00589         sack_left = sack_right = -1;
00590         // initialization; sack_index=0 and sack_{left,right}= -1
00591 
00592         if (old_seqno < 0) {
00593                 printf("Error: invalid packet number %d\n", old_seqno);
00594         } else if (seqno >= maxseen_ && (sf_->cnt() != 0))
00595                 sf_->reset();
00596         // if the Cumulative ACK seqno is at or beyond the right edge
00597         // of the window, and if the SackStack is not empty, reset it
00598         // (empty it)
00599         else if (( (seqno < maxseen_) || is_dup_ ) && (base_nblocks_ > 0)) {
00600                 // Otherwise, if the received packet is to the left of
00601                 // the right edge of the receive window (but not at
00602                 // the right edge), OR if it is a duplicate, AND we
00603                 // can have 1 or more Sack blocks, then execute the
00604                 // following, which computes the most recent Sack
00605                 // block
00606 
00607                 if ((*dsacks_) && is_dup_) {
00608                         // Record the DSACK Block
00609                         h->sa_left(sack_index) = old_seqno;
00610                         h->sa_right(sack_index) = old_seqno+1;
00611                         // record the block
00612                         sack_index++;
00613 #ifdef DEBUGDSACK
00614                         printf("%f\t Generating D-SACK for packet %d\n", Scheduler::instance().clock(),old_seqno);
00615 #endif
00616 
00617                         
00618                 }
00619 
00620                 //  Build FIRST (traditional) SACK block
00621 
00622                 // If we already had a DSACK block due to a duplicate
00623                 // packet, and if that duplicate packet is in the
00624                 // receiver's window (i.e. the packet's sequence
00625                 // number is > than the cumulative ACK) then the
00626                 // following should find the SACK block it's a subset
00627                 // of.  If it's <= cum ACK field then the following
00628                 // shouldn't record a superset SACK block for it.
00629 
00630                 if (sack_index >= base_nblocks_) {
00631                         printf("Error: can't use DSACK with less than 2 SACK blocks\n");
00632                 } else {
00633                 sack_right=-1;
00634 
00635                 // look rightward for first hole 
00636                 // start at the current packet 
00637                 for (i=old_seqno; i<=maxseen_; i++) {
00638                         if (!seen_[i & wndmask_]) {
00639                                 sack_right=i;
00640                                 break;
00641                         }
00642                 }
00643 
00644                 // if there's no hole set the right edge of the sack
00645                 // to be the next expected packet
00646                 if (sack_right == -1) {
00647                         sack_right = maxseen_+1;
00648                 }
00649 
00650                 // if the current packet's seqno is smaller than the
00651                 // left edge of the window, set the sack_left to 0
00652                 if (old_seqno <= seqno) {
00653                         sack_left = 0;
00654                         // don't record/send the block
00655                 } else {
00656                         // look leftward from right edge for first hole 
00657                         for (i = sack_right-1; i > seqno; i--) {
00658                                 if (!seen_[i & wndmask_]) {
00659                                         sack_left = i+1;
00660                                         break;
00661                                 }
00662                         }
00663                         h->sa_left(sack_index) = sack_left;
00664                         h->sa_right(sack_index) = sack_right;
00665                         
00666                         // printf("pkt_seqno: %i cuml_seqno: %i sa_idx: %i sa_left: %i sa_right: %i\n" ,old_seqno, seqno, sack_index, sack_left, sack_right);
00667                         // record the block
00668                         sack_index++;
00669                 }
00670 
00671                 recent_sack_left = sack_left;
00672                 recent_sack_right = sack_right;
00673 
00674                 // first sack block is built, check the others 
00675                 // make sure that if max_sack_blocks has been made
00676                 // large from tcl we don't over-run the stuff we
00677                 // allocated in Sacker::Sacker()
00678                 int k = 0;
00679                 while (sack_index < base_nblocks_) {
00680 
00681                         sack_left = sf_->head_left(k);
00682                         sack_right = sf_->head_right(k);
00683 
00684                         // no more history 
00685                         if (sack_left < 0 || sack_right < 0 ||
00686                                 sack_right > maxseen_ + 1)
00687                                 break;
00688 
00689                         // newest ack "covers up" this one 
00690 
00691                         if (recent_sack_left <= sack_left &&
00692                             recent_sack_right >= sack_right) {
00693                                 sf_->pop(k);
00694                                 continue;
00695                         }
00696 
00697                         h->sa_left(sack_index) = sack_left;
00698                         h->sa_right(sack_index) = sack_right;
00699                         
00700                         // printf("pkt_seqno: %i cuml_seqno: %i sa_idx: %i sa_left: %i sa_right: %i\n" ,old_seqno, seqno, sack_index, sack_left, sack_right);
00701                         
00702                         // store the old sack (i.e. move it down one)
00703                         sack_index++;
00704                         k++;
00705                 }
00706 
00707 
00708                 if (old_seqno > seqno) {
00709                         /* put most recent block onto stack */
00710                         sf_->push();
00711                         // this just moves things down 1 from the
00712                         // beginning, but it doesn't push any values
00713                         // on the stack
00714                         sf_->head_left() = recent_sack_left;
00715                         sf_->head_right() = recent_sack_right;
00716                         // this part stores the left/right values at
00717                         // the top of the stack (slot 0)
00718                 }
00719 
00720                 } // this '}' is for the DSACK base_nblocks_ >= test;
00721                   // (didn't feel like re-indenting all the code and 
00722                   // causing a large diff)
00723                 
00724         }
00725         h->sa_length() = sack_index;
00726         // set the Length of the sack stack in the header
00727         ch->size() += sack_index * 8;
00728         // change the size of the common header to account for the
00729         // Sack strings (2 4-byte words for each element)
00730 }

Here is the call graph for this function:

void Sacker::configure TcpSink  ) 
 

Definition at line 531 of file tcp-sink.cc.

References base_nblocks_, dsacks_, TcpSink::generate_dsacks_, TcpSink::max_sack_blocks_, NSA, and sf_.

Referenced by Sack1DelAckTcpSinkClass::create(), and Sack1TcpSinkClass::create().

00532 {
00533         if (sink == NULL) {
00534                 fprintf(stderr, "warning: Sacker::configure(): no TCP sink!\n");
00535                 return;
00536         }
00537 
00538         TracedInt& nblocks = sink->max_sack_blocks_;
00539         if (int(nblocks) > NSA) {
00540                 fprintf(stderr, "warning(Sacker::configure): TCP header limits number of SACK blocks to %d, not %d\n", NSA, int(nblocks));
00541                 nblocks = NSA;
00542         }
00543         sf_ = new SackStack(int(nblocks));
00544         nblocks.tracer(this);
00545         base_nblocks_ = int(nblocks);
00546         dsacks_ = &(sink->generate_dsacks_);
00547 }

int Acker::ecn_unacked  )  [inline, inherited]
 

Definition at line 66 of file tcp-sink.h.

References Acker::ecn_unacked_.

Referenced by TcpSink::ack(), and QSTcpSink::ack().

00066 { return ecn_unacked_;}

int Acker::Maxseen  )  const [inline, inherited]
 

Definition at line 67 of file tcp-sink.h.

References Acker::maxseen_.

Referenced by DelAckSink::recv().

00067 { return (maxseen_); }

void Sacker::reset  ) 
 

Reimplemented from Acker.

Definition at line 566 of file tcp-sink.cc.

References Acker::reset(), SackStack::reset(), and sf_.

00567 {
00568         sf_->reset();
00569         Acker::reset();
00570 }

Here is the call graph for this function:

void Acker::resize_buffers int  sz  )  [inherited]
 

Definition at line 66 of file tcp-sink.cc.

References Acker::maxseen_, Acker::next_, Acker::seen_, and Acker::wndmask_.

Referenced by Acker::update().

00066                                  { 
00067         int* new_seen = new int[sz];
00068         int new_wndmask = sz - 1;
00069         
00070         if(!new_seen){
00071                 fprintf(stderr, "Unable to allocate buffer seen_[%i]\n", sz);
00072                 exit(1);
00073         }
00074         
00075         memset(new_seen, 0, (sizeof(int) * (sz)));
00076         
00077         for(int i = next_; i <= maxseen_+1; i++){
00078                 new_seen[i & new_wndmask] = seen_[i&wndmask_];
00079         }
00080         
00081         delete[] seen_;
00082         seen_ = new_seen;      
00083         wndmask_ = new_wndmask;
00084         return; 
00085 }

int Acker::Seqno  )  const [inline, inherited]
 

Definition at line 62 of file tcp-sink.h.

References Acker::next_.

Referenced by TcpSink::ack(), QSTcpSink::ack(), append_ack(), DelAckSink::recv(), and TcpAsymSink::recv().

00062 { return (next_ - 1); }

void Sacker::trace TracedVar *   )  [protected]
 

Definition at line 550 of file tcp-sink.cc.

References base_nblocks_, NSA, and sf_.

00551 {
00552         // we come here if "nblocks" changed
00553         TracedInt* ti = (TracedInt*) v;
00554 
00555         if (int(*ti) > NSA) {
00556                 fprintf(stderr, "warning(Sacker::trace): TCP header limits number of SACK blocks to %d, not %d\n", NSA, int(*ti));
00557                 *ti = NSA;
00558         }
00559 
00560         int newval = int(*ti);
00561         delete sf_;
00562         sf_ = new SackStack(newval);
00563         base_nblocks_ = newval;
00564 }

double Acker::ts_to_echo  )  [inline, inherited]
 

Definition at line 65 of file tcp-sink.h.

References Acker::ts_to_echo_.

Referenced by TcpSink::ack(), and QSTcpSink::ack().

00065 { return ts_to_echo_;}

int Acker::update int  seqno,
int  numBytes
[inherited]
 

Definition at line 95 of file tcp-sink.cc.

References FALSE, Scheduler::instance(), Acker::is_dup_, Acker::maxseen_, Acker::next_, Acker::resize_buffers(), Acker::seen_, TRUE, and Acker::wndmask_.

Referenced by DelAckSink::recv(), TcpSink::recv(), QSTcpSink::recv(), and TcpAsymSink::recv().

00096 {
00097         bool just_marked_as_seen = FALSE;
00098         is_dup_ = FALSE;
00099         // start by assuming the segment hasn't been received before
00100         if (numBytes <= 0)
00101                 printf("Error, received TCP packet size <= 0\n");
00102         int numToDeliver = 0;
00103         while(seq + 1 - next_ >= wndmask_) {
00104                 // next_ is next packet expected; wndmask_ is the maximum
00105                 // window size minus 1; if somehow the seqno of the
00106                 // packet is greater than the one we're expecting+wndmask_,
00107                 // then resize the buffer.
00108                 resize_buffers((wndmask_+1)*2);
00109         }
00110 
00111         if (seq > maxseen_) {
00112                 // the packet is the highest one we've seen so far
00113                 int i;
00114                 for (i = maxseen_ + 1; i < seq; ++i)
00115                         seen_[i & wndmask_] = 0;
00116                 // we record the packets between the old maximum and
00117                 // the new max as being "unseen" i.e. 0 bytes of each
00118                 // packet have been received
00119                 maxseen_ = seq;
00120                 seen_[maxseen_ & wndmask_] = numBytes;
00121                 // store how many bytes have been seen for this packet
00122                 seen_[(maxseen_ + 1) & wndmask_] = 0;
00123                 // clear the array entry for the packet immediately
00124                 // after this one
00125                 just_marked_as_seen = TRUE;
00126                 // necessary so this packet isn't confused as being a duplicate
00127         }
00128         int next = next_;
00129         if (seq < next) {
00130                 // Duplicate packet case 1: the packet is to the left edge of
00131                 // the receive window; therefore we must have seen it
00132                 // before
00133 #ifdef DEBUGDSACK
00134                 printf("%f\t Received duplicate packet %d\n",Scheduler::instance().clock(),seq);
00135 #endif
00136                 is_dup_ = TRUE;
00137         }
00138 
00139         if (seq >= next && seq <= maxseen_) {
00140                 // next is the left edge of the recv window; maxseen_
00141                 // is the right edge; execute this block if there are
00142                 // missing packets in the recv window AND if current
00143                 // packet falls within those gaps
00144 
00145                 if (seen_[seq & wndmask_] && !just_marked_as_seen) {
00146                 // Duplicate case 2: the segment has already been
00147                 // recorded as being received (AND not because we just
00148                 // marked it as such)
00149                         is_dup_ = TRUE;
00150 #ifdef DEBUGDSACK
00151                         printf("%f\t Received duplicate packet %d\n",Scheduler::instance().clock(),seq);
00152 #endif
00153                 }
00154                 seen_[seq & wndmask_] = numBytes;
00155                 // record the packet as being seen
00156                 while (seen_[next & wndmask_]) {
00157                         // this loop first gets executed if seq==next;
00158                         // i.e., this is the next packet in order that
00159                         // we've been waiting for.  the loop sets how
00160                         // many bytes we can now deliver to the
00161                         // application, due to this packet arriving
00162                         // (and the prior arrival of any segments
00163                         // immediately to the right)
00164 
00165                         numToDeliver += seen_[next & wndmask_];
00166                         ++next;
00167                 }
00168                 next_ = next;
00169                 // store the new left edge of the window
00170         }
00171         return numToDeliver;
00172 }

Here is the call graph for this function:

void Acker::update_ecn_unacked int  value  )  [inherited]
 

Definition at line 224 of file tcp-sink.cc.

References Acker::ecn_unacked_.

Referenced by TcpSink::ack(), and QSTcpSink::ack().

00225 {
00226         ecn_unacked_ = value;
00227 }

void Acker::update_ts int  seqno,
double  ts
[inherited]
 

Definition at line 87 of file tcp-sink.cc.

References Acker::next_, ts, and Acker::ts_to_echo_.

Referenced by DelAckSink::recv(), TcpSink::recv(), QSTcpSink::recv(), and TcpAsymSink::recv().

00088 {
00089         if (ts >= ts_to_echo_ && seqno <= next_)
00090                 ts_to_echo_ = ts;
00091 }


Member Data Documentation

int Sacker::base_nblocks_ [protected]
 

Definition at line 91 of file tcp-sink.h.

Referenced by append_ack(), configure(), Sacker(), and trace().

int* Sacker::dsacks_ [protected]
 

Definition at line 92 of file tcp-sink.h.

Referenced by configure().

int Acker::ecn_unacked_ [protected, inherited]
 

Definition at line 74 of file tcp-sink.h.

Referenced by Acker::ecn_unacked(), and Acker::update_ecn_unacked().

int Acker::is_dup_ [protected, inherited]
 

Definition at line 78 of file tcp-sink.h.

Referenced by append_ack(), and Acker::update().

int Acker::maxseen_ [protected, inherited]
 

Definition at line 72 of file tcp-sink.h.

Referenced by append_ack(), Acker::Maxseen(), Acker::reset(), Acker::resize_buffers(), and Acker::update().

int Acker::next_ [protected, inherited]
 

Definition at line 71 of file tcp-sink.h.

Referenced by Acker::reset(), Acker::resize_buffers(), Acker::Seqno(), Acker::update(), and Acker::update_ts().

int* Acker::seen_ [protected, inherited]
 

Definition at line 76 of file tcp-sink.h.

Referenced by Acker::Acker(), append_ack(), Acker::reset(), Acker::resize_buffers(), Acker::update(), and Acker::~Acker().

SackStack* Sacker::sf_ [protected]
 

Definition at line 93 of file tcp-sink.h.

Referenced by append_ack(), configure(), reset(), Sacker(), trace(), and ~Sacker().

double Acker::ts_to_echo_ [protected, inherited]
 

Definition at line 77 of file tcp-sink.h.

Referenced by Acker::ts_to_echo(), and Acker::update_ts().

int Acker::wndmask_ [protected, inherited]
 

Definition at line 73 of file tcp-sink.h.

Referenced by append_ack(), Acker::reset(), Acker::resize_buffers(), and Acker::update().


The documentation for this class was generated from the following files:
Generated on Tue Apr 20 13:18:44 2004 for NS2.26SourcesOriginal by doxygen 1.3.3