?? tcp-sink.cc
字號:
// Dapeng nbytes_ += numBytes; // update the recv window; figure out how many in-order-bytes // (if any) can be removed from the window and handed to the // application if (numToDeliver) { bytes_ += numToDeliver; recvBytes(numToDeliver); } // send any packets to the application ack(pkt); // ACK the packet Packet::free(pkt); // remove it from the system}static class DelSinkClass : public TclClass {public: DelSinkClass() : TclClass("Agent/TCPSink/DelAck") {} TclObject* create(int, const char*const*) { return (new DelAckSink(new Acker)); }} class_delsink;DelAckSink::DelAckSink(Acker* acker) : TcpSink(acker), delay_timer_(this){ bind_time("interval_", &interval_); // Deleted the line below, since this is bound in TcpSink. // bind("bytes_", &bytes_); // useby JOBS}void DelAckSink::reset() { if (delay_timer_.status() == TIMER_PENDING) delay_timer_.cancel(); TcpSink::reset();}void DelAckSink::recv(Packet* pkt, Handler*){ int numToDeliver; int numBytes = hdr_cmn::access(pkt)->size(); hdr_tcp *th = hdr_tcp::access(pkt); /* W.N. Check if packet is from previous incarnation */ if (th->ts() < lastreset_) { // Remove packet and do nothing Packet::free(pkt); return; } acker_->update_ts(th->seqno(),th->ts(),ts_echo_rfc1323_); numToDeliver = acker_->update(th->seqno(), numBytes); if (numToDeliver) { bytes_ += numToDeliver; // for JOBS recvBytes(numToDeliver); } // If there's no timer and the packet is in sequence, set a timer. // Otherwise, send the ack and update the timer. if (delay_timer_.status() != TIMER_PENDING && th->seqno() == acker_->Seqno()) { // There's no timer, so we can set one and choose // to delay this ack. // If we're following RFC2581 (section 4.2) exactly, // we should only delay the ACK if we're know we're // not doing recovery, i.e. not gap-filling. // Since this is a change to previous ns behaviour, // it's controlled by an optional bound flag. // discussed April 2000 in the ns-users list archives. if (RFC2581_immediate_ack_ && (th->seqno() < acker_->Maxseen())) { // don't delay the ACK since // we're filling in a gap } else { // delay the ACK and start the timer. save_ = pkt; delay_timer_.resched(interval_); return; } } // If there was a timer, turn it off. if (delay_timer_.status() == TIMER_PENDING) delay_timer_.cancel(); ack(pkt); if (save_ != NULL) { Packet::free(save_); save_ = NULL; } Packet::free(pkt);}void DelAckSink::timeout(int){ // The timer expired so we ACK the last packet seen. if ( save_ != NULL ) { Packet* pkt = save_; ack(pkt); save_ = NULL; Packet::free(pkt); }}void DelayTimer::expire(Event* /*e*/) { a_->timeout(0);}/* "sack1-tcp-sink" is for Matt and Jamshid's implementation of sack. */class SackStack {protected: int size_; int cnt_; struct Sf_Entry { int left_; int right_; } *SFE_;public: SackStack(int); // create a SackStack of size (int) ~SackStack(); int& head_right(int n = 0) { return SFE_[n].right_; } int& head_left(int n = 0) { return SFE_[n].left_; } int cnt() { return cnt_; } // how big is the stack void reset() { register int i; for (i = 0; i < cnt_; i++) SFE_[i].left_ = SFE_[i].right_ = -1; cnt_ = 0; } inline void push(int n = 0) { if (cnt_ >= size_) cnt_ = size_ - 1; // overflow check register int i; for (i = cnt_-1; i >= n; i--) SFE_[i+1] = SFE_[i]; // not efficient for big size cnt_++; } inline void pop(int n = 0) { register int i; for (i = n; i < cnt_-1; i++) SFE_[i] = SFE_[i+1]; // not efficient for big size SFE_[i].left_ = SFE_[i].right_ = -1; cnt_--; }};SackStack::SackStack(int sz){ register int i; size_ = sz; SFE_ = new Sf_Entry[sz]; for (i = 0; i < sz; i++) SFE_[i].left_ = SFE_[i].right_ = -1; cnt_ = 0;}SackStack::~SackStack(){ delete SFE_;}static class Sack1TcpSinkClass : public TclClass {public: Sack1TcpSinkClass() : TclClass("Agent/TCPSink/Sack1") {} TclObject* create(int, const char*const*) { Sacker* sacker = new Sacker; TcpSink* sink = new TcpSink(sacker); sacker->configure(sink); return (sink); }} class_sack1tcpsink;static class Sack1DelAckTcpSinkClass : public TclClass {public: Sack1DelAckTcpSinkClass() : TclClass("Agent/TCPSink/Sack1/DelAck") {} TclObject* create(int, const char*const*) { Sacker* sacker = new Sacker; TcpSink* sink = new DelAckSink(sacker); sacker->configure(sink); return (sink); }} class_sack1delacktcpsink;void Sacker::configure(TcpSink *sink){ if (sink == NULL) { fprintf(stderr, "warning: Sacker::configure(): no TCP sink!\n"); return; } TracedInt& nblocks = sink->max_sack_blocks_; if (int(nblocks) > NSA) { fprintf(stderr, "warning(Sacker::configure): TCP header limits number of SACK blocks to %d, not %d\n", NSA, int(nblocks)); nblocks = NSA; } sf_ = new SackStack(int(nblocks)); nblocks.tracer(this); base_nblocks_ = int(nblocks); dsacks_ = &(sink->generate_dsacks_);}voidSacker::trace(TracedVar *v){ // we come here if "nblocks" changed TracedInt* ti = (TracedInt*) v; if (int(*ti) > NSA) { fprintf(stderr, "warning(Sacker::trace): TCP header limits number of SACK blocks to %d, not %d\n", NSA, int(*ti)); *ti = NSA; } int newval = int(*ti); delete sf_; sf_ = new SackStack(newval); base_nblocks_ = newval;}void Sacker::reset() { sf_->reset(); Acker::reset();}Sacker::~Sacker(){ delete sf_;}void Sacker::append_ack(hdr_cmn* ch, hdr_tcp* h, int old_seqno) const{ // ch and h are the common and tcp headers of the Ack being constructed // old_seqno is the sequence # of the packet we just got int sack_index, i, sack_right, sack_left; int recent_sack_left, recent_sack_right; int seqno = Seqno(); // the last in-order packet seen (i.e. the cumulative ACK # - 1) sack_index = 0; sack_left = sack_right = -1; // initialization; sack_index=0 and sack_{left,right}= -1 if (old_seqno < 0) { printf("Error: invalid packet number %d\n", old_seqno); } else if (seqno >= maxseen_ && (sf_->cnt() != 0)) sf_->reset(); // if the Cumulative ACK seqno is at or beyond the right edge // of the window, and if the SackStack is not empty, reset it // (empty it) else if (( (seqno < maxseen_) || is_dup_ ) && (base_nblocks_ > 0)) { // Otherwise, if the received packet is to the left of // the right edge of the receive window (but not at // the right edge), OR if it is a duplicate, AND we // can have 1 or more Sack blocks, then execute the // following, which computes the most recent Sack // block if ((*dsacks_) && is_dup_) { // Record the DSACK Block h->sa_left(sack_index) = old_seqno; h->sa_right(sack_index) = old_seqno+1; // record the block sack_index++;#ifdef DEBUGDSACK printf("%f\t Generating D-SACK for packet %d\n", Scheduler::instance().clock(),old_seqno);#endif } // Build FIRST (traditional) SACK block // If we already had a DSACK block due to a duplicate // packet, and if that duplicate packet is in the // receiver's window (i.e. the packet's sequence // number is > than the cumulative ACK) then the // following should find the SACK block it's a subset // of. If it's <= cum ACK field then the following // shouldn't record a superset SACK block for it. if (sack_index >= base_nblocks_) { printf("Error: can't use DSACK with less than 2 SACK blocks\n"); } else { sack_right=-1; // look rightward for first hole // start at the current packet for (i=old_seqno; i<=maxseen_; i++) { if (!seen_[i & wndmask_]) { sack_right=i; break; } } // if there's no hole set the right edge of the sack // to be the next expected packet if (sack_right == -1) { sack_right = maxseen_+1; } // if the current packet's seqno is smaller than the // left edge of the window, set the sack_left to 0 if (old_seqno <= seqno) { sack_left = 0; // don't record/send the block } else { // look leftward from right edge for first hole for (i = sack_right-1; i > seqno; i--) { if (!seen_[i & wndmask_]) { sack_left = i+1; break; } } h->sa_left(sack_index) = sack_left; h->sa_right(sack_index) = sack_right; // 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); // record the block sack_index++; } recent_sack_left = sack_left; recent_sack_right = sack_right; // first sack block is built, check the others // make sure that if max_sack_blocks has been made // large from tcl we don't over-run the stuff we // allocated in Sacker::Sacker() int k = 0; while (sack_index < base_nblocks_) { sack_left = sf_->head_left(k); sack_right = sf_->head_right(k); // no more history if (sack_left < 0 || sack_right < 0 || sack_right > maxseen_ + 1) break; // newest ack "covers up" this one if (recent_sack_left <= sack_left && recent_sack_right >= sack_right) { sf_->pop(k); continue; } h->sa_left(sack_index) = sack_left; h->sa_right(sack_index) = sack_right; // 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); // store the old sack (i.e. move it down one) sack_index++; k++; } if (old_seqno > seqno) { /* put most recent block onto stack */ sf_->push(); // this just moves things down 1 from the // beginning, but it doesn't push any values // on the stack sf_->head_left() = recent_sack_left; sf_->head_right() = recent_sack_right; // this part stores the left/right values at // the top of the stack (slot 0) } } // this '}' is for the DSACK base_nblocks_ >= test; // (didn't feel like re-indenting all the code and // causing a large diff) } h->sa_length() = sack_index; // set the Length of the sack stack in the header ch->size() += sack_index * 8; // change the size of the common header to account for the // Sack strings (2 4-byte words for each element)}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -