tcp-sink.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:22k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 1991-1997 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  * This product includes software developed by the Computer Systems
  17.  * Engineering Group at Lawrence Berkeley Laboratory.
  18.  * 4. Neither the name of the University nor of the Laboratory may be used
  19.  *    to endorse or promote products derived from this software without
  20.  *    specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  */
  34.  
  35. /* 8/02 Tom Kelly - Dynamic resizing of seen buffer */
  36. #include "flags.h"
  37. #include "ip.h"
  38. #include "tcp-sink.h"
  39. #include "hdr_qs.h"
  40. static class TcpSinkClass : public TclClass {
  41. public:
  42. TcpSinkClass() : TclClass("Agent/TCPSink") {}
  43. TclObject* create(int, const char*const*) {
  44. return (new TcpSink(new Acker));
  45. }
  46. } class_tcpsink;
  47. Acker::Acker() : next_(0), maxseen_(0), wndmask_(MWM), ecn_unacked_(0), 
  48. ts_to_echo_(0), last_ack_sent_(0)
  49. {
  50. seen_ = new int[MWS];
  51. memset(seen_, 0, (sizeof(int) * (MWS)));
  52. }
  53. void Acker::reset() 
  54. {
  55. next_ = 0;
  56. maxseen_ = 0;
  57. memset(seen_, 0, (sizeof(int) * (wndmask_ + 1)));
  58. }
  59. // dynamically increase the seen buffer as needed
  60. // size must be a factor of two for the wndmask_ to work...
  61. void Acker::resize_buffers(int sz) { 
  62. int* new_seen = new int[sz];
  63. int new_wndmask = sz - 1;
  64. if(!new_seen){
  65. fprintf(stderr, "Unable to allocate buffer seen_[%i]n", sz);
  66. exit(1);
  67. }
  68. memset(new_seen, 0, (sizeof(int) * (sz)));
  69. for(int i = next_; i <= maxseen_+1; i++){
  70. new_seen[i & new_wndmask] = seen_[i&wndmask_];
  71. }
  72. delete[] seen_;
  73. seen_ = new_seen;      
  74. wndmask_ = new_wndmask;
  75. return; 
  76. }
  77. void Acker::update_ts(int seqno, double ts, int rfc1323)
  78. {
  79. // update timestamp if segment advances with ACK.
  80.         // Code changed by Andrei Gurtov.
  81.         if (rfc1323 && seqno == last_ack_sent_ + 1)
  82.                ts_to_echo_ = ts;
  83.         else if (ts >= ts_to_echo_ && seqno <= last_ack_sent_ + 1)
  84.                //rfc1323-bis, update timestamps from duplicate segments
  85.                ts_to_echo_ = ts;
  86. }
  87. // returns number of bytes that can be "delivered" to application
  88. // also updates the receive window (i.e. next_, maxseen, and seen_ array)
  89. int Acker::update(int seq, int numBytes)
  90. {
  91. bool just_marked_as_seen = FALSE;
  92. is_dup_ = FALSE;
  93. // start by assuming the segment hasn't been received before
  94. if (numBytes <= 0)
  95. printf("Error, received TCP packet size <= 0n");
  96. int numToDeliver = 0;
  97. while(seq + 1 - next_ >= wndmask_) {
  98. // next_ is next packet expected; wndmask_ is the maximum
  99. // window size minus 1; if somehow the seqno of the
  100. // packet is greater than the one we're expecting+wndmask_,
  101. // then resize the buffer.
  102. resize_buffers((wndmask_+1)*2);
  103. }
  104. if (seq > maxseen_) {
  105. // the packet is the highest one we've seen so far
  106. int i;
  107. for (i = maxseen_ + 1; i < seq; ++i)
  108. seen_[i & wndmask_] = 0;
  109. // we record the packets between the old maximum and
  110. // the new max as being "unseen" i.e. 0 bytes of each
  111. // packet have been received
  112. maxseen_ = seq;
  113. seen_[maxseen_ & wndmask_] = numBytes;
  114. // store how many bytes have been seen for this packet
  115. seen_[(maxseen_ + 1) & wndmask_] = 0;
  116. // clear the array entry for the packet immediately
  117. // after this one
  118. just_marked_as_seen = TRUE;
  119. // necessary so this packet isn't confused as being a duplicate
  120. }
  121. int next = next_;
  122. if (seq < next) {
  123. // Duplicate packet case 1: the packet is to the left edge of
  124. // the receive window; therefore we must have seen it
  125. // before
  126. #ifdef DEBUGDSACK
  127. printf("%ft Received duplicate packet %dn",Scheduler::instance().clock(),seq);
  128. #endif
  129. is_dup_ = TRUE;
  130. }
  131. if (seq >= next && seq <= maxseen_) {
  132. // next is the left edge of the recv window; maxseen_
  133. // is the right edge; execute this block if there are
  134. // missing packets in the recv window AND if current
  135. // packet falls within those gaps
  136. if (seen_[seq & wndmask_] && !just_marked_as_seen) {
  137. // Duplicate case 2: the segment has already been
  138. // recorded as being received (AND not because we just
  139. // marked it as such)
  140. is_dup_ = TRUE;
  141. #ifdef DEBUGDSACK
  142. printf("%ft Received duplicate packet %dn",Scheduler::instance().clock(),seq);
  143. #endif
  144. }
  145. seen_[seq & wndmask_] = numBytes;
  146. // record the packet as being seen
  147. while (seen_[next & wndmask_]) {
  148. // this loop first gets executed if seq==next;
  149. // i.e., this is the next packet in order that
  150. // we've been waiting for.  the loop sets how
  151. // many bytes we can now deliver to the
  152. // application, due to this packet arriving
  153. // (and the prior arrival of any segments
  154. // immediately to the right)
  155. numToDeliver += seen_[next & wndmask_];
  156. ++next;
  157. }
  158. next_ = next;
  159. // store the new left edge of the window
  160. }
  161. return numToDeliver;
  162. }
  163. TcpSink::TcpSink(Acker* acker) : Agent(PT_ACK), acker_(acker), save_(NULL),
  164. lastreset_(0.0)
  165. {
  166. bytes_ = 0; 
  167. bind("bytes_", &bytes_);
  168. /*
  169.  * maxSackBlocks_ does wierd tracing things.
  170.  * don't make it delay-bound yet.
  171.  */
  172. #if defined(TCP_DELAY_BIND_ALL) && 0
  173. #else /* ! TCP_DELAY_BIND_ALL */
  174. bind("maxSackBlocks_", &max_sack_blocks_); // used only by sack
  175. #endif /* TCP_DELAY_BIND_ALL */
  176. }
  177. void
  178. TcpSink::delay_bind_init_all()
  179. {
  180.         delay_bind_init_one("packetSize_");
  181.         delay_bind_init_one("ts_echo_bugfix_");
  182. delay_bind_init_one("ts_echo_rfc1323_");
  183. delay_bind_init_one("bytes_"); // For throughput measurements in JOBS
  184.         delay_bind_init_one("generateDSacks_"); // used only by sack
  185. delay_bind_init_one("qs_enabled_");
  186. delay_bind_init_one("RFC2581_immediate_ack_");
  187. delay_bind_init_one("ecn_syn_");
  188. #if defined(TCP_DELAY_BIND_ALL) && 0
  189.         delay_bind_init_one("maxSackBlocks_");
  190. #endif /* TCP_DELAY_BIND_ALL */
  191. Agent::delay_bind_init_all();
  192. }
  193. int
  194. TcpSink::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer)
  195. {
  196.         if (delay_bind(varName, localName, "packetSize_", &size_, tracer)) return TCL_OK;
  197.         if (delay_bind_bool(varName, localName, "ts_echo_bugfix_", &ts_echo_bugfix_, tracer)) return TCL_OK;
  198. if (delay_bind_bool(varName, localName, "ts_echo_rfc1323_", &ts_echo_rfc1323_, tracer)) return TCL_OK;
  199.         if (delay_bind_bool(varName, localName, "generateDSacks_", &generate_dsacks_, tracer)) return TCL_OK;
  200.         if (delay_bind_bool(varName, localName, "qs_enabled_", &qs_enabled_, tracer)) return TCL_OK;
  201.         if (delay_bind_bool(varName, localName, "RFC2581_immediate_ack_", &RFC2581_immediate_ack_, tracer)) return TCL_OK;
  202. if (delay_bind_bool(varName, localName, "ecn_syn_", &ecn_syn_ ,tracer)) return TCL_OK;
  203. #if defined(TCP_DELAY_BIND_ALL) && 0
  204.         if (delay_bind(varName, localName, "maxSackBlocks_", &max_sack_blocks_, tracer)) return TCL_OK;
  205. #endif /* TCP_DELAY_BIND_ALL */
  206.         return Agent::delay_bind_dispatch(varName, localName, tracer);
  207. }
  208. void Acker::append_ack(hdr_cmn*, hdr_tcp*, int) const
  209. {
  210. }
  211. void Acker::update_ecn_unacked(int value)
  212. {
  213. ecn_unacked_ = value;
  214. }
  215. int TcpSink::command(int argc, const char*const* argv)
  216. {
  217. if (argc == 2) {
  218. if (strcmp(argv[1], "reset") == 0) {
  219. reset();
  220. return (TCL_OK);
  221. }
  222. if (strcmp(argv[1], "resize_buffers") == 0) {
  223. // no need for this as seen buffer set dynamically
  224. fprintf(stderr,"DEPRECIATED: resize_buffersn");
  225. return (TCL_OK);
  226. }
  227. }
  228. return (Agent::command(argc, argv));
  229. }
  230. void TcpSink::reset() 
  231. {
  232. acker_->reset();
  233. save_ = NULL;
  234. lastreset_ = Scheduler::instance().clock(); /* W.N. - for detecting */
  235. /* packets from previous incarnations */
  236. }
  237. void TcpSink::ack(Packet* opkt)
  238. {
  239. Packet* npkt = allocpkt();
  240. // opkt is the "old" packet that was received
  241. // npkt is the "new" packet being constructed (for the ACK)
  242. double now = Scheduler::instance().clock();
  243. hdr_tcp *otcp = hdr_tcp::access(opkt);
  244. hdr_ip *oiph = hdr_ip::access(opkt);
  245. hdr_tcp *ntcp = hdr_tcp::access(npkt);
  246. if (qs_enabled_) {
  247. // QuickStart code from Srikanth Sundarrajan.
  248. hdr_qs *oqsh = hdr_qs::access(opkt);
  249. hdr_qs *nqsh = hdr_qs::access(npkt);
  250.         if (otcp->seqno() == 0 && oqsh->flag() == QS_REQUEST) {
  251.                 nqsh->flag() = QS_RESPONSE;
  252.                 nqsh->ttl() = (oiph->ttl() - oqsh->ttl()) % 256;
  253.                 nqsh->rate() = oqsh->rate(); 
  254.         }
  255.         else {
  256.                 nqsh->flag() = QS_DISABLE;
  257.         }
  258. }
  259. // get the tcp headers
  260. ntcp->seqno() = acker_->Seqno();
  261. // get the cumulative sequence number to put in the ACK; this
  262. // is just the left edge of the receive window - 1
  263. ntcp->ts() = now;
  264. // timestamp the packet
  265. if (ts_echo_bugfix_)  /* TCP/IP Illustrated, Vol. 2, pg. 870 */
  266. ntcp->ts_echo() = acker_->ts_to_echo();
  267. else
  268. ntcp->ts_echo() = otcp->ts();
  269. // echo the original's time stamp
  270. hdr_ip* oip = hdr_ip::access(opkt);
  271. hdr_ip* nip = hdr_ip::access(npkt);
  272. // get the ip headers
  273. nip->flowid() = oip->flowid();
  274. // copy the flow id
  275. hdr_flags* of = hdr_flags::access(opkt);
  276. hdr_flags* nf = hdr_flags::access(npkt);
  277. hdr_flags* sf;
  278. if (save_ != NULL)
  279. sf = hdr_flags::access(save_);
  280. else 
  281. sf = 0;
  282. // Look at delayed packet being acked. 
  283. if ( (sf != 0 && sf->cong_action()) || of->cong_action() ) 
  284. // Sender has responsed to congestion. 
  285. acker_->update_ecn_unacked(0);
  286. if ( (sf != 0 && sf->ect() && sf->ce())  || 
  287. (of->ect() && of->ce()) )
  288. // New report of congestion.  
  289. acker_->update_ecn_unacked(1);
  290. if ( (sf != 0 && sf->ect()) || of->ect() )
  291. // Set EcnEcho bit.  
  292. nf->ecnecho() = acker_->ecn_unacked();
  293. if (!of->ect() && of->ecnecho() ||
  294. (sf != 0 && !sf->ect() && sf->ecnecho()) ) {
  295.  // This is the negotiation for ECN-capability.
  296.  // We are not checking for of->cong_action() also. 
  297.  // In this respect, this does not conform to the 
  298.  // specifications in the internet draft 
  299. nf->ecnecho() = 1;
  300. if (ecn_syn_) 
  301. nf->ect() = 1;
  302. }
  303. acker_->append_ack(hdr_cmn::access(npkt),
  304.    ntcp, otcp->seqno());
  305. add_to_ack(npkt);
  306. // the above function is used in TcpAsymSink
  307.         // Andrei Gurtov
  308.         acker_->last_ack_sent_ = ntcp->seqno();
  309.         // printf("ACK %d ts %fn", ntcp->seqno(), ntcp->ts_echo());
  310. send(npkt, 0);
  311. // send it
  312. }
  313. void TcpSink::add_to_ack(Packet*)
  314. {
  315. return;
  316. }
  317. void TcpSink::recv(Packet* pkt, Handler*)
  318. {
  319. int numToDeliver;
  320. int numBytes = hdr_cmn::access(pkt)->size();
  321. // number of bytes in the packet just received
  322. hdr_tcp *th = hdr_tcp::access(pkt);
  323. /* W.N. Check if packet is from previous incarnation */
  324. if (th->ts() < lastreset_) {
  325. // Remove packet and do nothing
  326. Packet::free(pkt);
  327. return;
  328. }
  329. acker_->update_ts(th->seqno(),th->ts(),ts_echo_rfc1323_);
  330. // update the timestamp to echo
  331.        numToDeliver = acker_->update(th->seqno(), numBytes);
  332. // update the recv window; figure out how many in-order-bytes
  333. // (if any) can be removed from the window and handed to the
  334. // application
  335. if (numToDeliver) {
  336. bytes_ += numToDeliver;
  337. recvBytes(numToDeliver);
  338. }
  339. // send any packets to the application
  340.        ack(pkt);
  341. // ACK the packet
  342. Packet::free(pkt);
  343. // remove it from the system
  344. }
  345. static class DelSinkClass : public TclClass {
  346. public:
  347. DelSinkClass() : TclClass("Agent/TCPSink/DelAck") {}
  348. TclObject* create(int, const char*const*) {
  349. return (new DelAckSink(new Acker));
  350. }
  351. } class_delsink;
  352. DelAckSink::DelAckSink(Acker* acker) : TcpSink(acker), delay_timer_(this)
  353. {
  354. bind_time("interval_", &interval_);
  355. // Deleted the line below, since this is bound in TcpSink.
  356. // bind("bytes_", &bytes_); // useby JOBS
  357. }
  358. void DelAckSink::reset() {
  359.     if (delay_timer_.status() == TIMER_PENDING)
  360.         delay_timer_.cancel();
  361.     TcpSink::reset();
  362. }
  363. void DelAckSink::recv(Packet* pkt, Handler*)
  364. {
  365. int numToDeliver;
  366. int numBytes = hdr_cmn::access(pkt)->size();
  367. hdr_tcp *th = hdr_tcp::access(pkt);
  368. /* W.N. Check if packet is from previous incarnation */
  369. if (th->ts() < lastreset_) {
  370. // Remove packet and do nothing
  371. Packet::free(pkt);
  372. return;
  373. }
  374. acker_->update_ts(th->seqno(),th->ts(),ts_echo_rfc1323_);
  375. numToDeliver = acker_->update(th->seqno(), numBytes);
  376. if (numToDeliver) {
  377.                 bytes_ += numToDeliver; // for JOBS
  378.                 recvBytes(numToDeliver);
  379.         }
  380.         // If there's no timer and the packet is in sequence, set a timer.
  381.         // Otherwise, send the ack and update the timer.
  382.         if (delay_timer_.status() != TIMER_PENDING &&
  383.                                 th->seqno() == acker_->Seqno()) {
  384.                 // There's no timer, so we can set one and choose
  385. // to delay this ack.
  386. // If we're following RFC2581 (section 4.2) exactly,
  387. // we should only delay the ACK if we're know we're
  388. // not doing recovery, i.e. not gap-filling.
  389. // Since this is a change to previous ns behaviour,
  390. // it's controlled by an optional bound flag.
  391. // discussed April 2000 in the ns-users list archives.
  392. if (RFC2581_immediate_ack_ && 
  393. (th->seqno() < acker_->Maxseen())) {
  394. // don't delay the ACK since
  395. // we're filling in a gap
  396. } else {
  397. // delay the ACK and start the timer.
  398.                 save_ = pkt;
  399.                  delay_timer_.resched(interval_);
  400.                  return;
  401. }
  402.         }
  403.         // If there was a timer, turn it off.
  404. if (delay_timer_.status() == TIMER_PENDING) 
  405. delay_timer_.cancel();
  406. ack(pkt);
  407.         if (save_ != NULL) {
  408.                 Packet::free(save_);
  409.                 save_ = NULL;
  410.         }
  411. Packet::free(pkt);
  412. }
  413. void DelAckSink::timeout(int)
  414. {
  415. // The timer expired so we ACK the last packet seen.
  416. if ( save_ != NULL ) {
  417. Packet* pkt = save_;
  418. ack(pkt);
  419. save_ = NULL;
  420. Packet::free(pkt);
  421. }
  422. }
  423. void DelayTimer::expire(Event* /*e*/) {
  424. a_->timeout(0);
  425. }
  426. /* "sack1-tcp-sink" is for Matt and Jamshid's implementation of sack. */
  427. class SackStack {
  428. protected:
  429. int size_;
  430. int cnt_;
  431. struct Sf_Entry {
  432. int left_;
  433. int right_;
  434. } *SFE_;
  435. public:
  436. SackStack(int);  // create a SackStack of size (int)
  437. ~SackStack();
  438. int& head_right(int n = 0) { return SFE_[n].right_; }
  439. int& head_left(int n = 0) { return SFE_[n].left_; }
  440. int cnt() { return cnt_; }   // how big is the stack
  441. void reset() {
  442. register int i;
  443. for (i = 0; i < cnt_; i++)
  444. SFE_[i].left_ = SFE_[i].right_ = -1;
  445. cnt_ = 0;
  446. }
  447. inline void push(int n = 0) {
  448.   if (cnt_ >= size_) cnt_ = size_ - 1;  // overflow check
  449. register int i;
  450. for (i = cnt_-1; i >= n; i--)
  451. SFE_[i+1] = SFE_[i]; // not efficient for big size
  452. cnt_++;
  453. }
  454. inline void pop(int n = 0) {
  455. register int i;
  456. for (i = n; i < cnt_-1; i++)
  457. SFE_[i] = SFE_[i+1]; // not efficient for big size
  458. SFE_[i].left_ = SFE_[i].right_ = -1;
  459. cnt_--;
  460. }
  461. };
  462. SackStack::SackStack(int sz)
  463. {
  464. register int i;
  465. size_ = sz;
  466. SFE_ = new Sf_Entry[sz];
  467. for (i = 0; i < sz; i++)
  468. SFE_[i].left_ = SFE_[i].right_ = -1;
  469. cnt_ = 0;
  470. }
  471. SackStack::~SackStack()
  472. {
  473. delete SFE_;
  474. }
  475. static class Sack1TcpSinkClass : public TclClass {
  476. public:
  477.         Sack1TcpSinkClass() : TclClass("Agent/TCPSink/Sack1") {}
  478. TclObject* create(int, const char*const*) {
  479. Sacker* sacker = new Sacker;
  480. TcpSink* sink = new TcpSink(sacker);
  481. sacker->configure(sink);
  482. return (sink);
  483.         }
  484. } class_sack1tcpsink;
  485. static class Sack1DelAckTcpSinkClass : public TclClass {
  486. public:
  487. Sack1DelAckTcpSinkClass() : TclClass("Agent/TCPSink/Sack1/DelAck") {}
  488. TclObject* create(int, const char*const*) {
  489. Sacker* sacker = new Sacker;
  490. TcpSink* sink = new DelAckSink(sacker);
  491. sacker->configure(sink);
  492. return (sink);
  493. }
  494. } class_sack1delacktcpsink;
  495. void Sacker::configure(TcpSink *sink)
  496. {
  497. if (sink == NULL) {
  498. fprintf(stderr, "warning: Sacker::configure(): no TCP sink!n");
  499. return;
  500. }
  501. TracedInt& nblocks = sink->max_sack_blocks_;
  502. if (int(nblocks) > NSA) {
  503. fprintf(stderr, "warning(Sacker::configure): TCP header limits number of SACK blocks to %d, not %dn", NSA, int(nblocks));
  504. nblocks = NSA;
  505. }
  506. sf_ = new SackStack(int(nblocks));
  507. nblocks.tracer(this);
  508. base_nblocks_ = int(nblocks);
  509. dsacks_ = &(sink->generate_dsacks_);
  510. }
  511. void
  512. Sacker::trace(TracedVar *v)
  513. {
  514. // we come here if "nblocks" changed
  515. TracedInt* ti = (TracedInt*) v;
  516. if (int(*ti) > NSA) {
  517. fprintf(stderr, "warning(Sacker::trace): TCP header limits number of SACK blocks to %d, not %dn", NSA, int(*ti));
  518. *ti = NSA;
  519. }
  520. int newval = int(*ti);
  521. delete sf_;
  522. sf_ = new SackStack(newval);
  523. base_nblocks_ = newval;
  524. }
  525. void Sacker::reset() 
  526. {
  527. sf_->reset();
  528. Acker::reset();
  529. }
  530. Sacker::~Sacker()
  531. {
  532. delete sf_;
  533. }
  534. void Sacker::append_ack(hdr_cmn* ch, hdr_tcp* h, int old_seqno) const
  535. {
  536. // ch and h are the common and tcp headers of the Ack being constructed
  537. // old_seqno is the sequence # of the packet we just got
  538.         int sack_index, i, sack_right, sack_left;
  539. int recent_sack_left, recent_sack_right;
  540.           
  541. int seqno = Seqno();
  542. // the last in-order packet seen (i.e. the cumulative ACK # - 1)
  543.         sack_index = 0;
  544. sack_left = sack_right = -1;
  545. // initialization; sack_index=0 and sack_{left,right}= -1
  546.         if (old_seqno < 0) {
  547.                 printf("Error: invalid packet number %dn", old_seqno);
  548.         } else if (seqno >= maxseen_ && (sf_->cnt() != 0))
  549. sf_->reset();
  550. // if the Cumulative ACK seqno is at or beyond the right edge
  551. // of the window, and if the SackStack is not empty, reset it
  552. // (empty it)
  553. else if (( (seqno < maxseen_) || is_dup_ ) && (base_nblocks_ > 0)) {
  554. // Otherwise, if the received packet is to the left of
  555. // the right edge of the receive window (but not at
  556. // the right edge), OR if it is a duplicate, AND we
  557. // can have 1 or more Sack blocks, then execute the
  558. // following, which computes the most recent Sack
  559. // block
  560. if ((*dsacks_) && is_dup_) {
  561. // Record the DSACK Block
  562. h->sa_left(sack_index) = old_seqno;
  563. h->sa_right(sack_index) = old_seqno+1;
  564. // record the block
  565. sack_index++;
  566. #ifdef DEBUGDSACK
  567. printf("%ft Generating D-SACK for packet %dn", Scheduler::instance().clock(),old_seqno);
  568. #endif
  569. }
  570. //  Build FIRST (traditional) SACK block
  571. // If we already had a DSACK block due to a duplicate
  572. // packet, and if that duplicate packet is in the
  573. // receiver's window (i.e. the packet's sequence
  574. // number is > than the cumulative ACK) then the
  575. // following should find the SACK block it's a subset
  576. // of.  If it's <= cum ACK field then the following
  577. // shouldn't record a superset SACK block for it.
  578.                 if (sack_index >= base_nblocks_) {
  579. printf("Error: can't use DSACK with less than 2 SACK blocksn");
  580. } else {
  581.                 sack_right=-1;
  582. // look rightward for first hole 
  583. // start at the current packet 
  584.                 for (i=old_seqno; i<=maxseen_; i++) {
  585. if (!seen_[i & wndmask_]) {
  586. sack_right=i;
  587. break;
  588. }
  589. }
  590. // if there's no hole set the right edge of the sack
  591. // to be the next expected packet
  592.                 if (sack_right == -1) {
  593. sack_right = maxseen_+1;
  594.                 }
  595. // if the current packet's seqno is smaller than the
  596. // left edge of the window, set the sack_left to 0
  597. if (old_seqno <= seqno) {
  598. sack_left = 0;
  599. // don't record/send the block
  600. } else {
  601. // look leftward from right edge for first hole 
  602.                 for (i = sack_right-1; i > seqno; i--) {
  603. if (!seen_[i & wndmask_]) {
  604. sack_left = i+1;
  605. break;
  606. }
  607.                 }
  608. h->sa_left(sack_index) = sack_left;
  609. h->sa_right(sack_index) = sack_right;
  610. // printf("pkt_seqno: %i cuml_seqno: %i sa_idx: %i sa_left: %i sa_right: %in" ,old_seqno, seqno, sack_index, sack_left, sack_right);
  611. // record the block
  612. sack_index++;
  613. }
  614. recent_sack_left = sack_left;
  615. recent_sack_right = sack_right;
  616. // first sack block is built, check the others 
  617. // make sure that if max_sack_blocks has been made
  618. // large from tcl we don't over-run the stuff we
  619. // allocated in Sacker::Sacker()
  620. int k = 0;
  621.                 while (sack_index < base_nblocks_) {
  622. sack_left = sf_->head_left(k);
  623. sack_right = sf_->head_right(k);
  624. // no more history 
  625. if (sack_left < 0 || sack_right < 0 ||
  626. sack_right > maxseen_ + 1)
  627. break;
  628. // newest ack "covers up" this one 
  629. if (recent_sack_left <= sack_left &&
  630.     recent_sack_right >= sack_right) {
  631. sf_->pop(k);
  632. continue;
  633. }
  634. h->sa_left(sack_index) = sack_left;
  635. h->sa_right(sack_index) = sack_right;
  636. // printf("pkt_seqno: %i cuml_seqno: %i sa_idx: %i sa_left: %i sa_right: %in" ,old_seqno, seqno, sack_index, sack_left, sack_right);
  637. // store the old sack (i.e. move it down one)
  638. sack_index++;
  639. k++;
  640.                 }
  641. if (old_seqno > seqno) {
  642.   /* put most recent block onto stack */
  643. sf_->push();
  644. // this just moves things down 1 from the
  645. // beginning, but it doesn't push any values
  646. // on the stack
  647. sf_->head_left() = recent_sack_left;
  648. sf_->head_right() = recent_sack_right;
  649. // this part stores the left/right values at
  650. // the top of the stack (slot 0)
  651. }
  652. } // this '}' is for the DSACK base_nblocks_ >= test;
  653.   // (didn't feel like re-indenting all the code and 
  654.   // causing a large diff)
  655.         }
  656. h->sa_length() = sack_index;
  657. // set the Length of the sack stack in the header
  658. ch->size() += sack_index * 8;
  659. // change the size of the common header to account for the
  660. // Sack strings (2 4-byte words for each element)
  661. }