Sacker Class Reference

#include <tcp-sink.h>

Inheritance diagram for Sacker:

Acker TclObject Collaboration diagram for Sacker:

Collaboration graph
[legend]

Detailed Description

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

Public Member Functions

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

Data Fields

int last_ack_sent_

Protected Member Functions

void trace (TracedVar *)

Protected Attributes

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


Constructor & Destructor Documentation

Sacker::Sacker  )  [inline]
 

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

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

Sacker::~Sacker  ) 
 

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

References sf_.

00590 {
00591     delete sf_;
00592 }


Member Function Documentation

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

Reimplemented from Acker.

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

References base_nblocks_, SackStack::cnt(), dsacks_, Scheduler::instance(), Acker::is_dup_, Acker::maxseen_, SackStack::reset(), hdr_tcp::sa_left(), hdr_tcp::sa_right(), Acker::seen_, Acker::Seqno(), sf_, and Acker::wndmask_.

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

Here is the call graph for this function:

void Sacker::configure TcpSink  ) 
 

Definition at line 548 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().

00549 {
00550     if (sink == NULL) {
00551         fprintf(stderr, "warning: Sacker::configure(): no TCP sink!\n");
00552         return;
00553     }
00554 
00555     TracedInt& nblocks = sink->max_sack_blocks_;
00556     if (int(nblocks) > NSA) {
00557         fprintf(stderr, "warning(Sacker::configure): TCP header limits number of SACK blocks to %d, not %d\n", NSA, int(nblocks));
00558         nblocks = NSA;
00559     }
00560     sf_ = new SackStack(int(nblocks));
00561     nblocks.tracer(this);
00562     base_nblocks_ = int(nblocks);
00563     dsacks_ = &(sink->generate_dsacks_);
00564 }

int Acker::ecn_unacked  )  [inline, inherited]
 

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

References Acker::ecn_unacked_.

Referenced by XcpSink::ack().

00066 { return ecn_unacked_;}

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

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

References Acker::maxseen_.

00067 { return (maxseen_); }

void Sacker::reset  ) 
 

Reimplemented from Acker.

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

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

00584 {
00585     sf_->reset();
00586     Acker::reset();
00587 }

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 XcpSink::ack(), and append_ack().

00062 { return (next_ - 1); }

void Sacker::trace TracedVar *   )  [protected]
 

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

References base_nblocks_, NSA, and sf_.

00568 {
00569     // we come here if "nblocks" changed
00570     TracedInt* ti = (TracedInt*) v;
00571 
00572     if (int(*ti) > NSA) {
00573         fprintf(stderr, "warning(Sacker::trace): TCP header limits number of SACK blocks to %d, not %d\n", NSA, int(*ti));
00574         *ti = NSA;
00575     }
00576 
00577     int newval = int(*ti);
00578     delete sf_;
00579     sf_ = new SackStack(newval);
00580     base_nblocks_ = newval;
00581 }

double Acker::ts_to_echo  )  [inline, inherited]
 

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

References Acker::ts_to_echo_.

Referenced by XcpSink::ack().

00065 { return ts_to_echo_;}

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

Definition at line 100 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 TcpAsymSink::recv().

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

Here is the call graph for this function:

void Acker::update_ecn_unacked int  value  )  [inherited]
 

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

References Acker::ecn_unacked_.

Referenced by XcpSink::ack().

00233 {
00234     ecn_unacked_ = value;
00235 }

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

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

References Acker::last_ack_sent_, and Acker::ts_to_echo_.

Referenced by TcpAsymSink::recv().

00088 {
00089     // update timestamp if segment advances with ACK.
00090         // Code changed by Andrei Gurtov.
00091         if (rfc1323 && seqno == last_ack_sent_ + 1)
00092                ts_to_echo_ = ts;
00093         else if (ts >= ts_to_echo_ && seqno <= last_ack_sent_ + 1)
00094                //rfc1323-bis, update timestamps from duplicate segments
00095                ts_to_echo_ = ts;
00096 }


Field Documentation

int Sacker::base_nblocks_ [protected]
 

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

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

int* Sacker::dsacks_ [protected]
 

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

Referenced by append_ack(), and 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::last_ack_sent_ [inherited]
 

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

Referenced by XcpSink::ack(), and Acker::update_ts().

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(), and Acker::update().

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 95 of file tcp-sink.h.

Referenced by append_ack(), configure(), reset(), 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 Mar 6 17:29:00 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6