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

通讯编程

开发平台:

Visual C++

  1. /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 1990, 1997 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted
  7.  * provided that the above copyright notice and this paragraph are
  8.  * duplicated in all such forms and that any documentation,
  9.  * advertising materials, and other materials related to such
  10.  * distribution and use acknowledge that the software was developed
  11.  * by the University of California, Lawrence Berkeley Laboratory,
  12.  * Berkeley, CA.  The name of the University may not be used to
  13.  * endorse or promote products derived from this software without
  14.  * specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19. #ifndef lint
  20. static const char rcsid[] =
  21.     "@(#) /home/ctk21/cvsroot//hssstcp/ns/ns-2.1b9/tcp/tcp-fack.cc,v 1.2 2002/08/12 10:43:58 ctk21 Exp (PSC)";
  22. #endif
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <sys/types.h>
  26. #include "ip.h"
  27. #include "tcp.h"
  28. #include "flags.h"
  29. #include "scoreboard.h"
  30. #include "random.h"
  31. #include "tcp-fack.h"
  32. #include "template.h"
  33. static class FackTcpClass : public TclClass {
  34. public:
  35. FackTcpClass() : TclClass("Agent/TCP/Fack") {}
  36. TclObject* create(int, const char*const*) {
  37. return (new FackTcpAgent());
  38. }
  39. } class_fack;
  40. FackTcpAgent::FackTcpAgent() :  timeout_(FALSE), wintrim_(0),
  41. wintrimmult_(.5), rampdown_(0), fack_(-1), retran_data_(0),
  42. ss_div4_(0) // What about fastrecov_ and scb_
  43. {
  44. bind_bool("ss-div4_", &ss_div4_);
  45. bind_bool("rampdown_", &rampdown_);
  46. scb_ = new ScoreBoard(new ScoreBoardNode[SBSIZE],SBSIZE);
  47. }
  48. FackTcpAgent::~FackTcpAgent(){
  49. delete [] scb_;
  50. }
  51. int FackTcpAgent::window() 
  52. {
  53. int win;
  54. win = int((cwnd_ < wnd_ ? (double) cwnd_ : (double) wnd_) + wintrim_);
  55. return (win);
  56. }
  57. void FackTcpAgent::reset ()
  58. {
  59. scb_->ClearScoreBoard();
  60. TcpAgent::reset ();
  61. }
  62. /*
  63.  * Process a dupack.
  64.  */
  65. void FackTcpAgent::oldack(Packet* pkt)
  66. {
  67. hdr_tcp *tcph = hdr_tcp::access(pkt);
  68. last_ack_ = tcph->seqno();
  69. highest_ack_ = last_ack_;
  70. fack_ = max(fack_,highest_ack_);
  71. /* 
  72.  * There are conditions under which certain versions of TCP (e.g., tcp-fs)
  73.  * retract maxseq_. The following line of code helps in those cases. For
  74.  * versions of TCP, it is a NOP.
  75. */
  76. maxseq_ = max(maxseq_, highest_ack_);
  77. if (t_seqno_ < last_ack_ + 1)
  78. t_seqno_ = last_ack_ + 1;
  79. newtimer(pkt);
  80. if (rtt_active_ && tcph->seqno() >= rtt_seq_) { 
  81. rtt_active_ = 0;
  82. t_backoff_ = 1;
  83. }
  84. /* with timestamp option */
  85. double tao = Scheduler::instance().clock() - tcph->ts_echo();
  86. rtt_update(tao);
  87. if (ts_resetRTO_) {
  88. // From Andrei Gurtov
  89. // FACK has not been updated to make sure the ECN works
  90. //   correctly in this case - Sally.
  91. t_backoff_ = 1;
  92. }
  93. /* update average window */
  94. awnd_ *= 1.0 - wnd_th_;
  95. awnd_ += wnd_th_ * cwnd_;
  96. /* if the connection is done, call finish() */
  97. if ((highest_ack_ >= curseq_-1) && !closed_) {
  98. closed_ = 1;
  99. finish();
  100. }
  101. }
  102. int FackTcpAgent::maxsack(Packet *pkt)
  103. {
  104. hdr_tcp *tcph = hdr_tcp::access(pkt);
  105. int maxsack=-1, sack_index; 
  106. for (sack_index=0; sack_index < tcph->sa_length(); sack_index++) {
  107. if (tcph->sa_right(sack_index) > maxsack)
  108. maxsack = tcph->sa_right(sack_index);
  109. }
  110. return (maxsack-1);
  111. }
  112. void FackTcpAgent::recv_newack_helper(Packet *pkt) {
  113. newack(pkt);
  114. opencwnd();
  115. /* if the connection is done, call finish() */
  116. if ((highest_ack_ >= curseq_-1) && !closed_) {
  117. closed_ = 1;
  118. finish();
  119. }
  120. }
  121. void FackTcpAgent::recv(Packet *pkt, Handler*)
  122. {
  123. hdr_tcp *tcph = hdr_tcp::access(pkt);
  124. int ms; 
  125. #ifdef notdef
  126. if (pkt->type_ != PT_ACK) {
  127. Tcl::instance().evalf("%s error "received non-ack"",
  128.       name());
  129. Packet::free(pkt);
  130. return;
  131. }
  132. #endif
  133. ts_peer_ = tcph->ts();
  134. if (hdr_flags::access(pkt)->ecnecho() && ecn_)
  135. ecn(tcph->seqno());
  136. recv_helper(pkt);
  137. if (!fastrecov_) { // Not in fast recovery 
  138. if ((int)tcph->seqno() > last_ack_ && tcph->sa_length() == 0) {
  139. /*
  140.  * regular ACK not in fast recovery... normal
  141.  */
  142. recv_newack_helper(pkt);
  143. fack_ = last_ack_;
  144. timeout_ = FALSE;
  145. scb_->ClearScoreBoard();
  146. retran_data_ = 0;
  147. wintrim_ = 0;
  148. } else if ((int)tcph->seqno() < last_ack_) {
  149. // Do nothing; ack may have been misordered
  150. } else {
  151. retran_data_ -= scb_->UpdateScoreBoard (highest_ack_, tcph);
  152. oldack(pkt);
  153. ms = maxsack(pkt);
  154. if (ms > fack_)
  155. fack_ = ms;
  156. if (fack_ >= t_seqno_)
  157. t_seqno_ = fack_ + 1;
  158. dupacks_ = (fack_ - last_ack_) - 1;
  159. /* 
  160.  * a duplicate ACK
  161.  */
  162. if (dupacks_ >= numdupacks_) {
  163. /*
  164.  * Assume we dropped just one packet.
  165.  * Retransmit last ack + 1
  166.  * and try to resume the sequence.
  167.  */
  168. recover_ = t_seqno_;
  169. last_cwnd_action_ = CWND_ACTION_DUPACK;
  170. if ((ss_div4_ == 1) && (cwnd_ <= ssthresh_ + .5)) {
  171. cwnd_ /= 2;
  172. wintrimmult_ = .75;
  173. } else {
  174. wintrimmult_ = .5;
  175. }
  176. slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);
  177. if (rampdown_) {
  178. wintrim_ = (t_seqno_ - fack_ - 1) * wintrimmult_;
  179. }
  180. reset_rtx_timer(1,0);
  181. fastrecov_ = TRUE;
  182. scb_->MarkRetran (last_ack_+1, t_seqno_);
  183. retran_data_++;
  184. output(last_ack_ + 1, TCP_REASON_DUPACK);
  185. }
  186. }
  187. if (dupacks_ == 0)
  188. send_much(FALSE, 0, maxburst_);
  189. } else {
  190. // we are in fast recovery
  191. oldack(pkt);
  192. ms = maxsack(pkt);
  193. if (ms > fack_) {
  194. if (rampdown_) {
  195. wintrim_ -= ((float)ms - (float)fack_)* wintrimmult_;
  196. if (wintrim_< 0) 
  197. wintrim_ = 0;
  198. }
  199. fack_ = ms;
  200. }
  201. if (fack_ >= t_seqno_)
  202. t_seqno_ = fack_ + 1;
  203. retran_data_ -= scb_->UpdateScoreBoard (highest_ack_, tcph);
  204. // If the retransmission was lost again, timeout_ forced to TRUE
  205. // if timeout_ TRUE, this shuts off send()
  206. timeout_ |= scb_->CheckSndNxt (tcph);
  207. opencwnd();
  208. if (retran_data_ < 0) {
  209. printf("Error, retran_data_ < 0");
  210. }
  211. if ((int)tcph->sa_length() == 0 && (last_ack_ >= recover_)) {
  212. // No SACK blocks indicates fast recovery is over
  213. fastrecov_ = FALSE;
  214. timeout_ = FALSE;
  215. scb_->ClearScoreBoard();
  216. retran_data_ = 0;
  217. wintrim_ = 0;
  218. dupacks_ = 0;
  219. }
  220. send_much(FALSE, 0, maxburst_);
  221. }
  222. Packet::free(pkt);
  223. #ifdef notyet
  224. if (trace_)
  225. plot();
  226. #endif
  227. }
  228. void FackTcpAgent::timeout(int tno)
  229. {
  230. if (tno == TCP_TIMER_RTX) {
  231. if (highest_ack_ == maxseq_ && !slow_start_restart_) {
  232. /*
  233.  * TCP option:
  234.  * If no outstanding data, then don't do anything.
  235.  */
  236. return;
  237. };
  238. // Do not clear fastrecov_ or alter recover_ variable
  239. timeout_ = FALSE;
  240. if (highest_ack_ > last_ack_)
  241. last_ack_ = highest_ack_;
  242. #ifdef DEBUGSACK1A
  243. printf ("timeout. highest_ack: %d seqno: %dn", 
  244. highest_ack_, t_seqno_);
  245. #endif
  246. retran_data_ = 0;
  247. last_cwnd_action_ = CWND_ACTION_TIMEOUT;
  248. /* if there is no outstanding data, don't cut down ssthresh_ */
  249. if (highest_ack_ == maxseq_ && restart_bugfix_) 
  250. slowdown(CLOSE_CWND_INIT);
  251. else {
  252. // close down to 1 segment
  253. slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);
  254. }
  255. scb_->ClearScoreBoard();
  256. /* if there is no outstanding data, don't back off rtx timer */
  257. if (highest_ack_ == maxseq_)
  258. reset_rtx_timer(TCP_REASON_TIMEOUT,0);
  259. else
  260. reset_rtx_timer(TCP_REASON_TIMEOUT,1);
  261. fack_ = last_ack_;
  262. t_seqno_ = last_ack_ + 1;
  263. send_much(0, TCP_REASON_TIMEOUT);
  264. } else {
  265. TcpAgent::timeout(tno);
  266. }
  267. }
  268. void FackTcpAgent::send_much(int force, int reason, int maxburst)
  269. {
  270. register int found, npacket = 0;
  271. send_idle_helper();
  272. int win = window();
  273. int xmit_seqno;
  274. if (!force && delsnd_timer_.status() == TIMER_PENDING)
  275. return;
  276. /* 
  277.  * If TCP_TIMER_BURSTSND is pending, cancel it. The timer is
  278.  * set again, if necessary, after the maxburst pakts have been
  279.  * sent out.
  280. */
  281. if (burstsnd_timer_.status() == TIMER_PENDING)
  282. burstsnd_timer_.cancel();
  283. found = 1;
  284. /*
  285. * as long as the pipe is open and there is app data to send...
  286. */
  287. while (( t_seqno_ <= fack_ + win - retran_data_) && (!timeout_)) {
  288. if (overhead_ == 0 || force) {
  289. found = 0;
  290. xmit_seqno = scb_->GetNextRetran ();
  291. #ifdef DEBUGSACK1A
  292. printf("highest_ack: %d xmit_seqno: %d timeout: %d seqno: %d fack: % d win: %d retran_data: %dn",
  293.        highest_ack_, xmit_seqno, timeout_, t_seqno_, fack_, win, retran_data_);
  294. #endif
  295. if (xmit_seqno == -1) {  // no retransmissions to send
  296. /* 
  297.  * if there is no more application data to send,
  298.  * do nothing
  299.  */
  300. if (t_seqno_ >= curseq_) 
  301. return;
  302.         /* if window-limited */
  303. if (fastrecov_ && 
  304.       t_seqno_>highest_ack_+int(wnd_)) 
  305. break;
  306. found = 1;
  307. xmit_seqno = t_seqno_++;
  308. #ifdef DEBUGSACK1A
  309. printf("sending %d fastrecovery: %d win %dn",
  310.        xmit_seqno, fastrecov_, win);
  311. #endif
  312. } else {
  313. found = 1;
  314. scb_->MarkRetran (xmit_seqno, t_seqno_);
  315. retran_data_++;
  316. win = window();
  317. }
  318. if (found) {
  319. output(xmit_seqno, reason);
  320. if (t_seqno_ <= xmit_seqno) {
  321. printf("Hit a strange case 2.n");
  322. t_seqno_ = xmit_seqno + 1;
  323. }
  324. npacket++;
  325. }
  326. } else if (!(delsnd_timer_.status() == TIMER_PENDING)) {
  327. /*
  328.  * Set a delayed send timeout.
  329.  */
  330. delsnd_timer_.resched(Random::uniform(overhead_));
  331. return;
  332. }
  333. if (maxburst && npacket == maxburst)
  334. break;
  335. } /* while */
  336. /* call helper function */
  337. send_helper(maxburst);
  338. }
  339. /*
  340.  * open up the congestion window -- Hack hack hack
  341.  */
  342. void FackTcpAgent::opencwnd()
  343. {
  344. TcpAgent::opencwnd();
  345. // if maxcwnd_ is set (nonzero), make it the cwnd limit
  346. if (maxcwnd_ && (int (cwnd_) > maxcwnd_))
  347. cwnd_ = maxcwnd_;
  348. }
  349. void FackTcpAgent::plot()
  350. {
  351. #ifdef notyet
  352. double t = Scheduler::instance().clock();
  353. sprintf(trace_->buffer(), "t %g %d rtt %gn", 
  354. t, class_, t_rtt_ * tcp_tick_);
  355. trace_->dump();
  356. sprintf(trace_->buffer(), "t %g %d dev %gn", 
  357. t, class_, t_rttvar_ * tcp_tick_);
  358. trace_->dump();
  359. sprintf(trace_->buffer(), "t %g %d win %fn", t, class_, cwnd_);
  360. trace_->dump();
  361. sprintf(trace_->buffer(), "t %g %d bck %dn", t, class_, t_backoff_);
  362. trace_->dump();
  363. #endif
  364. }