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

通讯编程

开发平台:

Visual C++

  1. /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 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 Daedalus Research
  17.  *  Group at the University of California Berkeley.
  18.  * 4. Neither the name of the University nor of the Research Group may be
  19.  *    used 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. #ifndef lint
  35. static const char rcsid[] =
  36.     "@(#) $Header: /cvsroot/nsnam/ns-2/tcp/snoop.cc,v 1.25 2003/01/28 23:31:03 sfloyd Exp $ (UCB)";
  37. #endif
  38. #include "snoop.h"
  39. int hdr_snoop::offset_;
  40. class SnoopHeaderClass : public PacketHeaderClass {
  41. public:
  42.         SnoopHeaderClass() : PacketHeaderClass("PacketHeader/Snoop",
  43. sizeof(hdr_snoop)) {
  44. bind_offset(&hdr_snoop::offset_);
  45. }
  46. } class_snoophdr;
  47. static class LLSnoopClass : public TclClass {
  48. public:
  49. LLSnoopClass() : TclClass("LL/LLSnoop") {}
  50. TclObject* create(int, const char*const*) {
  51. return (new LLSnoop());
  52. }
  53. } llsnoop_class;
  54. static class SnoopClass : public TclClass {
  55. public:
  56. SnoopClass() : TclClass("Snoop") {}
  57. TclObject* create(int, const char*const*) {
  58. return (new Snoop());
  59. }
  60. } snoop_class;
  61. Snoop::Snoop() : NsObject(),
  62. fstate_(0), lastSeen_(-1), lastAck_(-1), 
  63. expNextAck_(0), expDupacks_(0), bufhead_(0), 
  64. toutPending_(0), buftail_(0),
  65. wl_state_(SNOOP_WLEMPTY), wl_lastSeen_(-1), wl_lastAck_(-1), 
  66. wl_bufhead_(0), wl_buftail_(0)
  67. {
  68. bind("snoopDisable_", &snoopDisable_);
  69. bind_time("srtt_", &srtt_);
  70. bind_time("rttvar_", &rttvar_);
  71. bind("maxbufs_", &maxbufs_);
  72. bind("snoopTick_", &snoopTick_);
  73. bind("g_", &g_);
  74. bind("tailTime_", &tailTime_);
  75. bind("rxmitStatus_", &rxmitStatus_);
  76. bind("lru_", &lru_);
  77. rxmitHandler_ = new SnoopRxmitHandler(this);
  78. int i;
  79. for (i = 0; i < SNOOP_MAXWIND; i++) /* data from wired->wireless */
  80. pkts_[i] = 0;
  81. for (i = 0; i < SNOOP_WLSEQS; i++) {/* data from wireless->wired */
  82. wlseqs_[i] = (hdr_seq *) malloc(sizeof(hdr_seq));
  83. wlseqs_[i]->seq = wlseqs_[i]->num = 0;
  84. }
  85. if (maxbufs_ == 0)
  86. maxbufs_ = SNOOP_MAXWIND;
  87. }
  88. void
  89. Snoop::reset()
  90. {
  91. // printf("%x resettingn", this);
  92. fstate_ = 0;
  93. lastSeen_ = -1;
  94. lastAck_ = -1;
  95. expNextAck_ = 0;
  96. expDupacks_ = 0;
  97. bufhead_ = buftail_ = 0;
  98. if (toutPending_) {
  99. Scheduler::instance().cancel(toutPending_);
  100. // xxx: I think that toutPending_ doesn't need to be freed because snoop didn't allocate it (but I'm not sure).
  101. toutPending_ = 0;
  102. };
  103. for (int i = 0; i < SNOOP_MAXWIND; i++) {
  104. if (pkts_[i]) {
  105. Packet::free(pkts_[i]);
  106. pkts_[i] = 0;
  107. }
  108. }
  109. }
  110. void 
  111. Snoop::wlreset()
  112. {
  113. wl_state_ = SNOOP_WLEMPTY;
  114. wl_bufhead_ = wl_buftail_ = 0;
  115. for (int i = 0; i < SNOOP_WLSEQS; i++) {
  116. wlseqs_[i]->seq = wlseqs_[i]->num = 0;
  117. }
  118. }
  119. int 
  120. Snoop::command(int argc, const char*const* argv)
  121. {
  122. //Tcl& tcl = Tcl::instance();
  123. if (argc == 3) {
  124. if (strcmp(argv[1], "llsnoop") == 0) {
  125. parent_ = (LLSnoop *) TclObject::lookup(argv[2]);
  126. if (parent_)
  127. recvtarget_ = parent_->uptarget();
  128. return (TCL_OK);
  129. }
  130. if (strcmp(argv[1], "check-rxmit") == 0) {
  131. if (empty_()) {
  132. rxmitStatus_ = SNOOP_PROPAGATE;
  133. return (TCL_OK);
  134. }
  135. Packet *p = pkts_[buftail_];
  136. hdr_snoop *sh = hdr_snoop::access(p);
  137. if (sh->sndTime()!=-1 && sh->sndTime()<atoi(argv[2]) &&
  138.     sh->numRxmit() == 0)
  139. /* candidate for retransmission */
  140. rxmitStatus_ = snoop_rxmit(p);
  141. else
  142. rxmitStatus_ = SNOOP_PROPAGATE;
  143. return (TCL_OK);
  144. }
  145. }
  146. return NsObject::command(argc, argv);
  147. }
  148. void LLSnoop::recv(Packet *p, Handler *h)
  149. {
  150. Tcl &tcl = Tcl::instance();
  151. hdr_ip *iph = hdr_ip::access(p);
  152. /* get-snoop creates a snoop object if none currently exists */
  153. hdr_cmn *ch = HDR_CMN(p);
  154. if(ch->direction() == hdr_cmn::UP) 
  155. /* get-snoop creates a snoop object if none currently exists */
  156. /* In ns, addresses have ports embedded in them. */
  157. tcl.evalf("%s get-snoop %d %d", name(), iph->daddr(),
  158.   iph->saddr()); 
  159.        
  160. else  
  161. tcl.evalf("%s get-snoop %d %d", name(), iph->saddr(),
  162.   iph->daddr());
  163. Snoop *snoop = (Snoop *) TclObject::lookup(tcl.result());
  164. snoop->recv(p, h);
  165. if (integrate_)
  166. tcl.evalf("%s integrate %d %d", name(), iph->saddr(),
  167.   iph->daddr());
  168. if (h) /* resume higher layer (queue) */
  169. Scheduler::instance().schedule(h, &intr_, 0.000001);
  170. return;
  171. }
  172. /*
  173.  * Receive a packet from higher layer or from the network.
  174.  * Call snoop_data() if TCP packet and forward it on if it's an ack.
  175.  */
  176. void
  177. Snoop::recv(Packet* p, Handler* h )
  178. {
  179. hdr_cmn *ch = HDR_CMN(p);
  180. if(ch->direction() == hdr_cmn::UP) {
  181. handle((Event *) p);
  182. return;
  183. }
  184. packet_t type = hdr_cmn::access(p)->ptype();
  185. /* Put packet (if not ack) in cache after checking, and send it on */
  186. if (type == PT_TCP) 
  187. snoop_data(p);
  188. else if (type == PT_ACK)
  189. snoop_wired_ack(p);
  190. ch->direction() = hdr_cmn::DOWN;  // Ben added
  191. parent_->sendDown(p); /* vector to LLSnoop's sendto() */
  192. }
  193. /*
  194.  * Handle a packet received from peer across wireless link.  Check first
  195.  * for packet errors, then call snoop_ack() or pass it up as necessary.
  196.  */
  197. void
  198. Snoop::handle(Event *e)
  199. {
  200. Packet *p = (Packet *) e;
  201. packet_t type = hdr_cmn::access(p)->ptype();
  202. //int seq = hdr_tcp::access(p)->seqno();
  203. int prop = SNOOP_PROPAGATE; // by default;  propagate ack or packet
  204. Scheduler& s = Scheduler::instance();
  205. //hdr_ll *llh = hdr_ll::access(p);
  206. if (hdr_cmn::access(p)->error()) {
  207. parent_->drop(p); // drop packet if it's been corrupted
  208. return;
  209. }
  210. if (type == PT_ACK) 
  211. prop = snoop_ack(p); 
  212. else if (type == PT_TCP) /* XXX what about TELNET? */
  213. snoop_wless_data(p);
  214. if (prop == SNOOP_PROPAGATE)
  215. s.schedule(recvtarget_, e, parent_->delay());
  216. else { // suppress ack
  217. /* printf("---- %f suppressing ack %dn", s.clock(), seq);*/
  218. Packet::free(p);
  219. }
  220. }
  221. /*
  222.  * Data packet processing.  p is guaranteed to be of type PT_TCP when 
  223.  * this function is called.
  224.  */
  225. void
  226. Snoop::snoop_data(Packet *p)
  227. {
  228. Scheduler &s = Scheduler::instance();
  229. int seq = hdr_tcp::access(p)->seqno();
  230. int resetPending = 0;
  231. // printf("%x snoop_data: %f sending packet %dn", this, s.clock(), seq);
  232. if (fstate_ & SNOOP_ALIVE && seq == 0)
  233. reset();
  234. fstate_ |= SNOOP_ALIVE;
  235. if ((fstate_ & SNOOP_FULL) && !lru_) {
  236. // printf("snoop full, fwd'ingn t %d h %d", buftail_, bufhead_);
  237. if (seq > lastSeen_)
  238. lastSeen_ = seq;
  239. return;
  240. }
  241. /* 
  242.  * Only if the ifq is NOT full do we insert, since otherwise we want
  243.  * congestion control to kick in.
  244.  */
  245. if (parent_->ifq()->length() < parent_->ifq()->limit()-1)
  246. resetPending = snoop_insert(p);
  247. if (toutPending_ && resetPending == SNOOP_TAIL) {
  248. s.cancel(toutPending_);
  249. // xxx: I think that toutPending_ doesn't need to be freed because snoop didn't allocate it (but I'm not sure).
  250. toutPending_ = 0;
  251. }
  252. if (!toutPending_ && !empty_()) {
  253. toutPending_ = (Event *) (pkts_[buftail_]);
  254. s.schedule(rxmitHandler_, toutPending_, timeout());
  255. }
  256. return;
  257. }
  258. /* 
  259.  * snoop_insert() does all the hard work for snoop_data(). It traverses the 
  260.  * snoop cache and looks for the right place to insert this packet (or
  261.  * determines if its already been cached). It then decides whether
  262.  * this is a packet in the normal increasing sequence, whether it
  263.  * is a sender-rexmitted-but-lost-due-to-congestion (or network 
  264.  * out-of-order) packet, or if it is a sender-rexmitted packet that
  265.  * was buffered by us before.
  266.  */
  267. int
  268. Snoop::snoop_insert(Packet *p)
  269. {
  270. int i, seq = hdr_tcp::access(p)->seqno(), retval=0;
  271. if (seq <= lastAck_) 
  272. return retval;
  273. if (fstate_ & SNOOP_FULL) {
  274. /* free tail and go on */
  275. printf("snoop full, making roomn");
  276. Packet::free(pkts_[buftail_]);
  277. pkts_[buftail_] = 0;
  278. buftail_ = next(buftail_);
  279. fstate_ |= ~SNOOP_FULL;
  280. }
  281. if (seq > lastSeen_ || pkts_[buftail_] == 0) { // in-seq or empty cache
  282. i = bufhead_;
  283. bufhead_ = next(bufhead_);
  284. } else if (seq < hdr_snoop::access(pkts_[buftail_])->seqno()) {
  285. buftail_ = prev(buftail_);
  286. i = buftail_;
  287. } else {
  288. for (i = buftail_; i != bufhead_; i = next(i)) {
  289. hdr_snoop *sh = hdr_snoop::access(pkts_[i]);
  290. if (sh->seqno() == seq) {  // cached before
  291. sh->numRxmit() = 0;
  292. sh->senderRxmit() = 1; //must be a sender retr
  293. sh->sndTime() = Scheduler::instance().clock();
  294. return SNOOP_TAIL;
  295. } else if (sh->seqno() > seq) { 
  296. //not cached before, should insert in the middle
  297. // find the position it should be: prev(i)
  298.  
  299. Packet *temp = pkts_[prev(buftail_)];
  300. for (int j = buftail_; j != i; j = next(j)) 
  301. pkts_[prev(j)] = pkts_[j];
  302. i = prev(i);
  303. pkts_[i] = temp;   // seems not necessary. Ben comments
  304. buftail_ = prev(buftail_);
  305. break;
  306. }
  307. }
  308. // This should not happen, since seq must be > lastSeen, which is 
  309. // handled before in the first if.   Ben comments
  310. if (i == bufhead_)
  311. bufhead_ = next(bufhead_);
  312. }
  313. // save in the buffer
  314. savepkt_(p, seq, i);
  315. if (bufhead_ == buftail_)
  316. fstate_ |= SNOOP_FULL;
  317. /* 
  318.  * If we have one of the following packets:
  319.  * 1. a network-out-of-order packet, or
  320.  * 2. a fast rxmit packet, or 3. a sender retransmission 
  321.  * AND it hasn't already been buffered, 
  322.  * then seq will be < lastSeen_. 
  323.  * We mark this packet as having been due to a sender rexmit 
  324.  * and use this information in snoop_ack(). We let the dupacks
  325.  * for this packet go through according to expDupacks_.
  326.  */
  327. if (seq < lastSeen_) { /* not in-order -- XXX should it be <= ? */
  328. if (buftail_ == i) {
  329. hdr_snoop *sh = hdr_snoop::access(pkts_[i]);
  330. sh->senderRxmit() = 1;
  331. sh->numRxmit() = 0;
  332. }
  333. expNextAck_ = buftail_;
  334. retval = SNOOP_TAIL;
  335. } else
  336. lastSeen_ = seq;
  337. return retval;
  338. }
  339. void
  340. Snoop::savepkt_(Packet *p, int seq, int i)
  341. {
  342. pkts_[i] = p->copy();
  343. Packet *pkt = pkts_[i];
  344. hdr_snoop *sh = hdr_snoop::access(pkt);
  345. sh->seqno() = seq;
  346. sh->numRxmit() = 0;
  347. sh->senderRxmit() = 0;
  348. sh->sndTime() = Scheduler::instance().clock();
  349. }
  350. /*
  351.  * Ack processing in snoop protocol.  We know for sure that this is an ack.
  352.  * Return SNOOP_SUPPRESS if ack is to be suppressed and SNOOP_PROPAGATE o.w.
  353.  */
  354. int
  355. Snoop::snoop_ack(Packet *p)
  356. {
  357. Packet *pkt;
  358. int ack = hdr_tcp::access(p)->seqno();
  359. /*
  360.  * There are 3 cases:
  361.  * 1. lastAck_ > ack.  In this case what has happened is
  362.  *    that the acks have come out of order, so we don't
  363.  *    do any local processing but forward it on.
  364.  * 2. lastAck_ == ack.  This is a duplicate ack. If we have
  365.  *    the packet we resend it, and drop the dupack.
  366.  *    Otherwise we never got it from the fixed host, so we
  367.  *    need to let the dupack get through.
  368.  *    Set expDupacks_ to number of packets already sent
  369.  *    This is the number of dup acks to ignore.
  370.  * 3. lastAck_ < ack.  Set lastAck_ = ack, and update
  371.  *    the head of the buffer queue. Also clean up ack'd packets.
  372.  */
  373. if (fstate_ & SNOOP_CLOSED || lastAck_ > ack) 
  374. return SNOOP_PROPAGATE; // send ack onward
  375. if (lastAck_ == ack) {
  376. /* A duplicate ack; pure window updates don't occur in ns. */
  377. pkt = pkts_[buftail_];
  378. if (pkt == 0) 
  379. return SNOOP_PROPAGATE;
  380. hdr_snoop *sh = hdr_snoop::access(pkt);
  381. if (pkt == 0 || sh->seqno() > ack + 1) 
  382. /* don't have packet, letting thru' */
  383.         return SNOOP_PROPAGATE;
  384. /* 
  385.  * We have the packet: one of 3 possibilities:
  386.  * 1. We are not expecting any dupacks (expDupacks_ == 0)
  387.  * 2. We are expecting dupacks (expDupacks_ > 0)
  388.  * 3. We are in an inconsistent state (expDupacks_ == -1)
  389.  */
  390. if (expDupacks_ == 0) { // not expecting it
  391. #define RTX_THRESH 1
  392. static int thresh = 0;
  393. if (thresh++ < RTX_THRESH) 
  394. /* no action if under RTX_THRESH */
  395. return SNOOP_PROPAGATE;
  396. thresh = 0;
  397. // if the packet is a sender retransmission, pass on
  398. if (sh->senderRxmit()) 
  399. return SNOOP_PROPAGATE;
  400. /*
  401.  * Otherwise, not triggered by sender.  If this is
  402.  * the first dupack recd., we must determine how many
  403.  * dupacks will arrive that must be ignored, and also
  404.  * rexmit the desired packet.  Note that expDupacks_
  405.  * will be -1 if we miscount for some reason.
  406.  */
  407. expDupacks_ = bufhead_ - expNextAck_;
  408. if (expDupacks_ < 0)
  409. expDupacks_ += SNOOP_MAXWIND;
  410. expDupacks_ -= RTX_THRESH + 1;
  411. expNextAck_ = next(buftail_);
  412. if (sh->numRxmit() == 0) 
  413. return snoop_rxmit(pkt);
  414. } else if (expDupacks_ > 0) {
  415. expDupacks_--;
  416. return SNOOP_SUPPRESS;
  417. } else if (expDupacks_ == -1) {
  418. if (sh->numRxmit() < 2) {
  419. return snoop_rxmit(pkt);
  420. }
  421. } else // let sender deal with it
  422. return SNOOP_PROPAGATE;
  423. } else { // a new ack
  424. fstate_ &= ~SNOOP_NOACK; // have seen at least 1 new ack
  425. /* free buffers */
  426. double sndTime = snoop_cleanbufs_(ack);
  427. if (sndTime != -1)
  428. snoop_rtt(sndTime);
  429. expDupacks_ = 0;
  430. expNextAck_ = buftail_;
  431. lastAck_ = ack;
  432. }
  433. return SNOOP_PROPAGATE;
  434. }
  435. /* 
  436.  * Handle data packets that arrive from a wireless link, and we're not
  437.  * the end recipient.  See if there are any holes in the transmission, and
  438.  * if there are, mark them as candidates for wireless loss.  Then, when
  439.  * (dup)acks troop back for this loss, set the ELN bit in their header, to
  440.  * help the sender (or a snoop agent downstream) retransmit.
  441.  */
  442. void
  443. Snoop::snoop_wless_data(Packet *p)
  444. {
  445. hdr_tcp *th = hdr_tcp::access(p);
  446. int i, seq = th->seqno();
  447. if (wl_state_ & SNOOP_WLALIVE && seq == 0)
  448. wlreset();
  449. wl_state_ |= SNOOP_WLALIVE;
  450. if (wl_state_ & SNOOP_WLEMPTY && seq >= wl_lastAck_) {
  451. wlseqs_[wl_bufhead_]->seq = seq;
  452. wlseqs_[wl_bufhead_]->num = 1;
  453. wl_buftail_ = wl_bufhead_;
  454. wl_bufhead_ = wl_next(wl_bufhead_);
  455. wl_lastSeen_ = seq;
  456. wl_state_ &= ~SNOOP_WLEMPTY;
  457. return;
  458. }
  459. /* WL data list definitely not empty at this point. */
  460. if (seq >= wl_lastSeen_) {
  461. wl_lastSeen_ = seq;
  462. i = wl_prev(wl_bufhead_);
  463. if (wlseqs_[i]->seq + wlseqs_[i]->num == seq) {
  464. wlseqs_[i]->num++;
  465. return;
  466. }
  467. i = wl_bufhead_;
  468. wl_bufhead_ = wl_next(wl_bufhead_);
  469. } else if (seq == wlseqs_[i = wl_buftail_]->seq - 1) {
  470. } else
  471. return;
  472. wlseqs_[i]->seq = seq;
  473. wlseqs_[i]->num++;
  474. /* Ignore network out-of-ordering and retransmissions for now */
  475. return;
  476. }
  477. /*
  478.  * Ack from wired side (for sender on "other" side of wireless link.
  479.  */
  480. void 
  481. Snoop::snoop_wired_ack(Packet *p)
  482. {
  483. hdr_tcp *th = hdr_tcp::access(p);
  484. int ack = th->seqno();
  485. int i;
  486. if (ack == wl_lastAck_ && snoop_wlessloss(ack)) {
  487. hdr_flags::access(p)->eln_ = 1;
  488. } else if (ack > wl_lastAck_) {
  489. /* update info about unack'd data */
  490. for (i = wl_buftail_; i != wl_bufhead_; i = wl_next(i)) {
  491. hdr_seq *t = wlseqs_[i];
  492. if (t->seq + t->num - 1 <= ack) {
  493. t->seq = t->num = 0;
  494. } else if (ack < t->seq) {
  495. break;
  496. } else if (ack < t->seq + t->num - 1) {
  497. /* ack for part of a block */
  498. t->num -= ack - t->seq +1;
  499. t->seq = ack + 1;
  500. break;
  501. }
  502. }
  503. wl_buftail_ = i;
  504. if (wl_buftail_ == wl_bufhead_)
  505. wl_state_ |= SNOOP_WLEMPTY;
  506. wl_lastAck_ = ack;
  507. /* Even a new ack could cause an ELN to be set. */
  508. if (wl_bufhead_ != wl_buftail_ && snoop_wlessloss(ack))
  509. hdr_flags::access(p)->eln_ = 1;
  510. }
  511. }
  512. /* 
  513.  * Return 1 if we think this packet loss was not congestion-related, and 
  514.  * 0 otherwise.  This function simply implements the lookup into the table
  515.  * that maintains this info; most of the hard work is done in 
  516.  * snoop_wless_data() and snoop_wired_ack().
  517.  */
  518. int
  519. Snoop::snoop_wlessloss(int ack)
  520. {
  521. if ((wl_bufhead_ == wl_buftail_) || wlseqs_[wl_buftail_]->seq > ack+1)
  522. return 1;
  523. return 0;
  524. }
  525. /*
  526.  * clean snoop cache of packets that have been acked.
  527.  */
  528. double
  529. Snoop::snoop_cleanbufs_(int ack)
  530. {
  531. Scheduler &s = Scheduler::instance();
  532. double sndTime = -1;
  533. if (toutPending_) {
  534. s.cancel(toutPending_);
  535. // xxx: I think that toutPending_ doesn't need to be freed because snoop didn't allocate it (but I'm not sure).
  536. toutPending_ = 0;
  537. };
  538. if (empty_())
  539. return sndTime;
  540. int i = buftail_;
  541. do {
  542. hdr_snoop *sh = hdr_snoop::access(pkts_[i]);
  543. int seq = hdr_tcp::access(pkts_[i])->seqno();
  544. if (seq <= ack) {
  545. sndTime = sh->sndTime();
  546. Packet::free(pkts_[i]);
  547. pkts_[i] = 0;
  548. fstate_ &= ~SNOOP_FULL; /* XXX redundant? */
  549. } else if (seq > ack)
  550. break;
  551. i = next(i);
  552. } while (i != bufhead_);
  553. if ((i != buftail_) || (bufhead_ != buftail_)) {
  554. fstate_ &= ~SNOOP_FULL;
  555. buftail_ = i;
  556. }
  557. if (!empty_()) {
  558. toutPending_ = (Event *) (pkts_[buftail_]);
  559. s.schedule(rxmitHandler_, toutPending_, timeout());
  560. hdr_snoop *sh = hdr_snoop::access(pkts_[buftail_]);
  561. tailTime_ = sh->sndTime();
  562. }
  563. return sndTime;
  564. }
  565. /* 
  566.  * Calculate smoothed rtt estimate and linear deviation.
  567.  */
  568. void
  569. Snoop::snoop_rtt(double sndTime)
  570. {
  571. double rtt = Scheduler::instance().clock() - sndTime;
  572. if (parent_->integrate()) {
  573. parent_->snoop_rtt(sndTime);
  574. return;
  575. }
  576. if (rtt > 0) {
  577. srtt_ = g_*srtt_ + (1-g_)*rtt;
  578. double delta = rtt - srtt_;
  579. if (delta < 0)
  580. delta = -delta;
  581. if (rttvar_ != 0)
  582. rttvar_ = g_*delta + (1-g_)*rttvar_;
  583. else 
  584. rttvar_ = delta;
  585. }
  586. }
  587. /* 
  588.  * Calculate smoothed rtt estimate and linear deviation.
  589.  */
  590. void
  591. LLSnoop::snoop_rtt(double sndTime)
  592. {
  593. double rtt = Scheduler::instance().clock() - sndTime;
  594. if (rtt > 0) {
  595. srtt_ = g_*srtt_ + (1-g_)*rtt;
  596. double delta = rtt - srtt_;
  597. if (delta < 0)
  598. delta = -delta;
  599. if (rttvar_ != 0)
  600. rttvar_ = g_*delta + (1-g_)*rttvar_;
  601. else 
  602. rttvar_ = delta;
  603. }
  604. }
  605. /*
  606.  * Returns 1 if recent queue length is <= half the maximum and 0 otherwise.
  607.  */
  608. int 
  609. Snoop::snoop_qlong()
  610. {
  611. /* For now only instantaneous lengths */
  612. // if (parent_->ifq()->length() <= 3*parent_->ifq()->limit()/4)
  613. return 1;
  614. // return 0;
  615. }
  616. /*
  617.  * Ideally, would like to schedule snoop retransmissions at higher priority.
  618.  */
  619. int
  620. Snoop::snoop_rxmit(Packet *pkt)
  621. {
  622. Scheduler& s = Scheduler::instance();
  623. if (pkt != 0) {
  624. hdr_snoop *sh = hdr_snoop::access(pkt);
  625. if (sh->numRxmit() < SNOOP_MAX_RXMIT && snoop_qlong()) {
  626. /* && sh->seqno() == lastAck_+1)  */
  627. #if 0
  628. printf("%f Rxmitting packet %dn", s.clock(), 
  629.        hdr_tcp::access(pkt)->seqno());
  630. #endif
  631. // need to specify direction, in this case, down
  632. hdr_cmn *ch = HDR_CMN(pkt);       
  633. ch->direction() = hdr_cmn::DOWN;  // Ben added
  634. sh->sndTime() = s.clock();
  635. sh->numRxmit() = sh->numRxmit() + 1;
  636. Packet *p = pkt->copy();
  637. parent_->sendDown(p);
  638. } else 
  639. return SNOOP_PROPAGATE;
  640. }
  641. /* Reset timeout for later time. */
  642. if (toutPending_) {
  643. s.cancel(toutPending_);
  644. // xxx: I think that toutPending_ doesn't need to be freed because snoop didn't allocate it (but I'm not sure).
  645. };
  646. toutPending_ = (Event *)pkt;
  647. s.schedule(rxmitHandler_, toutPending_, timeout());
  648. return SNOOP_SUPPRESS;
  649. }
  650. void 
  651. Snoop::snoop_cleanup()
  652. {
  653. }
  654. void
  655. SnoopRxmitHandler::handle(Event *)
  656. {
  657. Packet *p = snoop_->pkts_[snoop_->buftail_];
  658. snoop_->toutPending_ = 0;
  659. if (p == 0)
  660. return;
  661. hdr_snoop *sh = hdr_snoop::access(p);
  662. if (sh->seqno() != snoop_->lastAck_ + 1)
  663. return;
  664. if ((snoop_->bufhead_ != snoop_->buftail_) || 
  665.     (snoop_->fstate_ & SNOOP_FULL)) {
  666. // printf("%f Snoop timeoutn", Scheduler::instance().clock());
  667. if (snoop_->snoop_rxmit(p) == SNOOP_SUPPRESS)
  668. snoop_->expNextAck_ = snoop_->next(snoop_->buftail_);
  669. }
  670. }