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

通讯编程

开发平台:

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 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.  * Contributed by the Daedalus Research Group, U.C.Berkeley
  35.  * http://daedalus.cs.berkeley.edu
  36.  *
  37.  * @(#) $Header: 
  38.  */
  39. /*
  40.  * tcp-asym includes modifications to several flavors of TCP to enhance
  41.  * performance over asymmetric networks, where the ack channel is
  42.  * constrained.  Types of asymmetry we have studied and used these mods
  43.  * include bandwidth asymmetry and latency asymmetry (where  variable 
  44.  * latencies cause problems to TCP, e.g., in packet radio networks.
  45.  * The receiver-side code in this file is derived from the regular
  46.  * TCP sink code. The main additional functionality is that the sink responds
  47.  * to ECN by performing ack congestion control, i.e. it multiplicatively backs
  48.  * off the frequency with which it sends acks (up to a limit). For each 
  49.  * subsequent round-trip period during which it does not receive an ECN, 
  50.  * it gradually increases the frequency of acks (up to a maximum of 1 
  51.  * per data packet).
  52.  *
  53.  * For questions/comments, please contact:
  54.  *   Venkata N. Padmanabhan (padmanab@cs.berkeley.edu)
  55.  *   http://www.cs.berkeley.edu/~padmanab
  56.  */
  57. #ifndef lint
  58. static const char rcsid[] =
  59.     "@(#) $Header: /cvsroot/nsnam/ns-2/tcp/tcp-asym-sink.cc,v 1.17 2003/08/14 04:26:42 sfloyd Exp $ (UCB)";
  60. #endif
  61. #include "template.h"
  62. #include "flags.h"
  63. #include "tcp-sink.h"
  64. #include "tcp-asym.h"
  65. class TcpAsymSink : public DelAckSink {
  66. public:
  67. TcpAsymSink(Acker*);
  68. virtual void recv(Packet* pkt, Handler* h);
  69. virtual void timeout(int tno);
  70. protected:
  71. virtual void add_to_ack(Packet* pkt);
  72. int delackcount_; /* the number of consecutive packets that have
  73.    not been acked yet */
  74. int maxdelack_; /* the maximum extent to which acks can be
  75.    delayed */
  76. int delackfactor_; /* the dynamically varying limit on the extent
  77.    to which acks can be delayed */
  78. int delacklim_; /* limit on the extent of del ack based on the
  79.    sender's window */
  80. double ts_ecn_; /* the time when an ECN was received last */
  81. double ts_decrease_;    /* the time when delackfactor_ was decreased last */
  82. double highest_ts_echo_;/* the highest timestamp echoed by the peer */
  83. };
  84. static class TcpAsymSinkClass : public TclClass {
  85. public:
  86. TcpAsymSinkClass() : TclClass("Agent/TCPSink/Asym") {}
  87. TclObject* create(int, const char*const*) {
  88. return (new TcpAsymSink(new Acker));
  89. }
  90. } class_tcpasymsink;
  91. TcpAsymSink::TcpAsymSink(Acker* acker) : DelAckSink(acker), delackcount_(0), 
  92.     delackfactor_(1), delacklim_(0), ts_ecn_(0), ts_decrease_(0)
  93. {
  94. bind("maxdelack_", &maxdelack_);
  95. }
  96. /* Add fields to the ack. Not needed? */
  97. void TcpAsymSink::add_to_ack(Packet* pkt) 
  98. {
  99. hdr_tcpasym *tha = hdr_tcpasym::access(pkt);
  100. tha->ackcount() = delackcount_;
  101. }
  102. void TcpAsymSink::recv(Packet* pkt, Handler*) 
  103. {
  104. int olddelackfactor = delackfactor_;
  105. int olddelacklim = delacklim_; 
  106. int max_sender_can_send = 0;
  107. hdr_flags *fh = hdr_flags::access(pkt);
  108. hdr_tcp *th = hdr_tcp::access(pkt);
  109. hdr_tcpasym *tha = hdr_tcpasym::access(pkt);
  110. double now = Scheduler::instance().clock();
  111. int numBytes = hdr_cmn::access(pkt)->size();
  112. acker_->update_ts(th->seqno(),th->ts(),ts_echo_rfc1323_);
  113. acker_->update(th->seqno(), numBytes);
  114. #if 0  // johnh
  115. int numToDeliver;
  116. /* XXX if the #if 0 is removed, delete the call to acker_->update() above */
  117. numToDeliver = acker_->update(th->seqno(), numBytes);
  118. if (numToDeliver)
  119. recvBytes(numToDeliver);
  120. #endif /* 0 */
  121. /* determine the highest timestamp the sender has echoed */
  122. highest_ts_echo_ = max(highest_ts_echo_, th->ts_echo());
  123. /* 
  124.  * if we receive an ECN and haven't received one in the past
  125.  * round-trip, double delackfactor_ (and consequently halve
  126.  * the frequency of acks) subject to a maximum
  127.  */
  128. if (fh->ecnecho() && highest_ts_echo_ >= ts_ecn_) {
  129. delackfactor_ = min(2*delackfactor_, maxdelack_);
  130. ts_ecn_ = now;
  131. }
  132. /*
  133.  * else if we haven't received an ECN in the past round trip and
  134.  * haven't (linearly) decreased delackfactor_ in the past round
  135.  * trip, we decrease delackfactor_ by 1 (and consequently increase
  136.  * the frequency of acks) subject to a minimum
  137.  */
  138. else if (highest_ts_echo_ >= ts_ecn_ && highest_ts_echo_ >= ts_decrease_) {
  139. delackfactor_ = max(delackfactor_ - 1, 1);
  140. ts_decrease_ = now;
  141. }
  142. /*
  143.          * if this is the next packet in sequence, we can consider delaying the ack. 
  144.  * Set delacklim_ based on how much data the sender can send if we don't
  145.  * send back any more acks. The idea is to avoid stalling the sender because
  146.  * of a lack of acks.
  147.          */
  148.         if (th->seqno() == acker_->Seqno()) {
  149. max_sender_can_send = (int) min(tha->win()+acker_->Seqno()-tha->highest_ack(), tha->max_left_to_send());
  150. /* XXXX we use a safety factor 2 */
  151. delacklim_ = min(maxdelack_, max_sender_can_send/2); 
  152. }
  153. else
  154. delacklim_ = 0;
  155. if (delackfactor_ < delacklim_) 
  156. delacklim_ = delackfactor_;
  157. /* 
  158.  * Log values of variables of interest. Since this is the only place
  159.  * where this is done, we decided against using a more general method
  160.  * as used for logging TCP sender state variables.
  161.  */
  162. if (channel_ && (olddelackfactor != delackfactor_ || olddelacklim != delacklim_)) {
  163. char wrk[500];
  164. int n;
  165. /* we print src and dst in reverse order to conform to sender side */
  166. sprintf(wrk, "time: %-6.3f saddr: %-2d sport: %-2d daddr:"
  167. " %-2d dport: %-2d dafactor: %2d dalim: %2d max_scs:"
  168. " %4d win: %4dn", now, addr(), port(),
  169. daddr(), dport(), delackfactor_,
  170. delacklim_,max_sender_can_send, tha->win());  
  171. n = strlen(wrk);
  172. wrk[n] = 'n';
  173. wrk[n+1] = 0;
  174. (void)Tcl_Write(channel_, wrk, n+1);
  175. wrk[n] = 0;
  176. }
  177. delackcount_++;
  178. /* check if we have waited long enough that we should send an ack */
  179. if (delackcount_ < delacklim_) { /* it is not yet time to send an ack */
  180. /* if the delayed ack timer is not set, set it now */
  181. if (!(delay_timer_.status() == TIMER_PENDING)) {
  182. save_ = pkt;
  183. delay_timer_.resched(interval_);
  184. }
  185. else {
  186. hdr_tcp *sth = hdr_tcp::access(save_);
  187. /* save the pkt with the more recent timestamp */
  188. if (th->ts() > sth->ts()) {
  189. Packet::free(save_);
  190. save_ = pkt;
  191. }
  192. }
  193. return;
  194. }
  195. else { /* send back an ack now */
  196. if (delay_timer_.status() == TIMER_PENDING) {
  197. delay_timer_.cancel();
  198. Packet::free(save_);
  199. save_ = 0;
  200. }
  201. hdr_flags* hf = hdr_flags::access(pkt);
  202. hf->ect() = 1;
  203. ack(pkt);
  204. delackcount_ = 0;
  205. Packet::free(pkt);
  206. }
  207. }
  208. void TcpAsymSink::timeout(int /*tno*/)
  209. {
  210. /*
  211.  * The timer expired so we ACK the last packet seen.
  212.  */
  213. Packet* pkt = save_;
  214. delackcount_ = 0;
  215. ack(pkt);
  216. save_ = 0;
  217. Packet::free(pkt);
  218. }