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

通讯编程

开发平台:

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.  * $Header: /cvsroot/nsnam/ns-2/tcp/chost.cc,v 1.13 2000/09/01 03:04:05 haoboy Exp $
  35.  */
  36. /*
  37.  * Functions invoked by TcpSessionAgent
  38.  */
  39. #include "nilist.h"
  40. #include "chost.h"
  41. #include "tcp-int.h"
  42. #include "random.h"
  43. CorresHost::CorresHost() : slink(), TcpFsAgent(),
  44. lastackTS_(0), dontAdjustOwnd_(0), dontIncrCwnd_(0), rexmtSegCount_(0),
  45. connWithPktBeforeFS_(NULL)
  46. {
  47. nActive_ = nTimeout_ = nFastRec_ = 0;
  48. ownd_ = 0;
  49. owndCorrection_ = 0;
  50. closecwTS_ = 0;
  51. connIter_ = new Islist_iter<IntTcpAgent> (conns_);
  52. rtt_seg_ = NULL;
  53. }
  54. /*
  55.  * Open up the congestion window.
  56.  */
  57. void 
  58. CorresHost::opencwnd(int /*size*/, IntTcpAgent *sender)
  59. {
  60. if (cwnd_ < ssthresh_) {
  61. /* slow-start (exponential) */
  62. cwnd_ += 1;
  63. } else {
  64. /* linear */
  65. //double f;
  66. if (!proxyopt_) {
  67. switch (wnd_option_) {
  68. case 0:
  69. if ((count_ = count_ + winInc_) >= cwnd_) {
  70. count_ = 0;
  71. cwnd_ += winInc_;
  72. }
  73. break;
  74. case 1:
  75. /* This is the standard algorithm. */
  76. cwnd_ += winInc_ / cwnd_;
  77. break;
  78. default:
  79. #ifdef notdef
  80. /*XXX*/
  81. error("illegal window option %d", wnd_option_);
  82. #endif
  83. abort();
  84. }
  85. } else { // proxy
  86. switch (wnd_option_) {
  87. case 0: 
  88. case 1:
  89. if (sender->highest_ack_ >= sender->wndIncSeqno_) {
  90. cwnd_ += winInc_;
  91. sender->wndIncSeqno_ = 0;
  92. }
  93. break;
  94. default:
  95. #ifdef notdef
  96. /*XXX*/
  97. error("illegal window option %d", wnd_option_);
  98. #endif
  99. abort();
  100. }
  101. }
  102. }
  103. // if maxcwnd_ is set (nonzero), make it the cwnd limit
  104. if (maxcwnd_ && (int(cwnd_) > maxcwnd_))
  105. cwnd_ = maxcwnd_;
  106. return;
  107. }
  108. void 
  109. CorresHost::closecwnd(int how, double ts, IntTcpAgent *sender)
  110. {
  111. if (proxyopt_) {
  112. if (!sender || ts > sender->closecwTS_)
  113. closecwnd(how, sender);
  114. }
  115. else {
  116. if (ts > closecwTS_)
  117. closecwnd(how, sender);
  118. }
  119. }
  120. void 
  121. CorresHost::closecwnd(int how, IntTcpAgent *sender)
  122. {
  123. int sender_ownd = 0;
  124. if (sender)
  125. sender_ownd = sender->maxseq_ - sender->highest_ack_;
  126. closecwTS_ = Scheduler::instance().clock();
  127. if (proxyopt_) {
  128. if (sender)
  129. sender->closecwTS_ = closecwTS_;
  130. how += 10;
  131. }
  132. switch (how) {
  133. case 0:
  134. case 10:
  135. /* timeouts */
  136. /* 
  137.  * XXX we use cwnd_ instead of ownd_ here, which may not be
  138.  * appropriate if the sender does not fully utilize the
  139.  * available congestion window (ownd_ < cwnd_).
  140.  */
  141. ssthresh_ = int(cwnd_ * winMult_);
  142. cwnd_ = int(wndInit_);
  143. break;
  144. case 1:
  145. /* Reno dup acks, or after a recent congestion indication. */
  146. /* 
  147.  * XXX we use cwnd_ instead of ownd_ here, which may not be
  148.  * appropriate if the sender does not fully utilize the
  149.  * available congestion window (ownd_ < cwnd_).
  150.  */
  151. cwnd_ *= winMult_;
  152. ssthresh_ = int(cwnd_);
  153. if (ssthresh_ < 2)
  154. ssthresh_ = 2;
  155. break;
  156. case 11:
  157. /* Reno dup acks, or after a recent congestion indication. */
  158. /* XXX fix this -- don't make it dependent on ownd */
  159. cwnd_ = ownd_ - sender_ownd*(1-winMult_);
  160. ssthresh_ = int(cwnd_);
  161. if (ssthresh_ < 2)
  162. ssthresh_ = 2;
  163. break;
  164. case 3:
  165. case 13:
  166. /* idle time >= t_rtxcur_ */
  167. cwnd_ = wndInit_;
  168. break;
  169. default:
  170. abort();
  171. }
  172. fcnt_ = 0.;
  173. count_ = 0;
  174. if (sender)
  175. sender->count_ = 0;
  176. }
  177. Segment* 
  178. CorresHost::add_pkts(int /*size*/, int seqno, int sessionSeqno, int daddr, int dport, 
  179.      int sport, double ts, IntTcpAgent *sender)
  180. {
  181. class Segment *news;
  182. ownd_ += 1;
  183. news = new Segment;
  184. news->seqno_ = seqno;
  185. news->sessionSeqno_ = sessionSeqno;
  186. news->daddr_ = daddr;
  187. news->dport_ = dport;
  188. news->sport_ = sport;
  189. news->ts_ = ts;
  190. news->size_ = 1;
  191. news->dupacks_ = 0;
  192. news->later_acks_ = 0;
  193. news->thresh_dupacks_ = 0;
  194. news->partialack_ = 0;
  195. news->rxmitted_ = 0;
  196. news->sender_ = sender;
  197. seglist_.append(news);
  198. return news;
  199. }
  200. void
  201. CorresHost::adjust_ownd(int size) 
  202. {
  203. if (double(owndCorrection_) < size)
  204. ownd_ -= min(double(ownd_), size - double(owndCorrection_));
  205. owndCorrection_ -= min(double(owndCorrection_),size);
  206. if (double(ownd_) < -0.5 || double(owndCorrection_ < -0.5))
  207. printf("In adjust_ownd(): ownd_ = %g  owndCorrection_ = %gn", double(ownd_), double(owndCorrection_));
  208. }
  209. int
  210. CorresHost::clean_segs(int /*size*/, Packet *pkt, IntTcpAgent *sender, int sessionSeqno, int amt_data_acked)
  211.     Segment *cur, *prev=NULL, *newseg;
  212.     int i;
  213.     //int rval = -1;
  214.     /* remove all acked pkts from list */
  215.     int latest_susp_loss = rmv_old_segs(pkt, sender, amt_data_acked);
  216.     /* 
  217.      * XXX If no new data is acked and the last time we shrunk the window 
  218.      * covers the most recent suspected loss, update the estimate of the amount
  219.      * of outstanding data.
  220.      */
  221.     if (amt_data_acked == 0 && latest_susp_loss <= recover_ && 
  222. !dontAdjustOwnd_ && last_cwnd_action_ != CWND_ACTION_TIMEOUT) {
  223.     owndCorrection_ += min(double(ownd_),1);
  224.     ownd_ -= min(double(ownd_),1);
  225.     }
  226.     /*
  227.      * A pkt is a candidate for retransmission if it is the leftmost one in the
  228.      * unacked window for the connection AND has at least numdupacks_
  229.      * dupacks/later acks AND (at least one dupack OR a later packet also
  230.      * with the threshold number of dup/later acks). A pkt is also a candidate
  231.      * for immediate retransmission if it has partialack_ set, indicating that
  232.      * a partial new ack has been received for it.
  233.      */
  234.     for (i=0; i < rexmtSegCount_; i++) {
  235.     int remove_flag = 0;
  236.     /* 
  237.      * curArray_ only contains segments that are the first oldest
  238.      * unacked segments of their connection (i.e., they are at the left
  239.      * edge of their window) and have either received a
  240.      * partial ack and/or have received at least cur->numdupacks_
  241.      * dupacks/later acks. Thus, segments in curArray_ have a high
  242.      * probability (but not certain) of being eligible for 
  243.      * retransmission. Using curArray_ avoids having to scan
  244.      * through all the segments.
  245.      */
  246.     cur = curArray_[i];
  247.     prev = prevArray_[i];
  248.     if (cur->partialack_ || cur->dupacks_ > 0 || 
  249. cur->sender_->num_thresh_dupack_segs_ > 1 ) {
  250.     if (cur->thresh_dupacks_) {
  251.     cur->thresh_dupacks_ = 0;
  252.     cur->sender_->num_thresh_dupack_segs_--;
  253.     }
  254.     if (cur->sessionSeqno_ <= recover_ && 
  255. last_cwnd_action_ != CWND_ACTION_TIMEOUT /* XXX 2 */)
  256.     dontAdjustOwnd_ = 1;
  257.     if ((cur->sessionSeqno_ > recover_) || 
  258. (last_cwnd_action_ == CWND_ACTION_TIMEOUT /* XXX 2 */)
  259. || (proxyopt_ && cur->seqno_ > cur->sender_->recover_)
  260. || (proxyopt_ && cur->sender_->last_cwnd_action_ == CWND_ACTION_TIMEOUT /* XXX 2 */)) { 
  261.     /* new loss window */
  262.     closecwnd(1, cur->ts_, cur->sender_);
  263.     recover_ = sessionSeqno - 1;
  264.     last_cwnd_action_ = CWND_ACTION_DUPACK /* XXX 1 */;
  265.     cur->sender_->recover_ = cur->sender_->maxseq_;
  266.     cur->sender_->last_cwnd_action_ = 
  267.     CWND_ACTION_DUPACK /* XXX 1 */;
  268.     dontAdjustOwnd_ = 0;
  269.     }
  270.     if ((newseg = cur->sender_->rxmit_last(TCP_REASON_DUPACK, 
  271.    cur->seqno_, cur->sessionSeqno_, cur->ts_))) {
  272.     newseg->rxmitted_ = 1;
  273.     adjust_ownd(cur->size_);
  274.     if (!dontAdjustOwnd_) {
  275.     owndCorrection_ += 
  276.     min(double(ownd_),cur->dupacks_);
  277.     ownd_ -= min(double(ownd_),cur->dupacks_);
  278.     }
  279.     seglist_.remove(cur, prev);
  280.     remove_flag = 1;
  281.     delete cur;
  282.     }
  283.     /* 
  284.      * if segment just removed used to be the one just previous
  285.      * to the next segment in the array, update prev for the
  286.      * next segment
  287.      */
  288.     if (remove_flag && cur == prevArray_[i+1])
  289.     prevArray_[i+1] = prev;
  290.     }
  291.     }
  292.     rexmtSegCount_ = 0;
  293.     return(0);
  294. }
  295.     
  296. int
  297. CorresHost::rmv_old_segs(Packet *pkt, IntTcpAgent *sender, int amt_data_acked)
  298. {
  299. Islist_iter<Segment> seg_iter(seglist_);
  300. Segment *cur, *prev=0;
  301. int found = 0;
  302. int done = 0;
  303. int new_data_acked = 0;
  304. int partialack = 0;
  305. int latest_susp_loss = -1;
  306. hdr_tcp *tcph = hdr_tcp::access(pkt);
  307. if (tcph->ts_echo() > lastackTS_)
  308. lastackTS_ = tcph->ts_echo();
  309. while (((cur = seg_iter()) != NULL) &&
  310.        (!done || tcph->ts_echo() > cur->ts_)) {
  311. int remove_flag = 0;
  312. /* ack for older pkt of another connection */
  313. if (sender != cur->sender_ && tcph->ts_echo() > cur->ts_) { 
  314. if (!disableIntLossRecov_)
  315. cur->later_acks_++;
  316. latest_susp_loss = 
  317. max(latest_susp_loss,cur->sessionSeqno_);
  318. dontIncrCwnd_ = 1;
  319. /* ack for same connection */
  320. else if (sender == cur->sender_) {
  321. /* found packet acked */
  322. if (tcph->seqno() == cur->seqno_ && 
  323.     tcph->ts_echo() == cur->ts_) 
  324. found = 1;
  325. /* higher ack => clean up acked packets */
  326. if (tcph->seqno() >= cur->seqno_) {
  327. adjust_ownd(cur->size_);
  328. seglist_.remove(cur, prev);
  329. remove_flag = 1;
  330. new_data_acked += cur->size_;
  331. if (new_data_acked >= amt_data_acked)
  332. done = 1;
  333. if (prev == cur) 
  334. prev = NULL;
  335. if (cur == rtt_seg_)
  336. rtt_seg_ = NULL;
  337. delete cur;
  338. if (seg_iter.get_cur() && prev)
  339. seg_iter.set_cur(prev);
  340. else if (seg_iter.get_cur())
  341. seg_iter.set_cur(seg_iter.get_last());
  342. /* partial new ack => rexmt immediately */
  343. /* XXX should we check recover for session? */
  344. else if (amt_data_acked > 0 && 
  345.  tcph->seqno() == cur->seqno_-1 &&
  346.  cur->seqno_ <= sender->recover_ &&
  347.  sender->last_cwnd_action_ == CWND_ACTION_DUPACK) {
  348. cur->partialack_ = 1;
  349. partialack = 1;
  350. latest_susp_loss = 
  351. max(latest_susp_loss,cur->sessionSeqno_);
  352. if (new_data_acked >= amt_data_acked)
  353. done = 1;
  354. dontIncrCwnd_ = 1;
  355. }
  356. /* 
  357.  * If no new data has been acked AND this segment has
  358.  * not been retransmitted before AND the ack indicates 
  359.  * that this is the next segment to be acked, then
  360.  * increment dupack count.
  361.  */
  362. else if (!amt_data_acked && !cur->rxmitted_ &&
  363.  tcph->seqno() == cur->seqno_-1) {
  364. cur->dupacks_++;
  365. latest_susp_loss = 
  366. max(latest_susp_loss,cur->sessionSeqno_);
  367. done = 1;
  368. dontIncrCwnd_ = 1;
  369. }
  370. if (cur->dupacks_+cur->later_acks_ >= sender->numdupacks_ &&
  371.     !cur->thresh_dupacks_) {
  372. cur->thresh_dupacks_ = 1;
  373. cur->sender_->num_thresh_dupack_segs_++;
  374. }
  375. if (amt_data_acked==0 && tcph->seqno()==cur->seqno_-1)
  376. done = 1;
  377. /* XXX we could check for rexmt candidates here if we ignore 
  378.    the num_thresh_dupack_segs_ check */
  379. if (!remove_flag &&
  380.     cur->seqno_ == cur->sender_->highest_ack_ + 1 &&
  381.     (cur->dupacks_ + cur->later_acks_ >= sender->numdupacks_ ||
  382.      cur->partialack_)) {
  383. curArray_[rexmtSegCount_] = cur;
  384. prevArray_[rexmtSegCount_] = prev;
  385. rexmtSegCount_++;
  386. }
  387. if (!remove_flag)
  388. prev = cur;
  389. }
  390. /* partial ack => terminate fast start mode */
  391. if (partialack && fs_enable_ && fs_mode_) {
  392. timeout(TCP_TIMER_RESET);
  393. rexmtSegCount_ = 0;
  394. }
  395. return latest_susp_loss;
  396. }
  397. void
  398. CorresHost::add_agent(IntTcpAgent *agent, int /*size*/, double winMult, 
  399.       int winInc, int /*ssthresh*/)
  400. {
  401. if (nActive_ >= MAX_PARALLEL_CONN) {
  402. printf("In add_agent(): reached limit of number of parallel conn (%d); returningn", nActive_);
  403. return;
  404. }
  405. nActive_++;
  406. if ((!fixedIw_ && nActive_ > 1) || cwnd_ == 0)
  407. cwnd_ += 1; /* XXX should this be done? */
  408. wndInit_ = 1;
  409. winMult_ = winMult;
  410. winInc_ = winInc;
  411. /* ssthresh_ = ssthresh;*/
  412. conns_.append(agent);
  413. }
  414. int
  415. CorresHost::ok_to_snd(int /*size*/)
  416. {
  417. if (ownd_ <= -0.5)
  418. printf("In ok_to_snd(): ownd_ = %g  owndCorrection_ = %gn", double(ownd_), double(owndCorrection_));
  419. return (cwnd_ >= ownd_+1);
  420. }