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

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 1999  International Computer Science Institute
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *      This product includes software developed by ACIRI, the AT&T
  16.  *      Center for Internet Research at ICSI (the International Computer
  17.  *      Science Institute).
  18.  * 4. Neither the name of ACIRI nor of ICSI 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 ICSI 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 ICSI 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. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <sys/types.h>
  37. #include <math.h>
  38. #include "ip.h"
  39. #include "tcp-rfc793edu.h"
  40. #include "flags.h"
  41. // Original code contributed by Fernando Cela Diaz,
  42. // <fcela@ce.chalmers.se>.
  43. // For more information, see the following:
  44. // URL "http://www.ce.chalmers.se/~fcela/tcp-tour.html"
  45. static class  RFC793eduTcpClass : public TclClass {
  46. public:
  47. RFC793eduTcpClass() : TclClass("Agent/TCP/RFC793edu") {}
  48. TclObject* create(int, const char*const*) {
  49. return (new RFC793eduTcpAgent());
  50. }
  51. } class_rfc793edu;
  52. RFC793eduTcpAgent::RFC793eduTcpAgent() : TcpAgent() 
  53. {
  54. }
  55. void
  56. RFC793eduTcpAgent::delay_bind_init_all()
  57. {
  58. delay_bind_init_one("add793expbackoff_");
  59. delay_bind_init_one("add793jacobsonrtt_");
  60. delay_bind_init_one("add793fastrtx_");
  61. delay_bind_init_one("add793slowstart_");
  62. delay_bind_init_one("add793additiveinc_");
  63. delay_bind_init_one("add793karnrtt_");
  64. delay_bind_init_one("add793exponinc_"); 
  65. delay_bind_init_one("rto_");
  66. TcpAgent::delay_bind_init_all();
  67.         reset();
  68. }
  69. int
  70. RFC793eduTcpAgent::delay_bind_dispatch(const char *varName, 
  71.        const char *localName,TclObject *tracer)
  72. {
  73.         if (delay_bind_bool(varName, localName, "add793expbackoff_", 
  74.     &add793expbackoff_, tracer)) 
  75. return TCL_OK;
  76.         if (delay_bind_bool(varName, localName, "add793jacobsonrtt_", 
  77.     &add793jacobsonrtt_, tracer)) 
  78. return TCL_OK;
  79.         if (delay_bind_bool(varName, localName, "add793fastrtx_", 
  80.     &add793fastrtx_, tracer)) 
  81. return TCL_OK;
  82.         if (delay_bind_bool(varName, localName, "add793slowstart_", 
  83.     &add793slowstart_, tracer)) 
  84. return TCL_OK;
  85.         if (delay_bind_bool(varName, localName, "add793slowstart_", 
  86.     &add793slowstart_, tracer)) 
  87. return TCL_OK;
  88.         if (delay_bind_bool(varName, localName, "add793additiveinc_", 
  89.     &add793additiveinc_, tracer)) 
  90. return TCL_OK;
  91.         if (delay_bind_bool(varName, localName, "add793karnrtt_", 
  92.     &add793karnrtt_, tracer)) 
  93. return TCL_OK;
  94.         if (delay_bind_bool(varName, localName, "add793exponinc_", 
  95.     &add793exponinc_, tracer)) 
  96. return TCL_OK;
  97.         if (delay_bind(varName, localName, "rto_", 
  98.        &rto_, tracer)) 
  99. return TCL_OK;
  100.         return TcpAgent::delay_bind_dispatch(varName, localName, tracer);
  101. }
  102. void RFC793eduTcpAgent::reset()
  103. {
  104.   //Reset here protected vars. 
  105.   rto_ = rtxcur_init_ / tcp_tick_;
  106.   TcpAgent::reset();
  107. }
  108. void RFC793eduTcpAgent::rtt_update(double tao)
  109. {
  110.   double now = Scheduler::instance().clock();
  111.   if (ts_option_)
  112.     t_rtt_ = int(tao /tcp_tick_ + 0.5);
  113.   else {
  114.     double sendtime = now - tao;
  115.     sendtime += boot_time_;
  116.     double tickoff = fmod(sendtime, tcp_tick_);
  117.     t_rtt_ = int((tao + tickoff) / tcp_tick_);
  118.   }
  119.   if (t_rtt_ < 1)
  120.     t_rtt_ = 1;
  121.   
  122.       // Jacobson/Karels RTT estimation as implemented in tcp.cc
  123.       //
  124.       // Diference    = SampleRTT - EstimatedRTT
  125.       // EstimatedRTT = EstimatedRTT + (delta * Difference)
  126.       // Deviation    = Deviation + delta * (|Difference| - Deviation)
  127.       // TimeOut      = EstimatedRTT + 4 * Deviation
  128.       // srtt has 3 bits to the right of the binary point
  129.       // rttvar has 2
  130.       if (t_srtt_ != 0) {
  131. register short delta;
  132. delta = t_rtt_ - (t_srtt_ >> T_SRTT_BITS); // d = (m - a0)
  133. if ((t_srtt_ += delta) <= 0) // a1 = 7/8 a0 + 1/8 m
  134.   t_srtt_ = 1;
  135. if (delta < 0)
  136.   delta = -delta;
  137. delta -= (t_rttvar_ >> T_RTTVAR_BITS);
  138. if ((t_rttvar_ += delta) <= 0) // var1 = 3/4 var0 + 1/4 |d|
  139.   t_rttvar_ = 1;
  140.       } else {
  141. t_srtt_ = t_rtt_ << T_SRTT_BITS; // srtt = rtt
  142. t_rttvar_ = t_rtt_ << (T_RTTVAR_BITS-1); // rttvar = rtt / 2
  143.       }
  144.    if (add793jacobsonrtt_) 
  145.     {
  146.       //
  147.       // Current retransmit value is 
  148.       //    (unscaled) smoothed round trip estimate
  149.       //    plus 2^rttvar_exp_ times (unscaled) rttvar. 
  150.       //
  151.       rto_ = (((t_rttvar_ << (rttvar_exp_ + (T_SRTT_BITS - T_RTTVAR_BITS)))                   + t_srtt_)  >> T_SRTT_BITS );
  152.     }
  153.    else { 
  154.      // RFC 793
  155.      rto_ = (t_srtt_ >> ( T_SRTT_BITS - 1) );
  156.    }
  157.       t_rtxcur_ = rto_  * tcp_tick_;
  158.   return;
  159. }
  160. void RFC793eduTcpAgent::rtt_backoff()
  161. {
  162.   if (add793expbackoff_) {
  163.     // Standard Tahoe Code
  164. if (t_backoff_ < 64)
  165. t_backoff_ <<= 1;
  166. if (t_backoff_ > 8) {
  167. /*
  168.  * If backed off this far, clobber the srtt
  169.  * value, storing it in the mean deviation
  170.  * instead.
  171.  */
  172. t_rttvar_ += (t_srtt_ >> T_SRTT_BITS);
  173. t_srtt_ = 0;
  174. }
  175.   }
  176.   // safe paranoia
  177.   else 
  178.     t_backoff_ = 1;
  179. }
  180. void RFC793eduTcpAgent::recv(Packet *pkt, Handler*)
  181. {
  182. hdr_tcp *tcph = hdr_tcp::access(pkt);
  183. #ifdef notdef
  184. if (pkt->type_ != PT_ACK) {
  185. Tcl::instance().evalf("%s error "received non-ack"",
  186.       name());
  187. Packet::free(pkt);
  188. return;
  189. }
  190. #endif
  191. ++nackpack_;
  192. ts_peer_ = tcph->ts();
  193. int ecnecho = hdr_flags::access(pkt)->ecnecho();
  194. if (ecnecho && ecn_)
  195. ecn(tcph->seqno());
  196. recv_helper(pkt);
  197. /* grow cwnd and check if the connection is done */ 
  198. if (tcph->seqno() > last_ack_) {
  199. recv_newack_helper(pkt);
  200. if (last_ack_ == 0 && delay_growth_) { 
  201. cwnd_ = initial_window();
  202. }
  203. } else if (tcph->seqno() == last_ack_) {
  204.                 if (hdr_flags::access(pkt)->eln_ && eln_) {
  205.                         tcp_eln(pkt);
  206.                         return;
  207.                 }
  208. // fast retransmission
  209. if ( (++dupacks_ == numdupacks_) && add793fastrtx_ ) {
  210. dupack_action();
  211. }
  212. }
  213. Packet::free(pkt);
  214. /*
  215.  * Try to send more data.
  216.  */
  217. send_much(0, 0, maxburst_);
  218. }
  219. void RFC793eduTcpAgent::opencwnd()
  220. {
  221.         if ( !(add793slowstart_ || add793exponinc_ || add793additiveinc_)) {
  222.   cwnd_ = wnd_;
  223.         } else if (((cwnd_ < ssthresh_) && (!add793additiveinc_)) 
  224.    || add793exponinc_)
  225.   {
  226. /* slow-start (exponential) */
  227.         if (add793exponinc_ && (cwnd_ < ssthresh_))
  228.   cwnd_ = ssthresh_;
  229. else cwnd_ += 1;
  230. } else {
  231. /* linear */
  232. double f;
  233. if (add793additiveinc_ && (cwnd_ < ssthresh_))
  234.   cwnd_ = ssthresh_;
  235. else {
  236.   switch (wnd_option_) {
  237.   case 0:
  238.     if (++count_ >= cwnd_) {
  239.       count_ = 0;
  240.       ++cwnd_;
  241.     }
  242.     break;
  243.     
  244.   case 1:
  245. /* This is the standard algorithm. */
  246.     cwnd_ += 1 / cwnd_;
  247.     break;
  248.     
  249.   case 2:
  250.     /* These are window increase algorithms
  251.      * for experimental purposes only. */
  252.     f = (t_srtt_ >> T_SRTT_BITS) * tcp_tick_;
  253.     f *= f;
  254.     f *= wnd_const_;
  255.     f += fcnt_;
  256.     if (f > cwnd_) {
  257.       fcnt_ = 0;
  258.       ++cwnd_;
  259.     } else
  260.       fcnt_ = f;
  261.     break;
  262.   case 3:
  263.     f = awnd_;
  264.     f *= f;
  265.     f *= wnd_const_;
  266.     f += fcnt_;
  267.     if (f > cwnd_) {
  268.       fcnt_ = 0;
  269.       ++cwnd_;
  270.     } else
  271.       fcnt_ = f;
  272.     break;
  273.     
  274.   case 4:
  275.     f = awnd_;
  276.     f *= wnd_const_;
  277.     f += fcnt_;
  278.     if (f > cwnd_) {
  279.       fcnt_ = 0;
  280.       ++cwnd_;
  281.     } else
  282.                                 fcnt_ = f;
  283.     break;
  284.   case 5:
  285.     f = (t_srtt_ >> T_SRTT_BITS) * tcp_tick_;
  286.     f *= wnd_const_;
  287.     f += fcnt_;
  288.     if (f > cwnd_) {
  289.       fcnt_ = 0;
  290.       ++cwnd_;
  291.     } else
  292.       fcnt_ = f;
  293.     break;
  294.     
  295.   default:
  296. #ifdef notdef
  297.     /*XXX*/
  298.     error("illegal window option %d", wnd_option_);
  299. #endif
  300.     abort();
  301.   }
  302. }
  303. }
  304. // if maxcwnd_ is set (nonzero), make it the cwnd limit
  305. if (maxcwnd_ && (int(cwnd_) > maxcwnd_))
  306.   cwnd_ = maxcwnd_;
  307. return;
  308. }
  309. void  RFC793eduTcpAgent::output(int seqno, int reason)
  310. {
  311. int force_set_rtx_timer = 0;
  312. Packet* p = allocpkt();
  313. hdr_tcp *tcph = hdr_tcp::access(p);
  314. hdr_flags* hf = hdr_flags::access(p);
  315. tcph->seqno() = seqno;
  316. tcph->ts() = Scheduler::instance().clock();
  317. tcph->ts_echo() = ts_peer_;
  318. tcph->reason() = reason;
  319. if (ecn_) {
  320. hf->ect() = 1; // ECN-capable transport
  321. }
  322. if (cong_action_) {
  323. hf->cong_action() = TRUE;  // Congestion action.
  324. cong_action_ = FALSE;
  325.         }
  326. /* Check if this is the initial SYN packet. */
  327. if (seqno == 0) {
  328. if (syn_) {
  329. hdr_cmn::access(p)->size() = tcpip_base_hdr_size_;
  330. }
  331. if (ecn_) {
  332. hf->ecnecho() = 1;
  333. // hf->cong_action() = 1;
  334. hf->ect() = 0;
  335. }
  336. }
  337.         int bytes = hdr_cmn::access(p)->size();
  338. /* if no outstanding data, be sure to set rtx timer again */
  339. if (highest_ack_ == maxseq_)
  340. force_set_rtx_timer = 1;
  341. /* call helper function to fill in additional fields */
  342. output_helper(p);
  343.         ++ndatapack_;
  344.         ndatabytes_ += bytes;
  345. send(p, 0);
  346. if (seqno == curseq_ && seqno > maxseq_)
  347. idle();  // Tell application I have sent everything so far
  348. if (seqno > maxseq_) {
  349. maxseq_ = seqno;
  350. if (!rtt_active_) {
  351. rtt_active_ = 1;
  352. if (seqno > rtt_seq_) {
  353. rtt_seq_ = seqno;
  354. rtt_ts_ = Scheduler::instance().clock();
  355. }
  356. }
  357. } else {
  358.   if (!add793karnrtt_) {
  359.         rtt_active_ = 1;
  360. rtt_seq_ = seqno;
  361. rtt_ts_ = Scheduler::instance().clock();
  362.   }
  363.          ++nrexmitpack_;
  364.          nrexmitbytes_ += bytes;
  365. }
  366. if (!(rtx_timer_.status() == TIMER_PENDING) || force_set_rtx_timer)
  367. /* No timer pending.  Schedule one. */
  368. set_rtx_timer();
  369. }
  370. void RFC793eduTcpAgent::recv_newack_helper(Packet *pkt) {
  371. //hdr_tcp *tcph = hdr_tcp::access(pkt);
  372. newack(pkt);
  373. if (!ect_ || !hdr_flags::access(pkt)->ecnecho() ||
  374. (old_ecn_ && ecn_burst_)) 
  375. /* If "old_ecn", this is not the first ACK carrying ECN-Echo
  376.  * after a period of ACKs without ECN-Echo.
  377.  * Therefore, open the congestion window. */
  378.         opencwnd();
  379. if (ect_) {
  380. if (!hdr_flags::access(pkt)->ecnecho())
  381. ecn_backoff_ = 0;
  382. if (!ecn_burst_ && hdr_flags::access(pkt)->ecnecho())
  383. ecn_burst_ = TRUE;
  384. else if (ecn_burst_ && ! hdr_flags::access(pkt)->ecnecho())
  385. ecn_burst_ = FALSE;
  386. }
  387. if (!ect_ && hdr_flags::access(pkt)->ecnecho() &&
  388. !hdr_flags::access(pkt)->cong_action())
  389. ect_ = 1;
  390. /* if the connection is done, call finish() */
  391. if ((highest_ack_ >= curseq_-1) && !closed_) {
  392. closed_ = 1;
  393. finish();
  394. }
  395. }
  396. void RFC793eduTcpAgent::newack(Packet* pkt)
  397. {
  398. double now = Scheduler::instance().clock();
  399. hdr_tcp *tcph = hdr_tcp::access(pkt);
  400. /* 
  401.  * Wouldn't it be better to set the timer *after*
  402.  * updating the RTT, instead of *before*? 
  403.  */
  404. newtimer(pkt);
  405. dupacks_ = 0;
  406. last_ack_ = tcph->seqno();
  407. highest_ack_ = last_ack_;
  408. if (t_seqno_ < last_ack_ + 1)
  409. t_seqno_ = last_ack_ + 1;
  410. /* 
  411.  * Update RTT only if it's OK to do so from info in the flags header.
  412.  * This is needed for protocols in which intermediate agents
  413.  * in the network intersperse acks (e.g., ack-reconstructors) for
  414.  * various reasons (without violating e2e semantics).
  415.  */
  416. hdr_flags *fh = hdr_flags::access(pkt);
  417. if (!fh->no_ts_) {
  418. if (ts_option_)
  419. rtt_update(now - tcph->ts_echo());
  420. if (rtt_active_ && tcph->seqno() >= rtt_seq_) {
  421. if (!ect_ || !ecn_backoff_ || 
  422. !hdr_flags::access(pkt)->ecnecho()) {
  423. /* 
  424.  * Don't end backoff if still in ECN-Echo with
  425.    * a congestion window of 1 packet. 
  426.  */
  427. t_backoff_ = 1;
  428. ecn_backoff_ = 0;
  429. }
  430. rtt_active_ = 0;
  431. if (!ts_option_)
  432. rtt_update(now - rtt_ts_);
  433. }
  434. }
  435. /* update average window */
  436. awnd_ *= 1.0 - wnd_th_;
  437. awnd_ += wnd_th_ * cwnd_;
  438. }