• tcp.cc


    ns2-tcp-tcp.cc

       1 /* -*-    Mode:C++; c-basic-offset:8; tab-8; indent-tabs-mode:t -*- */
       2 /*
       3  * Copyright (c) 1991-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 Computer Systems
      17  *    Engineering Group at Lawrence Berkeley Laboratory.
      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 
      35 #ifndef lint
      36 static const char rcsid[] =
      37     "@(#) $Header: /cvsroot/nsnam/ns-2/tcp/tcp.cc,v 1.182 2011/06/20 04:51:46 tom_henderson Exp $ (LBL)";
      38 #endif
      39 
      40 #include <stdlib.h>
      41 #include <math.h>
      42 #include <sys/types.h>
      43 #include <iostream>
      44 #include "ip.h"
      45 #include "tcp.h"
      46 #include "flags.h"
      47 #include "random.h"
      48 #include "basetrace.h"
      49 #include "hdr_qs.h"
      50 
      51 int hdr_tcp::offset_;
      52 
      53 static class TCPHeaderClass : public PacketHeaderClass {
      54 public:
      55         TCPHeaderClass() : PacketHeaderClass("PacketHeader/TCP",
      56                          sizeof(hdr_tcp)) {
      57         bind_offset(&hdr_tcp::offset_);
      58     }
      59 } class_tcphdr;
      60 
      61 static class TcpClass : public TclClass {
      62 public:
      63     TcpClass() : TclClass("Agent/TCP") {}
      64     TclObject* create(int , const char*const*) {
      65         return (new TcpAgent());
      66     }
      67 } class_tcp;
      68 
      69 TcpAgent::TcpAgent() 
      70     : Agent(PT_TCP), 
      71       t_seqno_(0), dupacks_(0), curseq_(0), highest_ack_(0), 
      72           cwnd_(0), ssthresh_(0), maxseq_(0), count_(0), 
      73           rtt_active_(0), rtt_seq_(-1), rtt_ts_(0.0), 
      74           lastreset_(0.0), closed_(0), t_rtt_(0), t_srtt_(0), t_rttvar_(0), 
      75       t_backoff_(0), ts_peer_(0), ts_echo_(0), tss(NULL), tss_size_(100), 
      76       rtx_timer_(this), delsnd_timer_(this), burstsnd_timer_(this), 
      77       first_decrease_(1), fcnt_(0), nrexmit_(0), restart_bugfix_(1), 
      78           cong_action_(0), ecn_burst_(0), ecn_backoff_(0), ect_(0), 
      79           use_rtt_(0), qs_requested_(0), qs_approved_(0),
      80       qs_window_(0), qs_cwnd_(0), frto_(0)
      81 {
      82 #ifdef TCP_DELAY_BIND_ALL
      83         // defined since Dec 1999.
      84 #else /* ! TCP_DELAY_BIND_ALL */
      85     bind("t_seqno_", &t_seqno_);
      86     bind("rtt_", &t_rtt_);
      87     bind("srtt_", &t_srtt_);
      88     bind("rttvar_", &t_rttvar_);
      89     bind("backoff_", &t_backoff_);
      90     bind("dupacks_", &dupacks_);
      91     bind("seqno_", &curseq_);
      92     bind("ack_", &highest_ack_);
      93     bind("cwnd_", &cwnd_);
      94     bind("ssthresh_", &ssthresh_);
      95     bind("maxseq_", &maxseq_);
      96         bind("ndatapack_", &ndatapack_);
      97         bind("ndatabytes_", &ndatabytes_);
      98         bind("nackpack_", &nackpack_);
      99         bind("nrexmit_", &nrexmit_);
     100         bind("nrexmitpack_", &nrexmitpack_);
     101         bind("nrexmitbytes_", &nrexmitbytes_);
     102         bind("necnresponses_", &necnresponses_);
     103         bind("ncwndcuts_", &ncwndcuts_);
     104     bind("ncwndcuts1_", &ncwndcuts1_);
     105 #endif /* TCP_DELAY_BIND_ALL */
     106 
     107 }
     108 
     109 void
     110 TcpAgent::delay_bind_init_all()
     111 {
     112 
     113         // Defaults for bound variables should be set in ns-default.tcl.
     114         delay_bind_init_one("window_");
     115         delay_bind_init_one("windowInit_");
     116         delay_bind_init_one("windowInitOption_");
     117 
     118         delay_bind_init_one("syn_");
     119         delay_bind_init_one("max_connects_");
     120         delay_bind_init_one("windowOption_");
     121         delay_bind_init_one("windowConstant_");
     122         delay_bind_init_one("windowThresh_");
     123         delay_bind_init_one("delay_growth_");
     124         delay_bind_init_one("overhead_");
     125         delay_bind_init_one("tcpTick_");
     126         delay_bind_init_one("ecn_");
     127         delay_bind_init_one("SetCWRonRetransmit_");
     128         delay_bind_init_one("old_ecn_");
     129         delay_bind_init_one("bugfix_ss_");
     130         delay_bind_init_one("eln_");
     131         delay_bind_init_one("eln_rxmit_thresh_");
     132         delay_bind_init_one("packetSize_");
     133         delay_bind_init_one("tcpip_base_hdr_size_");
     134     delay_bind_init_one("ts_option_size_");
     135         delay_bind_init_one("bugFix_");
     136     delay_bind_init_one("bugFix_ack_");
     137     delay_bind_init_one("bugFix_ts_");
     138     delay_bind_init_one("lessCareful_");
     139         delay_bind_init_one("slow_start_restart_");
     140         delay_bind_init_one("restart_bugfix_");
     141         delay_bind_init_one("timestamps_");
     142     delay_bind_init_one("ts_resetRTO_");
     143         delay_bind_init_one("maxburst_");
     144     delay_bind_init_one("aggressive_maxburst_");
     145         delay_bind_init_one("maxcwnd_");
     146     delay_bind_init_one("numdupacks_");
     147     delay_bind_init_one("numdupacksFrac_");
     148     delay_bind_init_one("exitFastRetrans_");
     149         delay_bind_init_one("maxrto_");
     150     delay_bind_init_one("minrto_");
     151         delay_bind_init_one("srtt_init_");
     152         delay_bind_init_one("rttvar_init_");
     153         delay_bind_init_one("rtxcur_init_");
     154         delay_bind_init_one("T_SRTT_BITS");
     155         delay_bind_init_one("T_RTTVAR_BITS");
     156         delay_bind_init_one("rttvar_exp_");
     157         delay_bind_init_one("awnd_");
     158         delay_bind_init_one("decrease_num_");
     159         delay_bind_init_one("increase_num_");
     160     delay_bind_init_one("k_parameter_");
     161     delay_bind_init_one("l_parameter_");
     162         delay_bind_init_one("trace_all_oneline_");
     163         delay_bind_init_one("nam_tracevar_");
     164 
     165         delay_bind_init_one("QOption_");
     166         delay_bind_init_one("EnblRTTCtr_");
     167         delay_bind_init_one("control_increase_");
     168     delay_bind_init_one("noFastRetrans_");
     169     delay_bind_init_one("precisionReduce_");
     170     delay_bind_init_one("oldCode_");
     171     delay_bind_init_one("useHeaders_");
     172     delay_bind_init_one("low_window_");
     173     delay_bind_init_one("high_window_");
     174     delay_bind_init_one("high_p_");
     175     delay_bind_init_one("high_decrease_");
     176     delay_bind_init_one("max_ssthresh_");
     177     delay_bind_init_one("cwnd_range_");
     178     delay_bind_init_one("timerfix_");
     179     delay_bind_init_one("rfc2988_");
     180     delay_bind_init_one("singledup_");
     181     delay_bind_init_one("LimTransmitFix_");
     182     delay_bind_init_one("rate_request_");
     183     delay_bind_init_one("qs_enabled_");
     184     delay_bind_init_one("tcp_qs_recovery_");
     185     delay_bind_init_one("qs_request_mode_");
     186     delay_bind_init_one("qs_thresh_");
     187     delay_bind_init_one("qs_rtt_");
     188     delay_bind_init_one("print_request_");
     189 
     190     delay_bind_init_one("frto_enabled_");
     191     delay_bind_init_one("sfrto_enabled_");
     192     delay_bind_init_one("spurious_response_");
     193 
     194 #ifdef TCP_DELAY_BIND_ALL
     195     // out because delay-bound tracevars aren't yet supported
     196         delay_bind_init_one("t_seqno_");
     197         delay_bind_init_one("rtt_");
     198         delay_bind_init_one("srtt_");
     199         delay_bind_init_one("rttvar_");
     200         delay_bind_init_one("backoff_");
     201         delay_bind_init_one("dupacks_");
     202         delay_bind_init_one("seqno_");
     203         delay_bind_init_one("ack_");
     204         delay_bind_init_one("cwnd_");
     205         delay_bind_init_one("ssthresh_");
     206         delay_bind_init_one("maxseq_");
     207         delay_bind_init_one("ndatapack_");
     208         delay_bind_init_one("ndatabytes_");
     209         delay_bind_init_one("nackpack_");
     210         delay_bind_init_one("nrexmit_");
     211         delay_bind_init_one("nrexmitpack_");
     212         delay_bind_init_one("nrexmitbytes_");
     213         delay_bind_init_one("necnresponses_");
     214         delay_bind_init_one("ncwndcuts_");
     215     delay_bind_init_one("ncwndcuts1_");
     216 #endif /* TCP_DELAY_BIND_ALL */
     217 
     218     Agent::delay_bind_init_all();
     219 
     220         reset();
     221 }
     222 
     223 int
     224 TcpAgent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer)
     225 {
     226         if (delay_bind(varName, localName, "window_", &wnd_, tracer)) return TCL_OK;
     227         if (delay_bind(varName, localName, "windowInit_", &wnd_init_, tracer)) return TCL_OK;
     228         if (delay_bind(varName, localName, "windowInitOption_", &wnd_init_option_, tracer)) return TCL_OK;
     229         if (delay_bind_bool(varName, localName, "syn_", &syn_, tracer)) return TCL_OK;
     230         if (delay_bind(varName, localName, "max_connects_", &max_connects_, tracer)) return TCL_OK;
     231         if (delay_bind(varName, localName, "windowOption_", &wnd_option_ , tracer)) return TCL_OK;
     232         if (delay_bind(varName, localName, "windowConstant_",  &wnd_const_, tracer)) return TCL_OK;
     233         if (delay_bind(varName, localName, "windowThresh_", &wnd_th_ , tracer)) return TCL_OK;
     234         if (delay_bind_bool(varName, localName, "delay_growth_", &delay_growth_ , tracer)) return TCL_OK;
     235         if (delay_bind(varName, localName, "overhead_", &overhead_, tracer)) return TCL_OK;
     236         if (delay_bind(varName, localName, "tcpTick_", &tcp_tick_, tracer)) return TCL_OK;
     237         if (delay_bind_bool(varName, localName, "ecn_", &ecn_, tracer)) return TCL_OK;
     238         if (delay_bind_bool(varName, localName, "SetCWRonRetransmit_", &SetCWRonRetransmit_, tracer)) return TCL_OK;
     239         if (delay_bind_bool(varName, localName, "old_ecn_", &old_ecn_ , tracer)) return TCL_OK;
     240         if (delay_bind_bool(varName, localName, "bugfix_ss_", &bugfix_ss_ , tracer)) return TCL_OK;
     241         if (delay_bind(varName, localName, "eln_", &eln_ , tracer)) return TCL_OK;
     242         if (delay_bind(varName, localName, "eln_rxmit_thresh_", &eln_rxmit_thresh_ , tracer)) return TCL_OK;
     243         if (delay_bind(varName, localName, "packetSize_", &size_ , tracer)) return TCL_OK;
     244         if (delay_bind(varName, localName, "tcpip_base_hdr_size_", &tcpip_base_hdr_size_, tracer)) return TCL_OK;
     245     if (delay_bind(varName, localName, "ts_option_size_", &ts_option_size_, tracer)) return TCL_OK;
     246         if (delay_bind_bool(varName, localName, "bugFix_", &bug_fix_ , tracer)) return TCL_OK;
     247     if (delay_bind_bool(varName, localName, "bugFix_ack_", &bugfix_ack_, tracer)) return TCL_OK;
     248     if (delay_bind_bool(varName, localName, "bugFix_ts_", &bugfix_ts_ , tracer)) return TCL_OK;
     249         if (delay_bind_bool(varName, localName, "lessCareful_", &less_careful_ , tracer)) return TCL_OK;
     250         if (delay_bind_bool(varName, localName, "timestamps_", &ts_option_ , tracer)) return TCL_OK;
     251         if (delay_bind_bool(varName, localName, "ts_resetRTO_", &ts_resetRTO_, tracer)) return TCL_OK;
     252         if (delay_bind_bool(varName, localName, "slow_start_restart_", &slow_start_restart_ , tracer)) return TCL_OK;
     253         if (delay_bind_bool(varName, localName, "restart_bugfix_", &restart_bugfix_ , tracer)) return TCL_OK;
     254         if (delay_bind(varName, localName, "maxburst_", &maxburst_ , tracer)) return TCL_OK;
     255         if (delay_bind_bool(varName, localName, "aggressive_maxburst_", &aggressive_maxburst_ , tracer)) return TCL_OK;
     256         if (delay_bind(varName, localName, "maxcwnd_", &maxcwnd_ , tracer)) return TCL_OK;
     257     if (delay_bind(varName, localName, "numdupacks_", &numdupacks_, tracer)) return TCL_OK;
     258     if (delay_bind(varName, localName, "numdupacksFrac_", &numdupacksFrac_, tracer)) return TCL_OK;
     259     if (delay_bind_bool(varName, localName, "exitFastRetrans_", &exitFastRetrans_, tracer)) return TCL_OK;
     260         if (delay_bind(varName, localName, "maxrto_", &maxrto_ , tracer)) return TCL_OK;
     261     if (delay_bind(varName, localName, "minrto_", &minrto_ , tracer)) return TCL_OK;
     262         if (delay_bind(varName, localName, "srtt_init_", &srtt_init_ , tracer)) return TCL_OK;
     263         if (delay_bind(varName, localName, "rttvar_init_", &rttvar_init_ , tracer)) return TCL_OK;
     264         if (delay_bind(varName, localName, "rtxcur_init_", &rtxcur_init_ , tracer)) return TCL_OK;
     265         if (delay_bind(varName, localName, "T_SRTT_BITS", &T_SRTT_BITS , tracer)) return TCL_OK;
     266         if (delay_bind(varName, localName, "T_RTTVAR_BITS", &T_RTTVAR_BITS , tracer)) return TCL_OK;
     267         if (delay_bind(varName, localName, "rttvar_exp_", &rttvar_exp_ , tracer)) return TCL_OK;
     268         if (delay_bind(varName, localName, "awnd_", &awnd_ , tracer)) return TCL_OK;
     269         if (delay_bind(varName, localName, "decrease_num_", &decrease_num_, tracer)) return TCL_OK;
     270         if (delay_bind(varName, localName, "increase_num_", &increase_num_, tracer)) return TCL_OK;
     271     if (delay_bind(varName, localName, "k_parameter_", &k_parameter_, tracer)) return TCL_OK;
     272         if (delay_bind(varName, localName, "l_parameter_", &l_parameter_, tracer)) return TCL_OK;
     273 
     274 
     275         if (delay_bind_bool(varName, localName, "trace_all_oneline_", &trace_all_oneline_ , tracer)) return TCL_OK;
     276         if (delay_bind_bool(varName, localName, "nam_tracevar_", &nam_tracevar_ , tracer)) return TCL_OK;
     277         if (delay_bind(varName, localName, "QOption_", &QOption_ , tracer)) return TCL_OK;
     278         if (delay_bind(varName, localName, "EnblRTTCtr_", &EnblRTTCtr_ , tracer)) return TCL_OK;
     279         if (delay_bind(varName, localName, "control_increase_", &control_increase_ , tracer)) return TCL_OK;
     280         if (delay_bind_bool(varName, localName, "noFastRetrans_", &noFastRetrans_, tracer)) return TCL_OK;
     281         if (delay_bind_bool(varName, localName, "precisionReduce_", &precision_reduce_, tracer)) return TCL_OK;
     282     if (delay_bind_bool(varName, localName, "oldCode_", &oldCode_, tracer)) return TCL_OK;
     283     if (delay_bind_bool(varName, localName, "useHeaders_", &useHeaders_, tracer)) return TCL_OK;
     284     if (delay_bind(varName, localName, "low_window_", &low_window_, tracer)) return TCL_OK;
     285     if (delay_bind(varName, localName, "high_window_", &high_window_, tracer)) return TCL_OK;
     286     if (delay_bind(varName, localName, "high_p_", &high_p_, tracer)) return TCL_OK;
     287     if (delay_bind(varName, localName, "high_decrease_", &high_decrease_, tracer)) return TCL_OK;
     288     if (delay_bind(varName, localName, "max_ssthresh_", &max_ssthresh_, tracer)) return TCL_OK;
     289     if (delay_bind(varName, localName, "cwnd_range_", &cwnd_range_, tracer)) return TCL_OK;
     290     if (delay_bind_bool(varName, localName, "timerfix_", &timerfix_, tracer)) return TCL_OK;
     291     if (delay_bind_bool(varName, localName, "rfc2988_", &rfc2988_, tracer)) return TCL_OK;
     292         if (delay_bind(varName, localName, "singledup_", &singledup_ , tracer)) return TCL_OK;
     293         if (delay_bind_bool(varName, localName, "LimTransmitFix_", &LimTransmitFix_ , tracer)) return TCL_OK;
     294         if (delay_bind(varName, localName, "rate_request_", &rate_request_ , tracer)) return TCL_OK;
     295         if (delay_bind_bool(varName, localName, "qs_enabled_", &qs_enabled_ , tracer)) return TCL_OK;
     296     if (delay_bind_bool(varName, localName, "tcp_qs_recovery_", &tcp_qs_recovery_, tracer)) return TCL_OK;
     297     if (delay_bind(varName, localName, "qs_request_mode_", &qs_request_mode_, tracer)) return TCL_OK;
     298     if (delay_bind(varName, localName, "qs_thresh_", &qs_thresh_, tracer)) return TCL_OK;
     299     if (delay_bind(varName, localName, "qs_rtt_", &qs_rtt_, tracer)) return TCL_OK;
     300     if (delay_bind_bool(varName, localName, "print_request_", &print_request_, tracer)) return TCL_OK;
     301     if (delay_bind_bool(varName, localName, "frto_enabled_", &frto_enabled_, tracer)) return TCL_OK;
     302     if (delay_bind_bool(varName, localName, "sfrto_enabled_", &sfrto_enabled_, tracer)) return TCL_OK;
     303     if (delay_bind_bool(varName, localName, "spurious_response_", &spurious_response_, tracer)) return TCL_OK;
     304 
     305 #ifdef TCP_DELAY_BIND_ALL
     306     // not if (delay-bound delay-bound tracevars aren't yet supported
     307         if (delay_bind(varName, localName, "t_seqno_", &t_seqno_ , tracer)) return TCL_OK;
     308         if (delay_bind(varName, localName, "rtt_", &t_rtt_ , tracer)) return TCL_OK;
     309         if (delay_bind(varName, localName, "srtt_", &t_srtt_ , tracer)) return TCL_OK;
     310         if (delay_bind(varName, localName, "rttvar_", &t_rttvar_ , tracer)) return TCL_OK;
     311         if (delay_bind(varName, localName, "backoff_", &t_backoff_ , tracer)) return TCL_OK;
     312 
     313         if (delay_bind(varName, localName, "dupacks_", &dupacks_ , tracer)) return TCL_OK;
     314         if (delay_bind(varName, localName, "seqno_", &curseq_ , tracer)) return TCL_OK;
     315         if (delay_bind(varName, localName, "ack_", &highest_ack_ , tracer)) return TCL_OK;
     316         if (delay_bind(varName, localName, "cwnd_", &cwnd_ , tracer)) return TCL_OK;
     317         if (delay_bind(varName, localName, "ssthresh_", &ssthresh_ , tracer)) return TCL_OK;
     318         if (delay_bind(varName, localName, "maxseq_", &maxseq_ , tracer)) return TCL_OK;
     319         if (delay_bind(varName, localName, "ndatapack_", &ndatapack_ , tracer)) return TCL_OK;
     320         if (delay_bind(varName, localName, "ndatabytes_", &ndatabytes_ , tracer)) return TCL_OK;
     321         if (delay_bind(varName, localName, "nackpack_", &nackpack_ , tracer)) return TCL_OK;
     322         if (delay_bind(varName, localName, "nrexmit_", &nrexmit_ , tracer)) return TCL_OK;
     323         if (delay_bind(varName, localName, "nrexmitpack_", &nrexmitpack_ , tracer)) return TCL_OK;
     324         if (delay_bind(varName, localName, "nrexmitbytes_", &nrexmitbytes_ , tracer)) return TCL_OK;
     325         if (delay_bind(varName, localName, "necnresponses_", &necnresponses_ , tracer)) return TCL_OK;
     326         if (delay_bind(varName, localName, "ncwndcuts_", &ncwndcuts_ , tracer)) return TCL_OK;
     327      if (delay_bind(varName, localName, "ncwndcuts1_", &ncwndcuts1_ , tracer)) return TCL_OK;
     328 
     329 #endif
     330 
     331         return Agent::delay_bind_dispatch(varName, localName, tracer);
     332 }
     333 
     334 #define TCP_WRK_SIZE        512
     335 /* Print out all the traced variables whenever any one is changed */
     336 void
     337 TcpAgent::traceAll() {
     338     if (!channel_)
     339         return;
     340 
     341     double curtime;
     342     Scheduler& s = Scheduler::instance();
     343     char wrk[TCP_WRK_SIZE];
     344 
     345     curtime = &s ? s.clock() : 0;
     346     snprintf(wrk, TCP_WRK_SIZE,
     347          "time: %-12.9f saddr: %-2d sport: %-2d daddr: %-2d dport:"
     348          " %-2d maxseq: %-4d hiack: %-4d seqno: %-4d cwnd: %-6.3f"
     349          " ssthresh: %-3d dupacks: %-2d rtt: %-10.9f srtt: %-10.9f"
     350          " rttvar: %-10.9f bkoff: %-d fid: %-2d wnd: %-6.3f
    ",
     351          curtime, addr(), port(),
     352          daddr(), dport(), int(maxseq_), int(highest_ack_),
     353          int(t_seqno_), double(cwnd_), int(ssthresh_),
     354          int(dupacks_), int(t_rtt_)*tcp_tick_, 
     355          (int(t_srtt_) >> T_SRTT_BITS)*tcp_tick_, 
     356          int(t_rttvar_)*tcp_tick_/4.0, int(t_backoff_),
     357          int(fid_), double(wnd_)); 
     358     (void)Tcl_Write(channel_, wrk, -1);
     359 }
     360 
     361 /* Print out just the variable that is modified */
     362 void
     363 TcpAgent::traceVar(TracedVar* v) 
     364 {
     365     if (!channel_)
     366         return;
     367 
     368     double curtime;
     369     Scheduler& s = Scheduler::instance();
     370     char wrk[TCP_WRK_SIZE];
     371 
     372     curtime = &s ? s.clock() : 0;
     373 
     374     // XXX comparing addresses is faster than comparing names
     375     if (v == &cwnd_)
     376         snprintf(wrk, TCP_WRK_SIZE,
     377              "%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f
    ",
     378              curtime, addr(), port(), daddr(), dport(),
     379              v->name(), double(*((TracedDouble*) v))); 
     380      else if (v == &t_rtt_)
     381         snprintf(wrk, TCP_WRK_SIZE,
     382              "%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f
    ",
     383              curtime, addr(), port(), daddr(), dport(),
     384              v->name(), int(*((TracedInt*) v))*tcp_tick_); 
     385     else if (v == &t_srtt_)
     386         snprintf(wrk, TCP_WRK_SIZE,
     387              "%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f
    ",
     388              curtime, addr(), port(), daddr(), dport(),
     389              v->name(), 
     390              (int(*((TracedInt*) v)) >> T_SRTT_BITS)*tcp_tick_); 
     391     else if (v == &t_rttvar_)
     392         snprintf(wrk, TCP_WRK_SIZE,
     393              "%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f
    ",
     394              curtime, addr(), port(), daddr(), dport(),
     395              v->name(), 
     396              int(*((TracedInt*) v))*tcp_tick_/4.0); 
     397     else
     398         snprintf(wrk, TCP_WRK_SIZE,
     399              "%-8.5f %-2d %-2d %-2d %-2d %s %d
    ",
     400              curtime, addr(), port(), daddr(), dport(),
     401              v->name(), int(*((TracedInt*) v))); 
     402 
     403     (void)Tcl_Write(channel_, wrk, -1);
     404 }
     405 
     406 void
     407 TcpAgent::trace(TracedVar* v) 
     408 {
     409     if (nam_tracevar_) {
     410         Agent::trace(v);
     411     } else if (trace_all_oneline_)
     412         traceAll();
     413     else 
     414         traceVar(v);
     415 }
     416 
     417 //
     418 // in 1-way TCP, syn_ indicates we are modeling
     419 // a SYN exchange at the beginning.  If this is true
     420 // and we are delaying growth, then use an initial
     421 // window of one.  If not, we do whatever initial_window()
     422 // says to do.
     423 //
     424 
     425 void
     426 TcpAgent::set_initial_window()
     427 {
     428     if (syn_ && delay_growth_) {
     429         cwnd_ = 1.0; 
     430         syn_connects_ = 0;
     431     } else
     432         cwnd_ = initial_window();
     433 }
     434 
     435 void
     436 TcpAgent::reset_qoption()
     437 {
     438     int now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5);
     439 
     440     T_start = now ; 
     441     RTT_count = 0 ; 
     442     RTT_prev = 0 ; 
     443     RTT_goodcount = 1 ; 
     444     F_counting = 0 ; 
     445     W_timed = -1 ; 
     446     F_full = 0 ;
     447     Backoffs = 0 ; 
     448 }
     449 
     450 void
     451 TcpAgent::reset()
     452 {
     453     rtt_init();
     454     rtt_seq_ = -1;
     455     /*XXX lookup variables */
     456     dupacks_ = 0;
     457     curseq_ = 0;
     458     set_initial_window();
     459 
     460     t_seqno_ = 0;
     461     maxseq_ = -1;
     462     last_ack_ = -1;
     463     highest_ack_ = -1;
     464     //highest_ack_ = 1;
     465     ssthresh_ = int(wnd_);
     466     if (max_ssthresh_ > 0 && max_ssthresh_ < ssthresh_) 
     467         ssthresh_ = max_ssthresh_;
     468     wnd_restart_ = 1.;
     469     awnd_ = wnd_init_ / 2.0;
     470     recover_ = 0;
     471     closed_ = 0;
     472     last_cwnd_action_ = 0;
     473     boot_time_ = Random::uniform(tcp_tick_);
     474     first_decrease_ = 1;
     475     /* W.N.: for removing packets from previous incarnations */
     476     lastreset_ = Scheduler::instance().clock();
     477 
     478     /* Now these variables will be reset 
     479        - Debojyoti Dutta 12th Oct'2000 */
     480  
     481     ndatapack_ = 0;
     482     ndatabytes_ = 0;
     483     nackpack_ = 0;
     484     nrexmitbytes_ = 0;
     485     nrexmit_ = 0;
     486     nrexmitpack_ = 0;
     487     necnresponses_ = 0;
     488     ncwndcuts_ = 0;
     489     ncwndcuts1_ = 0;
     490         cancel_timers();      // suggested by P. Anelli.
     491 
     492     if (control_increase_) {
     493         prev_highest_ack_ = highest_ack_ ; 
     494     }
     495 
     496     if (wnd_option_ == 8) {
     497         // HighSpeed TCP
     498         hstcp_.low_p = 1.5/(low_window_*low_window_);
     499         double highLowWin = log(high_window_)-log(low_window_);
     500         double highLowP = log(high_p_) - log(hstcp_.low_p);
     501         hstcp_.dec1 = 
     502            0.5 - log(low_window_) * (high_decrease_ - 0.5)/highLowWin;
     503         hstcp_.dec2 = (high_decrease_ - 0.5)/highLowWin;
     504             hstcp_.p1 = 
     505           log(hstcp_.low_p) - log(low_window_) * highLowP/highLowWin;
     506         hstcp_.p2 = highLowP/highLowWin;
     507     }
     508 
     509     if (QOption_) {
     510         int now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5);
     511         T_last = now ; 
     512         T_prev = now ; 
     513         W_used = 0 ;
     514         if (EnblRTTCtr_) {
     515             reset_qoption();
     516         }
     517     }
     518 }
     519 
     520 /*
     521  * Initialize variables for the retransmit timer.
     522  */
     523 void TcpAgent::rtt_init()
     524 {
     525     t_rtt_ = 0;
     526     t_srtt_ = int(srtt_init_ / tcp_tick_) << T_SRTT_BITS;
     527     t_rttvar_ = int(rttvar_init_ / tcp_tick_) << T_RTTVAR_BITS;
     528     t_rtxcur_ = rtxcur_init_;
     529     t_backoff_ = 1;
     530 }
     531 
     532 double TcpAgent::rtt_timeout()
     533 {
     534     double timeout;
     535     if (rfc2988_) {
     536     // Correction from Tom Kelly to be RFC2988-compliant, by
     537     // clamping minrto_ before applying t_backoff_.
     538         if (t_rtxcur_ < minrto_ && !use_rtt_)
     539             timeout = minrto_ * t_backoff_;
     540         else
     541             timeout = t_rtxcur_ * t_backoff_;
     542     } else {
     543         // only of interest for backwards compatibility
     544         timeout = t_rtxcur_ * t_backoff_;
     545         if (timeout < minrto_)
     546             timeout = minrto_;
     547     }
     548 
     549     if (timeout > maxrto_)
     550         timeout = maxrto_;
     551 
     552         if (timeout < 2.0 * tcp_tick_) {
     553         if (timeout < 0) {
     554             fprintf(stderr, "TcpAgent: negative RTO!  (%f)
    ",
     555                 timeout);
     556             exit(1);
     557         } else if (use_rtt_ && timeout < tcp_tick_)
     558             timeout = tcp_tick_;
     559         else
     560             timeout = 2.0 * tcp_tick_;
     561     }
     562     use_rtt_ = 0;
     563     return (timeout);
     564 }
     565 
     566 
     567 /* This has been modified to use the tahoe code. */
     568 void TcpAgent::rtt_update(double tao)
     569 {
     570     double now = Scheduler::instance().clock();
     571     if (ts_option_)
     572         t_rtt_ = int(tao /tcp_tick_ + 0.5);
     573     else {
     574         double sendtime = now - tao;
     575         sendtime += boot_time_;
     576         double tickoff = fmod(sendtime, tcp_tick_);
     577         t_rtt_ = int((tao + tickoff) / tcp_tick_);
     578     }
     579     if (t_rtt_ < 1)
     580         t_rtt_ = 1;
     581     //
     582     // t_srtt_ has 3 bits to the right of the binary point
     583     // t_rttvar_ has 2
     584         // Thus "t_srtt_ >> T_SRTT_BITS" is the actual srtt, 
     585       //   and "t_srtt_" is 8*srtt.
     586     // Similarly, "t_rttvar_ >> T_RTTVAR_BITS" is the actual rttvar,
     587     //   and "t_rttvar_" is 4*rttvar.
     588     //
     589         if (t_srtt_ != 0) {
     590         register short delta;
     591         delta = t_rtt_ - (t_srtt_ >> T_SRTT_BITS);    // d = (m - a0)
     592         if ((t_srtt_ += delta) <= 0)    // a1 = 7/8 a0 + 1/8 m
     593             t_srtt_ = 1;
     594         if (delta < 0)
     595             delta = -delta;
     596         delta -= (t_rttvar_ >> T_RTTVAR_BITS);
     597         if ((t_rttvar_ += delta) <= 0)    // var1 = 3/4 var0 + 1/4 |d|
     598             t_rttvar_ = 1;
     599     } else {
     600         t_srtt_ = t_rtt_ << T_SRTT_BITS;        // srtt = rtt
     601         t_rttvar_ = t_rtt_ << (T_RTTVAR_BITS-1);    // rttvar = rtt / 2
     602     }
     603     //
     604     // Current retransmit value is 
     605     //    (unscaled) smoothed round trip estimate
     606     //    plus 2^rttvar_exp_ times (unscaled) rttvar. 
     607     //
     608     t_rtxcur_ = (((t_rttvar_ << (rttvar_exp_ + (T_SRTT_BITS - T_RTTVAR_BITS))) +
     609         t_srtt_)  >> T_SRTT_BITS ) * tcp_tick_;
     610 
     611     return;
     612 }
     613 
     614 void TcpAgent::rtt_backoff()
     615 {
     616     if (t_backoff_ < 64 || (rfc2988_ && rtt_timeout() < maxrto_))
     617             t_backoff_ <<= 1;
     618         // RFC2988 allows a maximum for the backed-off RTO of 60 seconds.
     619         // This is applied by maxrto_.
     620 
     621     if (t_backoff_ > 8) {
     622         /*
     623          * If backed off this far, clobber the srtt
     624          * value, storing it in the mean deviation
     625          * instead.
     626          */
     627         t_rttvar_ += (t_srtt_ >> T_SRTT_BITS);
     628         t_srtt_ = 0;
     629     }
     630 }
     631 
     632 /*
     633  * headersize:
     634  *      how big is an IP+TCP header in bytes; include options such as ts
     635  * this function should be virtual so others (e.g. SACK) can override
     636  */
     637 int TcpAgent::headersize()
     638 {
     639         int total = tcpip_base_hdr_size_;
     640     if (total < 1) {
     641         fprintf(stderr,
     642           "TcpAgent(%s): warning: tcpip hdr size is only %d bytes
    ",
     643           name(), tcpip_base_hdr_size_);
     644     }
     645     if (ts_option_)
     646         total += ts_option_size_;
     647         return (total);
     648 }
     649 
     650 void TcpAgent::output(int seqno, int reason)
     651 {
     652     int force_set_rtx_timer = 0;
     653     Packet* p = allocpkt();
     654     hdr_tcp *tcph = hdr_tcp::access(p);
     655     hdr_flags* hf = hdr_flags::access(p);
     656     hdr_ip *iph = hdr_ip::access(p);
     657     int databytes = hdr_cmn::access(p)->size();
     658     tcph->seqno() = seqno;
     659     tcph->ts() = Scheduler::instance().clock();
     660     int is_retransmit = (seqno < maxseq_);
     661  
     662     // Mark packet for diagnosis purposes if we are in Quick-Start Phase
     663     if (qs_approved_) {
     664         hf->qs() = 1;
     665     }
     666  
     667         // store timestamps, with bugfix_ts_.  From Andrei Gurtov. 
     668     // (A real TCP would use scoreboard for this.)
     669         if (bugfix_ts_ && tss==NULL) {
     670                 tss = (double*) calloc(tss_size_, sizeof(double));
     671                 if (tss==NULL) exit(1);
     672         }
     673         //dynamically grow the timestamp array if it's getting full
     674         if (bugfix_ts_ && ((seqno - highest_ack_) > tss_size_* 0.9)) {
     675                 double *ntss;
     676                 ntss = (double*) calloc(tss_size_*2, sizeof(double));
     677                 printf("%p resizing timestamp table
    ", this);
     678                 if (ntss == NULL) exit(1);
     679                 for (int i=0; i<tss_size_; i++)
     680                         ntss[(highest_ack_ + i) % (tss_size_ * 2)] =
     681                                 tss[(highest_ack_ + i) % tss_size_];
     682                 free(tss);
     683                 tss_size_ *= 2;
     684                 tss = ntss;
     685         }
     686  
     687         if (tss!=NULL)
     688                 tss[seqno % tss_size_] = tcph->ts(); 
     689 
     690     tcph->ts_echo() = ts_peer_;
     691     tcph->reason() = reason;
     692     tcph->last_rtt() = int(int(t_rtt_)*tcp_tick_*1000);
     693 
     694     if (ecn_) {
     695         hf->ect() = 1;    // ECN-capable transport
     696     }
     697     if (cong_action_ && (!is_retransmit || SetCWRonRetransmit_)) {
     698         hf->cong_action() = TRUE;  // Congestion action.
     699         cong_action_ = FALSE;
     700         }
     701     /* Check if this is the initial SYN packet. */
     702     if (seqno == 0) {
     703         if (syn_) {
     704             databytes = 0;
     705             if (maxseq_ == -1) {
     706                 curseq_ += 1; /*increment only on initial SYN*/
     707             }
     708             hdr_cmn::access(p)->size() = tcpip_base_hdr_size_;
     709             ++syn_connects_;
     710             //fprintf(stderr, "TCPAgent: syn_connects_ %d max_connects_ %d
    ",
     711             //    syn_connects_, max_connects_);
     712             if (max_connects_ > 0 &&
     713                                syn_connects_ > max_connects_) {
     714                   // Abort the connection.    
     715                   // What is the best way to abort the connection?    
     716                   curseq_ = 0;
     717                           rtx_timer_.resched(10000);
     718                               return;
     719                         }
     720         }
     721         if (ecn_) {
     722             hf->ecnecho() = 1;
     723 //            hf->cong_action() = 1;
     724             hf->ect() = 0;
     725         }
     726         if (qs_enabled_) {
     727             hdr_qs *qsh = hdr_qs::access(p);
     728 
     729             // dataout is kilobytes queued for sending
     730             int dataout = (curseq_ - maxseq_ - 1) * (size_ + headersize()) / 1024;
     731             int qs_rr = rate_request_;
     732             if (qs_request_mode_ == 1 && qs_rtt_ > 0) {
     733                 // PS: Avoid making unnecessary QS requests
     734                 // use a rough estimation of RTT in qs_rtt_
     735                 // to calculate the desired rate from dataout.
     736                 // printf("dataout %d qs_rr %d qs_rtt_ %d
    ",
     737                 //    dataout, qs_rr, qs_rtt_);
     738                 if (dataout * 1000 / qs_rtt_ < qs_rr) {
     739                     qs_rr = dataout * 1000 / qs_rtt_;
     740                 }
     741                 // printf("request %d
    ", qs_rr);
     742                 // qs_thresh_ is minimum number of unsent
     743                 // segments needed to activate QS request
     744                 // printf("curseq_ %d maxseq_ %d qs_thresh_ %d
    ",
     745                 //     int(curseq_), int(maxseq_), qs_thresh_);
     746                 if ((curseq_ - maxseq_ - 1) < qs_thresh_) {
     747                     qs_rr = 0;
     748                 }
     749             } 
     750 
     751                 if (qs_rr > 0) {
     752                 if (print_request_) 
     753                     printf("QS request (before encoding): %d KBps
    ", qs_rr);
     754                 // QuickStart code from Srikanth Sundarrajan.
     755                 qsh->flag() = QS_REQUEST;
     756                 qsh->ttl() = Random::integer(256);
     757                 ttl_diff_ = (iph->ttl() - qsh->ttl()) % 256;
     758                 qsh->rate() = hdr_qs::Bps_to_rate(qs_rr * 1024);
     759                 qs_requested_ = 1;
     760                 } else {
     761                 qsh->flag() = QS_DISABLE;
     762             }
     763         }
     764     }
     765     else if (useHeaders_ == true) {
     766         hdr_cmn::access(p)->size() += headersize();
     767     }
     768         hdr_cmn::access(p)->size();
     769 
     770     /* if no outstanding data, be sure to set rtx timer again */
     771     if (highest_ack_ == maxseq_)
     772         force_set_rtx_timer = 1;
     773     /* call helper function to fill in additional fields */
     774     output_helper(p);
     775 
     776         ++ndatapack_;
     777         ndatabytes_ += databytes;
     778     send(p, 0);
     779     if (seqno == curseq_ && seqno > maxseq_)
     780         idle();  // Tell application I have sent everything so far
     781     if (seqno > maxseq_) {
     782         maxseq_ = seqno;
     783         if (!rtt_active_) {
     784             rtt_active_ = 1;
     785             if (seqno > rtt_seq_) {
     786                 rtt_seq_ = seqno;
     787                 rtt_ts_ = Scheduler::instance().clock();
     788             }
     789                     
     790         }
     791     } else {
     792             ++nrexmitpack_;
     793         nrexmitbytes_ += databytes;
     794     }
     795     if (!(rtx_timer_.status() == TIMER_PENDING) || force_set_rtx_timer)
     796         /* No timer pending.  Schedule one. */
     797         set_rtx_timer();
     798 }
     799 
     800 /*
     801  * Must convert bytes into packets for one-way TCPs.
     802  * If nbytes == -1, this corresponds to infinite send.  We approximate
     803  * infinite by a very large number (TCP_MAXSEQ).
     804  */
     805 void TcpAgent::sendmsg(int nbytes, const char* /*flags*/)
     806 {
     807     if (nbytes == -1 && curseq_ <= TCP_MAXSEQ)
     808         curseq_ = TCP_MAXSEQ; 
     809     else
     810         curseq_ += (nbytes/size_ + (nbytes%size_ ? 1 : 0));
     811     send_much(0, 0, maxburst_);
     812 }
     813 
     814 void TcpAgent::advanceby(int delta)
     815 {
     816   curseq_ += delta;
     817     if (delta > 0)
     818         closed_ = 0;
     819     send_much(0, 0, maxburst_); 
     820 }
     821 
     822 
     823 int TcpAgent::command(int argc, const char*const* argv)
     824 {
     825     if (argc == 3) {
     826         if (strcmp(argv[1], "advance") == 0) {
     827             int newseq = atoi(argv[2]);
     828             if (newseq > maxseq_)
     829                 advanceby(newseq - curseq_);
     830             else
     831                 advanceby(maxseq_ - curseq_);
     832             return (TCL_OK);
     833         }
     834         if (strcmp(argv[1], "advanceby") == 0) {
     835             advanceby(atoi(argv[2]));
     836             return (TCL_OK);
     837         }
     838         if (strcmp(argv[1], "eventtrace") == 0) {
     839             et_ = (EventTrace *)TclObject::lookup(argv[2]);
     840             return (TCL_OK);
     841         }
     842         /*
     843          * Curtis Villamizar's trick to transfer tcp connection
     844          * parameters to emulate http persistent connections.
     845          *
     846          * Another way to do the same thing is to open one tcp
     847          * object and use start/stop/maxpkts_ or advanceby to control
     848          * how much data is sent in each burst.
     849          * With a single connection, slow_start_restart_
     850          * should be configured as desired.
     851          *
     852          * This implementation (persist) may not correctly
     853          * emulate pure-BSD-based systems which close cwnd
     854          * after the connection goes idle (slow-start
     855          * restart).  See appendix C in
     856          * Jacobson and Karels ``Congestion
     857          * Avoidance and Control'' at
     858          * <ftp://ftp.ee.lbl.gov/papers/congavoid.ps.Z>
     859          * (*not* the original
     860          * '88 paper) for why BSD does this.  See
     861          * ``Performance Interactions Between P-HTTP and TCP
     862          * Implementations'' in CCR 27(2) for descriptions of
     863          * what other systems do the same.
     864          *
     865          */
     866         if (strcmp(argv[1], "persist") == 0) {
     867             TcpAgent *other
     868               = (TcpAgent*)TclObject::lookup(argv[2]);
     869             cwnd_ = other->cwnd_;
     870             awnd_ = other->awnd_;
     871             ssthresh_ = other->ssthresh_;
     872             t_rtt_ = other->t_rtt_;
     873             t_srtt_ = other->t_srtt_;
     874             t_rttvar_ = other->t_rttvar_;
     875             t_backoff_ = other->t_backoff_;
     876             return (TCL_OK);
     877         }
     878     }
     879     return (Agent::command(argc, argv));
     880 }
     881 
     882 /*
     883  * Returns the window size adjusted to allow <num> segments past recovery
     884  * point to be transmitted on next ack.
     885  */
     886 int TcpAgent::force_wnd(int num)
     887 {
     888     return recover_ + num - (int)highest_ack_;
     889 }
     890 
     891 int TcpAgent::window()
     892 {
     893         /*
     894          * If F-RTO is enabled and first ack has come in, temporarily open
     895          * window for sending two segments.
     896      * The F-RTO code is from Pasi Sarolahti.  F-RTO is an algorithm
     897      * for detecting spurious retransmission timeouts.
     898          */
     899         if (frto_ == 2) {
     900                 return (force_wnd(2) < wnd_ ?
     901                         force_wnd(2) : (int)wnd_);
     902         } else {
     903         return (cwnd_ < wnd_ ? (int)cwnd_ : (int)wnd_);
     904         }
     905 }
     906 
     907 double TcpAgent::windowd()
     908 {
     909     return (cwnd_ < wnd_ ? (double)cwnd_ : (double)wnd_);
     910 }
     911 
     912 /*
     913  * Try to send as much data as the window will allow.  The link layer will 
     914  * do the buffering; we ask the application layer for the size of the packets.
     915  */
     916 void TcpAgent::send_much(int force, int reason, int maxburst)
     917 {
     918     send_idle_helper();
     919     int win = window();
     920     int npackets = 0;
     921 
     922     if (!force && delsnd_timer_.status() == TIMER_PENDING)
     923         return;
     924     /* Save time when first packet was sent, for newreno  --Allman */
     925     if (t_seqno_ == 0)
     926         firstsent_ = Scheduler::instance().clock();
     927 
     928     if (burstsnd_timer_.status() == TIMER_PENDING)
     929         return;
     930     while (t_seqno_ <= highest_ack_ + win && t_seqno_ < curseq_) {
     931         if (overhead_ == 0 || force || qs_approved_) {
     932             output(t_seqno_, reason);
     933             npackets++;
     934             if (QOption_)
     935                 process_qoption_after_send () ; 
     936             t_seqno_ ++ ;
     937             if (qs_approved_ == 1) {
     938                 // delay = effective RTT / window
     939                 double delay = (double) t_rtt_ * tcp_tick_ / win;
     940                 if (overhead_) { 
     941                     delsnd_timer_.resched(delay + Random::uniform(overhead_));
     942                 } else {
     943                     delsnd_timer_.resched(delay);
     944                 }
     945                 return;
     946             }
     947         } else if (!(delsnd_timer_.status() == TIMER_PENDING)) {
     948             /*
     949              * Set a delayed send timeout.
     950              */
     951             delsnd_timer_.resched(Random::uniform(overhead_));
     952             return;
     953         }
     954         win = window();
     955         if (maxburst && npackets == maxburst)
     956             break;
     957     }
     958     /* call helper function */
     959     send_helper(maxburst);
     960 }
     961 
     962 /*
     963  * We got a timeout or too many duplicate acks.  Clear the retransmit timer.  
     964  * Resume the sequence one past the last packet acked.  
     965  * "mild" is 0 for timeouts and Tahoe dup acks, 1 for Reno dup acks.
     966  * "backoff" is 1 if the timer should be backed off, 0 otherwise.
     967  */
     968 void TcpAgent::reset_rtx_timer(int mild, int backoff)
     969 {
     970     if (backoff)
     971         rtt_backoff();
     972     set_rtx_timer();
     973     if (!mild)
     974         t_seqno_ = highest_ack_ + 1;
     975     rtt_active_ = 0;
     976 }
     977 
     978 /*
     979  * Set retransmit timer using current rtt estimate.  By calling resched(), 
     980  * it does not matter whether the timer was already running.
     981  */
     982 void TcpAgent::set_rtx_timer()
     983 {
     984     rtx_timer_.resched(rtt_timeout());
     985 }
     986 
     987 /*
     988  * Set new retransmission timer if not all outstanding
     989  * or available data acked, or if we are unable to send because 
     990  * cwnd is less than one (as when the ECN bit is set when cwnd was 1).
     991  * Otherwise, if a timer is still outstanding, cancel it.
     992  */
     993 void TcpAgent::newtimer(Packet* pkt)
     994 {
     995     hdr_tcp *tcph = hdr_tcp::access(pkt);
     996     /*
     997      * t_seqno_, the next packet to send, is reset (decreased) 
     998      *   to highest_ack_ + 1 after a timeout,
     999      *   so we also have to check maxseq_, the highest seqno sent.
    1000      * In addition, if the packet sent after the timeout has
    1001      *   the ECN bit set, then the returning ACK caused cwnd_ to
    1002      *   be decreased to less than one, and we can't send another
    1003      *   packet until the retransmit timer again expires.
    1004      *   So we have to check for "cwnd_ < 1" as well.
    1005      */
    1006     if (t_seqno_ > tcph->seqno() || tcph->seqno() < maxseq_ || cwnd_ < 1) 
    1007         set_rtx_timer();
    1008     else
    1009         cancel_rtx_timer();
    1010 }
    1011 
    1012 /*
    1013  * for experimental, high-speed TCP
    1014  */
    1015 double TcpAgent::linear(double x, double x_1, double y_1, double x_2, double y_2)
    1016 {
    1017     // The y coordinate factor ranges from y_1 to y_2
    1018     //  as the x coordinate ranges from x_1 to x_2.
    1019     double y = y_1 + ((y_2 - y_1) * ((x - x_1)/(x_2-x_1)));
    1020     return y;
    1021 }
    1022 
    1023 /*
    1024  * Limited Slow-Start for large congestion windows.
    1025  * This should only be called when max_ssthresh_ is non-zero.
    1026  */
    1027 double TcpAgent::limited_slow_start(double cwnd, int max_ssthresh, double increment)
    1028 {
    1029         if (max_ssthresh <= 0) {
    1030           return increment;
    1031     } else {
    1032                 double increment1 = 0.0;
    1033         int round = int(cwnd / (double(max_ssthresh)/2.0));
    1034         if (round > 0) {
    1035               increment1 = 1.0/double(round); 
    1036         } 
    1037         if (increment < increment1) {
    1038               return increment1;
    1039         } else {
    1040               return increment;
    1041         }
    1042     }
    1043 }
    1044 
    1045 /*
    1046  * For retrieving numdupacks_.
    1047  */
    1048 int TcpAgent::numdupacks(double cwnd)
    1049 {
    1050         int cwndfraction = (int) cwnd/numdupacksFrac_;
    1051     if (numdupacks_ > cwndfraction) {
    1052           return numdupacks_;
    1053         } else {
    1054           return cwndfraction;
    1055     }
    1056 }
    1057 
    1058 /*
    1059  * Calculating the decrease parameter for highspeed TCP.
    1060  */
    1061 double TcpAgent::decrease_param()
    1062 {
    1063     double decrease;
    1064     // OLD:
    1065     // decrease = linear(log(cwnd_), log(low_window_), 0.5, log(high_window_), high_decrease_);
    1066     // NEW (but equivalent):
    1067         decrease = hstcp_.dec1 + log(cwnd_) * hstcp_.dec2;  
    1068     return decrease;
    1069 }
    1070 
    1071 /*
    1072  * Calculating the increase parameter for highspeed TCP.
    1073  */
    1074 double TcpAgent::increase_param()
    1075 {
    1076     double increase, decrease, p, answer;
    1077     /* extending the slow-start for high-speed TCP */
    1078 
    1079     /* for highspeed TCP -- from Sylvia Ratnasamy, */
    1080     /* modifications by Sally Floyd and Evandro de Souza */
    1081      // p ranges from 1.5/W^2 at congestion window low_window_, to
    1082     //    high_p_ at congestion window high_window_, on a log-log scale.
    1083         // The decrease factor ranges from 0.5 to high_decrease
    1084     //  as the window ranges from low_window to high_window, 
    1085     //  as the log of the window. 
    1086     // For an efficient implementation, this would just be looked up
    1087     //   in a table, with the increase and decrease being a function of the
    1088     //   congestion window.
    1089 
    1090        if (cwnd_ <= low_window_) { 
    1091         answer = 1 / cwnd_;
    1092                return answer; 
    1093        } else if (cwnd_ >= hstcp_.cwnd_last_ && 
    1094           cwnd_ < hstcp_.cwnd_last_ + cwnd_range_) {
    1095           // cwnd_range_ can be set to 0 to be disabled,
    1096           //  or can be set from 1 to 100 
    1097                answer = hstcp_.increase_last_ / cwnd_;
    1098                   return answer;
    1099        } else { 
    1100         // OLD:
    1101          // p = exp(linear(log(cwnd_), log(low_window_), log(hstcp_.low_p), log(high_window_), log(high_p_)));
    1102         // NEW, but equivalent:
    1103             p = exp(hstcp_.p1 + log(cwnd_) * hstcp_.p2);  
    1104             decrease = decrease_param();
    1105         // OLD:
    1106         // increase = cwnd_*cwnd_*p *(2.0*decrease)/(2.0 - decrease); 
    1107         // NEW, but equivalent:
    1108         increase = cwnd_ * cwnd_ * p /(1/decrease - 0.5);
    1109         //    if (increase > max_increase) { 
    1110         //        increase = max_increase;
    1111         //    } 
    1112         answer = increase / cwnd_;
    1113         hstcp_.cwnd_last_ = cwnd_;
    1114         hstcp_.increase_last_ = increase;
    1115                return answer;
    1116     }       
    1117 }
    1118 
    1119 /*
    1120  * open up the congestion window
    1121  */
    1122 void TcpAgent::opencwnd()
    1123 {
    1124     double increment;
    1125     if (cwnd_ < ssthresh_) {
    1126         /* slow-start (exponential) */
    1127         cwnd_ += 1;
    1128     } else {
    1129         /* linear */
    1130         double f;
    1131         switch (wnd_option_) {
    1132         case 0:
    1133             if (++count_ >= cwnd_) {
    1134                 count_ = 0;
    1135                 ++cwnd_;
    1136             }
    1137             break;
    1138 
    1139         case 1:
    1140             /* This is the standard algorithm. */
    1141             increment = increase_num_ / cwnd_;
    1142             if ((last_cwnd_action_ == 0 ||
    1143               last_cwnd_action_ == CWND_ACTION_TIMEOUT) 
    1144               && max_ssthresh_ > 0) {
    1145                 increment = limited_slow_start(cwnd_,
    1146                   max_ssthresh_, increment);
    1147             }
    1148             cwnd_ += increment;
    1149             break;
    1150 
    1151         case 2:
    1152             /* These are window increase algorithms
    1153              * for experimental purposes only. */
    1154             /* This is the Constant-Rate increase algorithm 
    1155                          *  from the 1991 paper by S. Floyd on "Connections  
    1156              *  with Multiple Congested Gateways". 
    1157              *  The window is increased by roughly 
    1158              *  wnd_const_*RTT^2 packets per round-trip time.  */
    1159             f = (t_srtt_ >> T_SRTT_BITS) * tcp_tick_;
    1160             f *= f;
    1161             f *= wnd_const_;
    1162             /* f = wnd_const_ * RTT^2 */
    1163             f += fcnt_;
    1164             if (f > cwnd_) {
    1165                 fcnt_ = 0;
    1166                 ++cwnd_;
    1167             } else
    1168                 fcnt_ = f;
    1169             break;
    1170 
    1171         case 3:
    1172             /* The window is increased by roughly 
    1173              *  awnd_^2 * wnd_const_ packets per RTT,
    1174              *  for awnd_ the average congestion window. */
    1175             f = awnd_;
    1176             f *= f;
    1177             f *= wnd_const_;
    1178             f += fcnt_;
    1179             if (f > cwnd_) {
    1180                 fcnt_ = 0;
    1181                 ++cwnd_;
    1182             } else
    1183                 fcnt_ = f;
    1184             break;
    1185 
    1186                 case 4:
    1187             /* The window is increased by roughly 
    1188              *  awnd_ * wnd_const_ packets per RTT,
    1189              *  for awnd_ the average congestion window. */
    1190                         f = awnd_;
    1191                         f *= wnd_const_;
    1192                         f += fcnt_;
    1193                         if (f > cwnd_) {
    1194                                 fcnt_ = 0;
    1195                                 ++cwnd_;
    1196                         } else
    1197                                 fcnt_ = f;
    1198                         break;
    1199         case 5:
    1200             /* The window is increased by roughly wnd_const_*RTT 
    1201              *  packets per round-trip time, as discussed in
    1202              *  the 1992 paper by S. Floyd on "On Traffic 
    1203              *  Phase Effects in Packet-Switched Gateways". */
    1204                         f = (t_srtt_ >> T_SRTT_BITS) * tcp_tick_;
    1205                         f *= wnd_const_;
    1206                         f += fcnt_;
    1207                         if (f > cwnd_) {
    1208                                 fcnt_ = 0;
    1209                                 ++cwnd_;
    1210                         } else
    1211                                 fcnt_ = f;
    1212                         break;
    1213                 case 6:
    1214                         /* binomial controls */ 
    1215                         cwnd_ += increase_num_ / (cwnd_*pow(cwnd_,k_parameter_));                
    1216                         break; 
    1217          case 8: 
    1218             /* high-speed TCP, RFC 3649 */
    1219             increment = increase_param();
    1220             if ((last_cwnd_action_ == 0 ||
    1221               last_cwnd_action_ == CWND_ACTION_TIMEOUT) 
    1222               && max_ssthresh_ > 0) {
    1223                 increment = limited_slow_start(cwnd_,
    1224                   max_ssthresh_, increment);
    1225             }
    1226             cwnd_ += increment;
    1227                         break;
    1228         default:
    1229 #ifdef notdef
    1230             /*XXX*/
    1231             error("illegal window option %d", wnd_option_);
    1232 #endif
    1233             abort();
    1234         }
    1235     }
    1236     // if maxcwnd_ is set (nonzero), make it the cwnd limit
    1237     if (maxcwnd_ && (int(cwnd_) > maxcwnd_))
    1238         cwnd_ = maxcwnd_;
    1239 
    1240     return;
    1241 }
    1242 
    1243 // Shigeyuki Osada 2012/01/08
    1244 void TcpAgent::recv_helper(Packet* pkt)
    1245 {
    1246     hdr_tcp *tcph = hdr_tcp::access(pkt);
    1247      //double now = Scheduler::instance().clock();
    1248     //hdr_ip *iph   = hdr_ip::access(pkt);
    1249     //cout << now << ": Server recv pkt with win "
    1250     //     << tcph->wnd() 
    1251     //     << " seqno: "  << tcph->seqno()
    1252     //     << " nodeid: " << iph->daddr() 
    1253     //     << "
    ";
    1254     if (tcph->wnd() > 0) {
    1255         // wnd == 0 can be occuerd but this is not considered.
    1256         // future works. Shigeyuki Osada 2012/01/08
    1257         wnd_ = tcph->wnd();
    1258     }
    1259     return;
    1260 }
    1261 
    1262 void
    1263 TcpAgent::slowdown(int how)
    1264 {
    1265     double decrease;  /* added for highspeed - sylvia */
    1266     double win, halfwin, decreasewin;
    1267     int slowstart = 0;
    1268     ++ncwndcuts_;
    1269     if (!(how & TCP_IDLE) && !(how & NO_OUTSTANDING_DATA)){
    1270         ++ncwndcuts1_; 
    1271     }
    1272     // we are in slowstart for sure if cwnd < ssthresh
    1273     if (cwnd_ < ssthresh_) 
    1274         slowstart = 1;
    1275         if (precision_reduce_) {
    1276         halfwin = windowd() / 2;
    1277                 if (wnd_option_ == 6) {         
    1278                         /* binomial controls */
    1279                         decreasewin = windowd() - (1.0-decrease_num_)*pow(windowd(),l_parameter_);
    1280                 } else if (wnd_option_ == 8 && (cwnd_ > low_window_)) { 
    1281                         /* experimental highspeed TCP */
    1282             decrease = decrease_param();
    1283             //if (decrease < 0.1) 
    1284             //    decrease = 0.1;
    1285             decrease_num_ = decrease;
    1286                         decreasewin = windowd() - (decrease * windowd());
    1287                 } else {
    1288              decreasewin = decrease_num_ * windowd();
    1289         }
    1290         win = windowd();
    1291     } else  {
    1292         int temp;
    1293         temp = (int)(window() / 2);
    1294         halfwin = (double) temp;
    1295                 if (wnd_option_ == 6) {
    1296                         /* binomial controls */
    1297                         temp = (int)(window() - (1.0-decrease_num_)*pow(window(),l_parameter_));
    1298                 } else if ((wnd_option_ == 8) && (cwnd_ > low_window_)) { 
    1299                         /* experimental highspeed TCP */
    1300             decrease = decrease_param();
    1301             //if (decrease < 0.1)
    1302                         //       decrease = 0.1;        
    1303             decrease_num_ = decrease;
    1304                         temp = (int)(windowd() - (decrease * windowd()));
    1305                 } else {
    1306              temp = (int)(decrease_num_ * window());
    1307         }
    1308         decreasewin = (double) temp;
    1309         win = (double) window();
    1310     }
    1311     if (how & CLOSE_SSTHRESH_HALF)
    1312         // For the first decrease, decrease by half
    1313         // even for non-standard values of decrease_num_.
    1314         if (first_decrease_ == 1 || slowstart ||
    1315             last_cwnd_action_ == CWND_ACTION_TIMEOUT) {
    1316             // Do we really want halfwin instead of decreasewin
    1317         // after a timeout?
    1318             ssthresh_ = (int) halfwin;
    1319         } else {
    1320             ssthresh_ = (int) decreasewin;
    1321         }
    1322         else if (how & THREE_QUARTER_SSTHRESH)
    1323         if (ssthresh_ < 3*cwnd_/4)
    1324             ssthresh_  = (int)(3*cwnd_/4);
    1325     if (how & CLOSE_CWND_HALF)
    1326         // For the first decrease, decrease by half
    1327         // even for non-standard values of decrease_num_.
    1328         if (first_decrease_ == 1 || slowstart || decrease_num_ == 0.5) {
    1329             cwnd_ = halfwin;
    1330         } else cwnd_ = decreasewin;
    1331         else if (how & CWND_HALF_WITH_MIN) {
    1332         // We have not thought about how non-standard TCPs, with
    1333         // non-standard values of decrease_num_, should respond
    1334         // after quiescent periods.
    1335                 cwnd_ = decreasewin;
    1336                 if (cwnd_ < 1)
    1337                         cwnd_ = 1;
    1338     }
    1339     else if (how & CLOSE_CWND_RESTART) 
    1340         cwnd_ = int(wnd_restart_);
    1341     else if (how & CLOSE_CWND_INIT)
    1342         cwnd_ = int(wnd_init_);
    1343     else if (how & CLOSE_CWND_ONE)
    1344         cwnd_ = 1;
    1345     else if (how & CLOSE_CWND_HALF_WAY) {
    1346         // cwnd_ = win - (win - W_used)/2 ;
    1347         cwnd_ = W_used + decrease_num_ * (win - W_used);
    1348                 if (cwnd_ < 1)
    1349                         cwnd_ = 1;
    1350     }
    1351     if (ssthresh_ < 2)
    1352         ssthresh_ = 2;
    1353     if (how & (CLOSE_CWND_HALF|CLOSE_CWND_RESTART|CLOSE_CWND_INIT|CLOSE_CWND_ONE))
    1354         cong_action_ = TRUE;
    1355 
    1356     fcnt_ = count_ = 0;
    1357     if (first_decrease_ == 1)
    1358         first_decrease_ = 0;
    1359     // for event tracing slow start
    1360     if (cwnd_ == 1 || slowstart) 
    1361         // Not sure if this is best way to capture slow_start
    1362         // This is probably tracing a superset of slowdowns of
    1363         // which all may not be slow_start's --Padma, 07/'01.
    1364         trace_event("SLOW_START");
    1365     
    1366 
    1367 
    1368     
    1369 }
    1370 
    1371 /*
    1372  * Process a packet that acks previously unacknowleged data.
    1373  */
    1374 void TcpAgent::newack(Packet* pkt)
    1375 {
    1376      double now = Scheduler::instance().clock();
    1377     hdr_tcp *tcph = hdr_tcp::access(pkt);
    1378     /* 
    1379      * Wouldn't it be better to set the timer *after*
    1380      * updating the RTT, instead of *before*? 
    1381      */
    1382     if (!timerfix_) newtimer(pkt);
    1383     dupacks_ = 0;
    1384     last_ack_ = tcph->seqno();
    1385     prev_highest_ack_ = highest_ack_ ;
    1386     highest_ack_ = last_ack_;
    1387 
    1388     if (t_seqno_ < last_ack_ + 1)
    1389         t_seqno_ = last_ack_ + 1;
    1390     /* 
    1391      * Update RTT only if it's OK to do so from info in the flags header.
    1392      * This is needed for protocols in which intermediate agents
    1393      * in the network intersperse acks (e.g., ack-reconstructors) for
    1394      * various reasons (without violating e2e semantics).
    1395      */    
    1396     hdr_flags *fh = hdr_flags::access(pkt);
    1397     if (!fh->no_ts_) {
    1398         if (ts_option_) {
    1399             ts_echo_=tcph->ts_echo();
    1400             rtt_update(now - tcph->ts_echo());
    1401             if (ts_resetRTO_ && (!ect_ || !ecn_backoff_ ||
    1402                 !hdr_flags::access(pkt)->ecnecho())) { 
    1403                 // From Andrei Gurtov
    1404                 /* 
    1405                  * Don't end backoff if still in ECN-Echo with
    1406                   * a congestion window of 1 packet. 
    1407                  */
    1408                 t_backoff_ = 1;
    1409                 ecn_backoff_ = 0;
    1410             }
    1411         }
    1412         if (rtt_active_ && tcph->seqno() >= rtt_seq_) {
    1413             if (!ect_ || !ecn_backoff_ || 
    1414                 !hdr_flags::access(pkt)->ecnecho()) {
    1415                 /* 
    1416                  * Don't end backoff if still in ECN-Echo with
    1417                   * a congestion window of 1 packet. 
    1418                  */
    1419                 t_backoff_ = 1;
    1420                 ecn_backoff_ = 0;
    1421             }
    1422             rtt_active_ = 0;
    1423             if (!ts_option_)
    1424                 rtt_update(now - rtt_ts_);
    1425         }
    1426     }
    1427     if (timerfix_) newtimer(pkt);
    1428     /* update average window */
    1429     awnd_ *= 1.0 - wnd_th_;
    1430     awnd_ += wnd_th_ * cwnd_;
    1431 }
    1432 
    1433 
    1434 /*
    1435  * Respond either to a source quench or to a congestion indication bit.
    1436  * This is done at most once a roundtrip time;  after a source quench,
    1437  * another one will not be done until the last packet transmitted before
    1438  * the previous source quench has been ACKed.
    1439  *
    1440  * Note that this procedure is called before "highest_ack_" is
    1441  * updated to reflect the current ACK packet.  
    1442  */
    1443 void TcpAgent::ecn(int seqno)
    1444 {
    1445     if (seqno > recover_ || 
    1446           last_cwnd_action_ == CWND_ACTION_TIMEOUT) {
    1447         recover_ =  maxseq_;
    1448         last_cwnd_action_ = CWND_ACTION_ECN;
    1449         if (cwnd_ <= 1.0) {
    1450             if (ecn_backoff_) 
    1451                 rtt_backoff();
    1452             else ecn_backoff_ = 1;
    1453         } else ecn_backoff_ = 0;
    1454         slowdown(CLOSE_CWND_HALF|CLOSE_SSTHRESH_HALF);
    1455         ++necnresponses_ ;
    1456         // added by sylvia to count number of ecn responses 
    1457     }
    1458 }
    1459 
    1460 /*
    1461  *  Is the connection limited by the network (instead of by a lack
    1462  *    of data from the application?
    1463  */
    1464 int TcpAgent::network_limited() {
    1465     int win = window () ;
    1466     if (t_seqno_ > (prev_highest_ack_ + win))
    1467         return 1;
    1468     else
    1469         return 0;
    1470 }
    1471 
    1472 void TcpAgent::recv_newack_helper(Packet *pkt) {
    1473     //hdr_tcp *tcph = hdr_tcp::access(pkt);
    1474     newack(pkt);
    1475         if (qs_window_ && highest_ack_ >= qs_window_) {
    1476                 // All segments in the QS window have been acknowledged.
    1477                 // We can exit the Quick-Start phase.
    1478                 qs_window_ = 0;
    1479         }
    1480     if (!ect_ || !hdr_flags::access(pkt)->ecnecho() ||
    1481         (old_ecn_ && ecn_burst_)) {
    1482         /* If "old_ecn", this is not the first ACK carrying ECN-Echo
    1483          * after a period of ACKs without ECN-Echo.
    1484          * Therefore, open the congestion window. */
    1485         /* if control option is set, and the sender is not
    1486              window limited, then do not increase the window size */
    1487         
    1488         if (!control_increase_ || 
    1489            (control_increase_ && (network_limited() == 1))) 
    1490                   opencwnd();
    1491     }
    1492     if (ect_) {
    1493         if (!hdr_flags::access(pkt)->ecnecho())
    1494             ecn_backoff_ = 0;
    1495         if (!ecn_burst_ && hdr_flags::access(pkt)->ecnecho())
    1496             ecn_burst_ = TRUE;
    1497         else if (ecn_burst_ && ! hdr_flags::access(pkt)->ecnecho())
    1498             ecn_burst_ = FALSE;
    1499     }
    1500     if (!ect_ && hdr_flags::access(pkt)->ecnecho() &&
    1501         !hdr_flags::access(pkt)->cong_action())
    1502         ect_ = 1;
    1503     /* if the connection is done, call finish() */
    1504     if ((highest_ack_ >= curseq_-1) && !closed_) {
    1505         closed_ = 1;
    1506         finish();
    1507     }
    1508     if (QOption_ && curseq_ == highest_ack_ +1) {
    1509         cancel_rtx_timer();
    1510     }
    1511     if (frto_ == 1) {
    1512         /*
    1513          * New ack after RTO. If F-RTO is enabled, try to transmit new
    1514          * previously unsent segments.
    1515          * If there are no new data or receiver window limits the
    1516          * transmission, revert to traditional recovery.
    1517          */
    1518         if (recover_ + 1 >= highest_ack_ + wnd_ ||
    1519             recover_ + 1 >= curseq_) {
    1520             frto_ = 0;
    1521          } else if (highest_ack_ == recover_) {
    1522              /*
    1523               * F-RTO step 2a) RTO retransmission fixes whole
    1524              * window => cancel F-RTO
    1525               */
    1526              frto_ = 0;
    1527         } else {
    1528             t_seqno_ = recover_ + 1;
    1529             frto_ = 2;
    1530         }
    1531     } else if (frto_ == 2) {
    1532         /*
    1533          * Second new ack after RTO. If F-RTO is enabled, RTO can be
    1534          * declared spurious
    1535          */
    1536         spurious_timeout();
    1537     }
    1538 }
    1539 
    1540 /*
    1541  * Set the initial window. 
    1542  */
    1543 double
    1544 TcpAgent::initial_window()
    1545 {
    1546         // If Quick-Start Request was approved, use that as a basis for
    1547         // initial window
    1548         if (qs_cwnd_) {
    1549                 return (qs_cwnd_);
    1550         }
    1551     //
    1552     // init_option = 1: static iw of wnd_init_
    1553     //
    1554     if (wnd_init_option_ == 1) {
    1555         return (wnd_init_);
    1556     }
    1557         else if (wnd_init_option_ == 2) {
    1558         // do iw according to Internet draft
    1559          if (size_ <= 1095) {
    1560             return (4.0);
    1561          } else if (size_ < 2190) {
    1562             return (3.0);
    1563         } else {
    1564             return (2.0);
    1565         }
    1566     }
    1567     // XXX what should we return here???
    1568     fprintf(stderr, "Wrong number of wnd_init_option_ %d
    ", 
    1569         wnd_init_option_);
    1570     abort();
    1571     return (2.0); // XXX make msvc happy.
    1572 }
    1573 
    1574 /*
    1575  * Dupack-action: what to do on a DUP ACK.  After the initial check
    1576  * of 'recover' below, this function implements the following truth
    1577  * table:
    1578  *
    1579  *    bugfix    ecn    last-cwnd == ecn    action
    1580  *
    1581  *    0    0    0            tahoe_action
    1582  *    0    0    1            tahoe_action    [impossible]
    1583  *    0    1    0            tahoe_action
    1584  *    0    1    1            slow-start, return
    1585  *    1    0    0            nothing
    1586  *    1    0    1            nothing        [impossible]
    1587  *    1    1    0            nothing
    1588  *    1    1    1            slow-start, return
    1589  */
    1590 
    1591 /* 
    1592  * A first or second duplicate acknowledgement has arrived, and
    1593  * singledup_ is enabled.
    1594  * If the receiver's advertised window permits, and we are exceeding our
    1595  * congestion window by less than numdupacks_, then send a new packet.
    1596  */
    1597 void
    1598 TcpAgent::send_one()
    1599 {
    1600     if (t_seqno_ <= highest_ack_ + wnd_ && t_seqno_ < curseq_ &&
    1601         t_seqno_ <= highest_ack_ + cwnd_ + dupacks_ ) {
    1602         output(t_seqno_, 0);
    1603         if (QOption_)
    1604             process_qoption_after_send () ;
    1605         t_seqno_ ++ ;
    1606         // send_helper(); ??
    1607     }
    1608     return;
    1609 }
    1610 
    1611 void
    1612 TcpAgent::dupack_action()
    1613 {
    1614     int recovered = (highest_ack_ > recover_);
    1615     if (recovered || (!bug_fix_ && !ecn_) || 
    1616         (bugfix_ss_ && highest_ack_ == 0)) {
    1617         // (highest_ack_ == 0) added to allow Fast Retransmit
    1618         //  when the first data packet is dropped.
    1619         //  Bug report from Mark Allman.
    1620         goto tahoe_action;
    1621     }
    1622 
    1623     if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
    1624         last_cwnd_action_ = CWND_ACTION_DUPACK;
    1625         slowdown(CLOSE_CWND_ONE);
    1626         reset_rtx_timer(0,0);
    1627         return;
    1628     }
    1629 
    1630     if (bug_fix_) {
    1631         /*
    1632          * The line below, for "bug_fix_" true, avoids
    1633          * problems with multiple fast retransmits in one
    1634          * window of data. 
    1635          */
    1636         return;
    1637     }
    1638 
    1639 tahoe_action:
    1640         recover_ = maxseq_;
    1641         if (!lossQuickStart()) {
    1642         // we are now going to fast-retransmit and willtrace that event
    1643         trace_event("FAST_RETX");
    1644         last_cwnd_action_ = CWND_ACTION_DUPACK;
    1645         slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_ONE);
    1646     }
    1647     reset_rtx_timer(0,0);
    1648     return;
    1649 }
    1650 
    1651 /*
    1652  * When exiting QuickStart, reduce the congestion window to the
    1653  *   size that was actually used.
    1654  */
    1655 void TcpAgent::endQuickStart()
    1656 {
    1657     qs_approved_ = 0;
    1658         qs_cwnd_ = 0;
    1659         qs_window_ = maxseq_;
    1660     int new_cwnd = maxseq_ - last_ack_;
    1661     if (new_cwnd > 1 && new_cwnd < cwnd_) {
    1662          cwnd_ = new_cwnd;
    1663         if (cwnd_ < initial_window()) 
    1664             cwnd_ = initial_window();
    1665     }
    1666 }
    1667 
    1668 void TcpAgent::processQuickStart(Packet *pkt)
    1669 {
    1670     // QuickStart code from Srikanth Sundarrajan.
    1671     hdr_tcp *tcph = hdr_tcp::access(pkt);
    1672     hdr_qs *qsh = hdr_qs::access(pkt);
    1673     double now = Scheduler::instance().clock();
    1674     int app_rate;
    1675 
    1676         // printf("flag: %d ttl: %d ttl_diff: %d rate: %d
    ", qsh->flag(),
    1677     //     qsh->ttl(), ttl_diff_, qsh->rate());
    1678     qs_requested_ = 0;
    1679     qs_approved_ = 0;
    1680     if (qsh->flag() == QS_RESPONSE && qsh->ttl() == ttl_diff_ && 
    1681             qsh->rate() > 0) {
    1682                 app_rate = (int) ((hdr_qs::rate_to_Bps(qsh->rate()) *
    1683                       (now - tcph->ts_echo())) / (size_ + headersize()));
    1684         if (print_request_) {
    1685           double num1 = hdr_qs::rate_to_Bps(qsh->rate());
    1686           double time = now - tcph->ts_echo();
    1687           int size = size_ + headersize();
    1688           printf("Quick Start request, rate: %g Bps, encoded rate: %d
    ", 
    1689              num1, qsh->rate());
    1690           printf("Quick Start request, window %d rtt: %4.2f pktsize: %d
    ",
    1691              app_rate, time, size);
    1692         }
    1693                 if (app_rate > initial_window()) {
    1694             qs_cwnd_ = app_rate;
    1695                         qs_approved_ = 1;
    1696                 }
    1697         } else { // Quick Start rejected
    1698 #ifdef QS_DEBUG
    1699                 printf("Quick Start rejected
    ");
    1700 #endif
    1701         }
    1702 
    1703 }
    1704 
    1705 
    1706 
    1707 /*
    1708  * ACK has been received, hook from recv()
    1709  */
    1710 void TcpAgent::recv_frto_helper(Packet *pkt)
    1711 {
    1712     hdr_tcp *tcph = hdr_tcp::access(pkt);
    1713     if (tcph->seqno() == last_ack_ && frto_ != 0) {
    1714         /*
    1715          * Duplicate ACK while in F-RTO indicates that the
    1716          * timeout was valid. Go to slow start retransmissions.
    1717          */
    1718         t_seqno_ = highest_ack_ + 1;
    1719         cwnd_ = frto_;
    1720         frto_ = 0;
    1721 
    1722         // Must zero dupacks (in order to trigger send_much at recv)
    1723         // dupacks is increased in recv after exiting this function
    1724         dupacks_ = -1;
    1725     }
    1726 }
    1727 
    1728 
    1729 /*
    1730  * A spurious timeout has been detected. Do appropriate actions.
    1731  */
    1732 void TcpAgent::spurious_timeout()
    1733 {
    1734     frto_ = 0;
    1735 
    1736     switch (spurious_response_) {
    1737     case 1:
    1738     default:
    1739         /*
    1740          * Full revert of congestion window
    1741          * (FlightSize before last acknowledgment)
    1742          */
    1743         cwnd_ = t_seqno_ - prev_highest_ack_;
    1744         break;
    1745  
    1746     case 2:
    1747         /*
    1748          * cwnd = reduced ssthresh (approx. half of the earlier pipe)
    1749          */
    1750         cwnd_ = ssthresh_; break;
    1751     case 3:
    1752         /*
    1753          * slow start, but without retransmissions
    1754          */
    1755         cwnd_ = 1; break;
    1756     }
    1757 
    1758     /*
    1759      * Revert ssthresh to size before retransmission timeout
    1760      */
    1761     ssthresh_ = pipe_prev_;
    1762 
    1763     /* If timeout was spurious, bugfix is not needed */
    1764     recover_ = highest_ack_ - 1;
    1765 }
    1766 
    1767 
    1768 /*
    1769  * Loss occurred in Quick-Start window.
    1770  * If Quick-Start is enabled, packet loss in the QS phase, during slow-start,
    1771  * should trigger slow start instead of the regular fast retransmit.
    1772  * We use variable tcp_qs_recovery_ to toggle this behaviour on and off.
    1773  * If tcp_qs_recovery_ is true, initiate slow start to probe for
    1774  * a correct window size.
    1775  *
    1776  * Return value: non-zero if Quick-Start specific loss recovery took place
    1777  */
    1778 int TcpAgent::lossQuickStart()
    1779 {
    1780        if (qs_window_ && tcp_qs_recovery_) {
    1781                 //recover_ = maxseq_;
    1782                 //reset_rtx_timer(1,0);
    1783                 slowdown(CLOSE_CWND_INIT);
    1784         // reset ssthresh to half of W-D/2?
    1785                 qs_window_ = 0;
    1786                 output(last_ack_ + 1, TCP_REASON_DUPACK);
    1787                 return 1;
    1788        }
    1789        return 0;
    1790 }
    1791 
    1792 
    1793 
    1794 
    1795 /*
    1796  * main reception path - should only see acks, otherwise the
    1797  * network connections are misconfigured
    1798  */
    1799 void TcpAgent::recv(Packet *pkt, Handler*)
    1800 {
    1801     hdr_tcp *tcph = hdr_tcp::access(pkt);
    1802     int valid_ack = 0;
    1803     if (qs_approved_ == 1 && tcph->seqno() > last_ack_) 
    1804         endQuickStart();
    1805     if (qs_requested_ == 1)
    1806         processQuickStart(pkt);
    1807 #ifdef notdef
    1808     if (pkt->type_ != PT_ACK) {
    1809         Tcl::instance().evalf("%s error "received non-ack"",
    1810                       name());
    1811         Packet::free(pkt);
    1812         return;
    1813     }
    1814 #endif
    1815     /* W.N.: check if this is from a previous incarnation */
    1816     if (tcph->ts() < lastreset_) {
    1817         // Remove packet and do nothing
    1818         Packet::free(pkt);
    1819         return;
    1820     }
    1821     ++nackpack_;
    1822     ts_peer_ = tcph->ts();
    1823     int ecnecho = hdr_flags::access(pkt)->ecnecho();
    1824     if (ecnecho && ecn_)
    1825         ecn(tcph->seqno());
    1826     recv_helper(pkt);
    1827     recv_frto_helper(pkt);
    1828     /* grow cwnd and check if the connection is done */ 
    1829     if (tcph->seqno() > last_ack_) {
    1830         recv_newack_helper(pkt);
    1831         if (last_ack_ == 0 && delay_growth_) { 
    1832             cwnd_ = initial_window();
    1833         }
    1834     } else if (tcph->seqno() == last_ack_) {
    1835                 if (hdr_flags::access(pkt)->eln_ && eln_) {
    1836                         tcp_eln(pkt);
    1837                         return;
    1838                 }
    1839         if (++dupacks_ == numdupacks_ && !noFastRetrans_) {
    1840             dupack_action();
    1841         } else if (dupacks_ < numdupacks_ && singledup_ ) {
    1842             send_one();
    1843         }
    1844     }
    1845 
    1846     if (QOption_ && EnblRTTCtr_)
    1847         process_qoption_after_ack (tcph->seqno());
    1848 
    1849     if (tcph->seqno() >= last_ack_)  
    1850         // Check if ACK is valid.  Suggestion by Mark Allman. 
    1851         valid_ack = 1;
    1852     Packet::free(pkt);
    1853     /*
    1854      * Try to send more data.
    1855      */
    1856     if (valid_ack || aggressive_maxburst_)
    1857         send_much(0, 0, maxburst_);
    1858 }
    1859 
    1860 /*
    1861  * Process timeout events other than rtx timeout. Having this as a separate 
    1862  * function allows derived classes to make alterations/enhancements (e.g.,
    1863  * response to new types of timeout events).
    1864  */ 
    1865 void TcpAgent::timeout_nonrtx(int tno) 
    1866 {
    1867     if (tno == TCP_TIMER_DELSND)  {
    1868      /*
    1869          * delayed-send timer, with random overhead
    1870          * to avoid phase effects
    1871          */
    1872         send_much(1, TCP_REASON_TIMEOUT, maxburst_);
    1873     }
    1874 }
    1875     
    1876 void TcpAgent::timeout(int tno)
    1877 {
    1878     /* retransmit timer */
    1879     if (tno == TCP_TIMER_RTX) {
    1880 
    1881         // There has been a timeout - will trace this event
    1882         trace_event("TIMEOUT");
    1883 
    1884         frto_ = 0;
    1885         // Set pipe_prev as per Eifel Response
    1886         pipe_prev_ = (window() > ssthresh_) ?
    1887             window() : (int)ssthresh_;
    1888 
    1889             if (cwnd_ < 1) cwnd_ = 1;
    1890         if (qs_approved_ == 1) qs_approved_ = 0;
    1891         if (highest_ack_ == maxseq_ && !slow_start_restart_) {
    1892             /*
    1893              * TCP option:
    1894              * If no outstanding data, then don't do anything.  
    1895              */
    1896              // Should this return be here?
    1897              // What if CWND_ACTION_ECN and cwnd < 1?
    1898              // return;
    1899         } else {
    1900             recover_ = maxseq_;
    1901             if (highest_ack_ == -1 && wnd_init_option_ == 2)
    1902                 /* 
    1903                  * First packet dropped, so don't use larger
    1904                  * initial windows. 
    1905                  */
    1906                 wnd_init_option_ = 1;
    1907                         else if ((highest_ack_ == -1) &&
    1908                                 (wnd_init_option_ == 1) && (wnd_init_ > 1)
    1909                 && bugfix_ss_)
    1910                                 /*
    1911                                  * First packet dropped, so don't use larger
    1912                                  * initial windows.  Bugfix from Mark Allman.
    1913                                  */
    1914                                 wnd_init_ = 1;
    1915             if (highest_ack_ == maxseq_ && restart_bugfix_)
    1916                    /* 
    1917                 * if there is no outstanding data, don't cut 
    1918                 * down ssthresh_.
    1919                 */
    1920                 slowdown(CLOSE_CWND_ONE|NO_OUTSTANDING_DATA);
    1921             else if (highest_ack_ < recover_ &&
    1922               last_cwnd_action_ == CWND_ACTION_ECN) {
    1923                    /*
    1924                 * if we are in recovery from a recent ECN,
    1925                 * don't cut down ssthresh_.
    1926                 */
    1927                 slowdown(CLOSE_CWND_ONE);
    1928                 if (frto_enabled_ || sfrto_enabled_) {
    1929                     frto_ = 1;
    1930                 }
    1931             }
    1932             else {
    1933                 ++nrexmit_;
    1934                 last_cwnd_action_ = CWND_ACTION_TIMEOUT;
    1935                 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);
    1936                 if (frto_enabled_ || sfrto_enabled_) {
    1937                     frto_ = 1;
    1938                 }
    1939             }
    1940         }
    1941         /* if there is no outstanding data, don't back off rtx timer */
    1942         if (highest_ack_ == maxseq_ && restart_bugfix_) {
    1943             reset_rtx_timer(0,0);
    1944         }
    1945         else {
    1946             reset_rtx_timer(0,1);
    1947         }
    1948         last_cwnd_action_ = CWND_ACTION_TIMEOUT;
    1949         send_much(0, TCP_REASON_TIMEOUT, maxburst_);
    1950     } 
    1951     else {
    1952         timeout_nonrtx(tno);
    1953     }
    1954 }
    1955 
    1956 /* 
    1957  * Check if the packet (ack) has the ELN bit set, and if it does, and if the
    1958  * last ELN-rxmitted packet is smaller than this one, then retransmit the
    1959  * packet.  Do not adjust the cwnd when this happens.
    1960  */
    1961 void TcpAgent::tcp_eln(Packet *pkt)
    1962 {
    1963         //int eln_rxmit;
    1964         hdr_tcp *tcph = hdr_tcp::access(pkt);
    1965         int ack = tcph->seqno();
    1966 
    1967         if (++dupacks_ == eln_rxmit_thresh_ && ack > eln_last_rxmit_) {
    1968                 /* Retransmit this packet */
    1969                 output(last_ack_ + 1, TCP_REASON_DUPACK);
    1970                 eln_last_rxmit_ = last_ack_+1;
    1971         } else
    1972                 send_much(0, 0, maxburst_);
    1973 
    1974         Packet::free(pkt);
    1975         return;
    1976 }
    1977 
    1978 /*
    1979  * This function is invoked when the connection is done. It in turn
    1980  * invokes the Tcl finish procedure that was registered with TCP.
    1981  */
    1982 void TcpAgent::finish()
    1983 {
    1984     Tcl::instance().evalf("%s done", this->name());
    1985 }
    1986 
    1987 void RtxTimer::expire(Event*)
    1988 {
    1989     a_->timeout(TCP_TIMER_RTX);
    1990 }
    1991 
    1992 void DelSndTimer::expire(Event*)
    1993 {
    1994     a_->timeout(TCP_TIMER_DELSND);
    1995 }
    1996 
    1997 void BurstSndTimer::expire(Event*)
    1998 {
    1999     a_->timeout(TCP_TIMER_BURSTSND);
    2000 }
    2001 
    2002 /*
    2003  * THE FOLLOWING FUNCTIONS ARE OBSOLETE, but REMAIN HERE
    2004  * DUE TO OTHER PEOPLE's TCPs THAT MIGHT USE THEM
    2005  *
    2006  * These functions are now replaced by ecn() and slowdown(),
    2007  * respectively.
    2008  */
    2009 
    2010 /*
    2011  * Respond either to a source quench or to a congestion indication bit.
    2012  * This is done at most once a roundtrip time;  after a source quench,
    2013  * another one will not be done until the last packet transmitted before
    2014  * the previous source quench has been ACKed.
    2015  */
    2016 void TcpAgent::quench(int how)
    2017 {
    2018     if (highest_ack_ >= recover_) {
    2019         recover_ =  maxseq_;
    2020         last_cwnd_action_ = CWND_ACTION_ECN;
    2021         closecwnd(how);
    2022     }
    2023 }
    2024 
    2025 /*
    2026  * close down the congestion window
    2027  */
    2028 void TcpAgent::closecwnd(int how)
    2029 {   
    2030     static int first_time = 1;
    2031     if (first_time == 1) {
    2032         fprintf(stderr, "the TcpAgent::closecwnd() function is now deprecated, please use the function slowdown() instead
    ");
    2033     }
    2034     switch (how) {
    2035     case 0:
    2036         /* timeouts */
    2037         ssthresh_ = int( window() / 2 );
    2038         if (ssthresh_ < 2)
    2039             ssthresh_ = 2;
    2040         cwnd_ = int(wnd_restart_);
    2041         break;
    2042 
    2043     case 1:
    2044         /* Reno dup acks, or after a recent congestion indication. */
    2045         // cwnd_ = window()/2;
    2046         cwnd_ = decrease_num_ * window();
    2047         ssthresh_ = int(cwnd_);
    2048         if (ssthresh_ < 2)
    2049             ssthresh_ = 2;        
    2050         break;
    2051 
    2052     case 2:
    2053         /* Tahoe dup acks          
    2054          * after a recent congestion indication */
    2055         cwnd_ = wnd_init_;
    2056         break;
    2057 
    2058     case 3:
    2059         /* Retransmit timeout, but no outstanding data. */ 
    2060         cwnd_ = int(wnd_init_);
    2061         break;
    2062     case 4:
    2063         /* Tahoe dup acks */
    2064         ssthresh_ = int( window() / 2 );
    2065         if (ssthresh_ < 2)
    2066             ssthresh_ = 2;
    2067         cwnd_ = 1;
    2068         break;
    2069 
    2070     default:
    2071         abort();
    2072     }
    2073     fcnt_ = 0.;
    2074     count_ = 0;
    2075 }
    2076 
    2077 /*
    2078  * Check if the sender has been idle or application-limited for more
    2079  * than an RTO, and if so, reduce the congestion window.
    2080  */
    2081 void TcpAgent::process_qoption_after_send ()
    2082 {
    2083     int tcp_now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5);
    2084     int rto = (int)(t_rtxcur_/tcp_tick_) ; 
    2085     /*double ct = Scheduler::instance().clock();*/
    2086 
    2087     if (!EnblRTTCtr_) {
    2088         if (tcp_now - T_last >= rto) {
    2089             // The sender has been idle.
    2090              slowdown(THREE_QUARTER_SSTHRESH|TCP_IDLE) ;
    2091             for (int i = 0 ; i < (tcp_now - T_last)/rto; i ++) {
    2092                 slowdown(CWND_HALF_WITH_MIN|TCP_IDLE);
    2093             }
    2094             T_prev = tcp_now ;
    2095             W_used = 0 ;
    2096         }
    2097         T_last = tcp_now ;
    2098         if (t_seqno_ == highest_ack_+ window()) {
    2099             T_prev = tcp_now ; 
    2100             W_used = 0 ; 
    2101         }
    2102         else if (t_seqno_ == curseq_-1) {
    2103             // The sender has no more data to send.
    2104             int tmp = t_seqno_ - highest_ack_ ;
    2105             if (tmp > W_used)
    2106                 W_used = tmp ;
    2107             if (tcp_now - T_prev >= rto) {
    2108                 // The sender has been application-limited.
    2109                 slowdown(THREE_QUARTER_SSTHRESH|TCP_IDLE);
    2110                 slowdown(CLOSE_CWND_HALF_WAY|TCP_IDLE);
    2111                 T_prev = tcp_now ;
    2112                 W_used = 0 ;
    2113             }
    2114         }
    2115     } else {
    2116         rtt_counting();
    2117     }
    2118 }
    2119 
    2120 /*
    2121  * Check if the sender has been idle or application-limited for more
    2122  * than an RTO, and if so, reduce the congestion window, for a TCP sender
    2123  * that "counts RTTs" by estimating the number of RTTs that fit into
    2124  * a single clock tick.
    2125  */
    2126 void
    2127 TcpAgent::rtt_counting()
    2128 {
    2129         int tcp_now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5);
    2130     int rtt = (int(t_srtt_) >> T_SRTT_BITS) ;
    2131 
    2132     if (rtt < 1) 
    2133         rtt = 1 ;
    2134     if (tcp_now - T_last >= 2*rtt) {
    2135         // The sender has been idle.
    2136         int RTTs ; 
    2137         RTTs = (tcp_now -T_last)*RTT_goodcount/(rtt*2) ; 
    2138         RTTs = RTTs - Backoffs ; 
    2139         Backoffs = 0 ; 
    2140         if (RTTs > 0) {
    2141             slowdown(THREE_QUARTER_SSTHRESH|TCP_IDLE) ;
    2142             for (int i = 0 ; i < RTTs ; i ++) {
    2143                 slowdown(CWND_HALF_WITH_MIN|TCP_IDLE);
    2144                 RTT_prev = RTT_count ; 
    2145                 W_used = 0 ;
    2146             }
    2147         }
    2148     }
    2149     T_last = tcp_now ;
    2150     if (tcp_now - T_start >= 2*rtt) {
    2151         if ((RTT_count > RTT_goodcount) || (F_full == 1)) {
    2152             RTT_goodcount = RTT_count ; 
    2153             if (RTT_goodcount < 1) RTT_goodcount = 1 ; 
    2154         }
    2155         RTT_prev = RTT_prev - RTT_count ;
    2156         RTT_count = 0 ; 
    2157         T_start  = tcp_now ;
    2158         F_full = 0;
    2159     }
    2160     if (t_seqno_ == highest_ack_ + window()) {
    2161         W_used = 0 ; 
    2162         F_full = 1 ; 
    2163         RTT_prev = RTT_count ;
    2164     }
    2165     else if (t_seqno_ == curseq_-1) {
    2166         // The sender has no more data to send.
    2167         int tmp = t_seqno_ - highest_ack_ ;
    2168         if (tmp > W_used)
    2169             W_used = tmp ;
    2170         if (RTT_count - RTT_prev >= 2) {
    2171             // The sender has been application-limited.
    2172             slowdown(THREE_QUARTER_SSTHRESH|TCP_IDLE) ;
    2173             slowdown(CLOSE_CWND_HALF_WAY|TCP_IDLE);
    2174             RTT_prev = RTT_count ; 
    2175             Backoffs ++ ; 
    2176             W_used = 0;
    2177         }
    2178     }
    2179     if (F_counting == 0) {
    2180         W_timed = t_seqno_  ;
    2181         F_counting = 1 ;
    2182     }
    2183 }
    2184 
    2185 void TcpAgent::process_qoption_after_ack (int seqno)
    2186 {
    2187     if (F_counting == 1) {
    2188         if (seqno >= W_timed) {
    2189             RTT_count ++ ; 
    2190             F_counting = 0 ; 
    2191         }
    2192         else {
    2193             if (dupacks_ == numdupacks_)
    2194                 RTT_count ++ ;
    2195         }
    2196     }
    2197 }
    2198 
    2199 void TcpAgent::trace_event(char *eventtype)
    2200 {
    2201     if (et_ == NULL) return;
    2202     int seqno = t_seqno_;
    2203     char *wrk = et_->buffer();
    2204     char *nwrk = et_->nbuffer();
    2205     if (wrk != 0)
    2206         sprintf(wrk,
    2207             "E "TIME_FORMAT" %d %d TCP %s %d %d %d",
    2208             et_->round(Scheduler::instance().clock()),   // time
    2209             addr(),                       // owner (src) node id
    2210             daddr(),                      // dst node id
    2211             eventtype,                    // event type
    2212             fid_,                         // flow-id
    2213             seqno,                        // current seqno
    2214             int(cwnd_)                         //cong. window
    2215             );
    2216     
    2217     if (nwrk != 0)
    2218         sprintf(nwrk,
    2219             "E -t "TIME_FORMAT" -o TCP -e %s -s %d.%d -d %d.%d",
    2220             et_->round(Scheduler::instance().clock()),   // time
    2221             eventtype,                    // event type
    2222             addr(),                       // owner (src) node id
    2223             port(),                       // owner (src) port id
    2224             daddr(),                      // dst node id
    2225             dport()                       // dst port id
    2226             );
    2227     et_->trace();
    2228 }
  • 相关阅读:
    Failed to load module "canberra-gtk-module"
    [Ubuntu18]桌面美化-仿MAC主题
    [Ubuntu]18自定义切换输入法的快捷键
    2016-2017-1 《信息安全系统设计基础》 学生博客及Git@OSC 链接
    2015-2016-2 《Java程序设计》 游戏化
    2015-2016-2 《Java程序设计》项目小组博客
    博客引用书单
    2015-2016-2 《网络攻防实践》 学生博客
    2015-2016-2 《网络攻击与防范》 学生博客
    《网络攻防技术与实践》学习指导
  • 原文地址:https://www.cnblogs.com/forcheryl/p/3997872.html
Copyright © 2020-2023  润新知