tcp-full-bay.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1997 The Regents of the University of California.
00003  * All rights reserved.
00004  * 
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. All advertising materials mentioning features or use of this software
00014  *    must display the following acknowledgement:
00015  *  This product includes software developed by the Network Research
00016  *  Group at Lawrence Berkeley National Laboratory.
00017  * 4. Neither the name of the University nor of the Laboratory may be used
00018  *    to endorse or promote products derived from this software without
00019  *    specific prior written permission.
00020  * 
00021  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00022  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00025  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00026  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00027  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00028  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  */
00033 
00034 /*
00035  * This code below was motivated in part by code contributed by
00036  * Kathie Nichols (nichols@com21.com).  The code below is based primarily
00037  * on the 4.4BSD TCP implementation. -KF [kfall@ee.lbl.gov]
00038  *
00039  * Major revisions, 8/97, kmn (vj)
00040  *
00041  * Some Warnings:
00042  *  this version of TCP will not work correctly if the sequence number
00043  *  goes above 2147483648 due to sequence number wrap
00044  *
00045  *  this version of TCP currently sends data on the 3rd segment of
00046  *  the initial 3-way handshake.  So, the typical sequence of events is
00047  *      A   ------> SYN ------> B
00048  *      A   <----- SYN+ACK ---- B
00049  *      A   ------> ACK+data -> B
00050  *  whereas many "real-world" TCPs don't send data until a 4th segment
00051  *
00052  *  there is no dynamic receiver's advertised window.   The advertised
00053  *  window is simulated by simply telling the sender a bound on the window
00054  *  size (wnd_).
00055  *
00056  *  in real TCP, a user process performing a read (via PRU_RCVD)
00057  *      calls tcp_output each time to (possibly) send a window
00058  *      update.  Here we don't have a user process, so we simulate
00059  *      a user process always ready to consume all the receive buffer
00060  *
00061  * Notes:
00062  *  wnd_, wnd_init_, cwnd_, ssthresh_ are in segment units
00063  *  sequence and ack numbers are in byte units
00064  *
00065  * Futures:
00066  *  there are different existing TCPs with respect to how
00067  *  ack's are handled on connection startup.  Some delay
00068  *  the ack for the first segment, which can cause connections
00069  *  to take longer to start up than if we be sure to ack it quickly.
00070  */
00071 
00072 #ifndef lint
00073 static const char rcsid[] =
00074     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/baytcp/tcp-full-bay.cc,v 1.4 2001/07/19 17:57:02 haldar Exp $ (LBL)";
00075 #endif
00076 
00077 #include "tclcl.h"
00078 #include "ip.h"
00079 #include "tcp-full-bay.h"
00080 #include "flags.h"
00081 #include "random.h"
00082 #include "template.h"
00083 
00084 #define TRUE    1
00085 #define FALSE   0
00086 
00087 static class BayFullTcpClass : public TclClass { 
00088 public:
00089     BayFullTcpClass() : TclClass("Agent/TCP/BayFullTcp") {}
00090     TclObject* create(int, const char*const*) { 
00091         return (new BayFullTcpAgent());
00092     }
00093 } class_bayfull;
00094 
00095 static class TahoeBayFullTcpClass : public TclClass { 
00096 public:
00097     TahoeBayFullTcpClass() : TclClass("Agent/TCP/BayFullTcp/Tahoe") {}
00098   TclObject* create(int, const char*const*) { 
00099     // tcl lib code
00100     // sets reno_fastrecov_ to false
00101     //return (new BayFullTcpAgent());
00102     fprintf(stderr,"Tahoe, NewReno or Sack flavors are NOT available for BayTCP!! Use BayFullTcp only, which actually implements Reno.\n");
00103 
00104     exit(1);
00105     }
00106 } class_tahoe_bayfull;
00107 
00108 static class NewRenoBayFullTcpClass : public TclClass { 
00109 public:
00110     NewRenoBayFullTcpClass() : TclClass("Agent/TCP/BayFullTcp/Newreno") {}
00111     TclObject* create(int, const char*const*) { 
00112       // tcl lib code
00113       // sets deflate_on_pack_ to false
00114       //return (new BayFullTcpAgent());
00115       fprintf(stderr,"Tahoe, NewReno or Sack flavors are NOT available for BayFullTCP!! Use BayFullTcp only, which actually implements Reno.\n");
00116       exit(1);
00117     }
00118 } class_newreno_bayfull;
00119 
00120 static class SackBayFullTcpClass : public TclClass { 
00121 public:
00122     SackBayFullTcpClass() : TclClass("Agent/TCP/BayFullTcp/Sack") {}
00123     TclObject* create(int, const char*const*) { 
00124       //return (new BayFullTcpAgent());
00125       fprintf(stderr,"Tahoe, NewReno or Sack flavors are NOT available for BayFullTCP!! Use BayFullTcp only, which actually implements Reno.\n");
00126       exit(1);
00127     }
00128 } class_sack_bayfull;
00129 
00130 /*
00131  * Tcl bound variables:
00132  *  segsperack: for delayed ACKs, how many to wait before ACKing
00133  *  segsize: segment size to use when sending
00134  */
00135 BayFullTcpAgent::BayFullTcpAgent() : flags_(0),
00136     state_(TCPS_CLOSED), rq_(rcv_nxt_), last_ack_sent_(0), app_(0),
00137     delack_timer_(this)
00138 {
00139     bind("segsperack_", &segs_per_ack_);
00140     bind("segsize_", &maxseg_);
00141     bind("tcprexmtthresh_", &tcprexmtthresh_);
00142     bind("iss_", &iss_);
00143     bind_bool("nodelay_", &nodelay_);
00144     bind_bool("data_on_syn_",&data_on_syn_);
00145     bind_bool("dupseg_fix_", &dupseg_fix_);
00146     bind_bool("dupack_reset_", &dupack_reset_);
00147     bind("interval_", &delack_interval_);
00148 }
00149 
00150 void
00151 BayFullTcpAgent::delay_bind_init_all()
00152 {
00153     TcpAgent::delay_bind_init_all();
00154         reset();
00155 }
00156 
00157 int
00158 BayFullTcpAgent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer)
00159 {
00160         return TcpAgent::delay_bind_dispatch(varName, localName, tracer);
00161 }
00162 
00163 /*
00164  * reset to starting point, don't set state_ here,
00165  * because our starting point might be LISTEN rather
00166  * than CLOSED if we're a passive opener
00167  */
00168 void
00169 BayFullTcpAgent::reset()
00170 {
00171     TcpAgent::reset();
00172     highest_ack_ = 0;
00173     last_ack_sent_ = 0;
00174     rcv_nxt_ = 0;       //kmn
00175     flags_ = 0;
00176     t_seqno_ = iss_;
00177     close_on_empty_ = 0;    //added 7/30/97 by kmn
00178     switch_spa_thresh_ = 0;
00179     first_data_ = 0;        //don't open cwnd too early
00180 }
00181 
00182 void
00183 BayFullTcpAgent::reinit()
00184 {
00185     cancel_rtx_timeout();
00186     rtt_init();
00187     cwnd_ = wnd_init_;
00188     last_ack_ = highest_ack_ = 0;
00189     ssthresh_ = int(wnd_);
00190     awnd_ = wnd_init_ / 2.0;
00191     recover_ = 0;
00192     recover_cause_ = 0;
00193 
00194     last_ack_sent_ = 0;
00195     rcv_nxt_ = 0;       //kmn
00196     flags_ = 0;
00197     t_seqno_ = maxseq_ = iss_;
00198     switch_spa_thresh_ = 0;
00199     /*
00200     for(int i =0; i < NTIMER; i++)  {
00201         cancel(i);
00202     }
00203     */
00204     rq_.clear();
00205     first_data_ = 0;        //don't open cwnd too early
00206 }
00207 
00208 /*
00209  * headersize:
00210  *  how big is an IP+TCP header in bytes
00211  *  (for now, is the basic size, but may changes
00212  *   in the future w/options; fix for sack)
00213  */
00214 int
00215 BayFullTcpAgent::headersize()
00216 {
00217     return (TCPIP_BASE_PKTSIZE);
00218 }
00219 
00220 /*
00221  * cancel any pending timers
00222  * free up the reassembly queue if there's anything there
00223  */
00224 BayFullTcpAgent::~BayFullTcpAgent()
00225 {
00226   /*
00227    * not required any more
00228     register i;
00229     for (i = 0; i < NTIMER; i++)
00230         if (pending_[i])
00231             cancel(i);
00232   */
00233     rq_.clear();
00234 }
00235 
00236 /*
00237  * the 'advance' interface to the regular tcp is in packet
00238  * units.  Here we scale this to bytes for full tcp.
00239  *
00240  * 'advance' is normally called by an "application" (i.e. data source)
00241  * to signal that there is something to send
00242  *
00243  * 'curseq_' is the last byte number provided by the application
00244  */
00245 void
00246 BayFullTcpAgent::advance(int np)
00247 {
00248     // XXX hack:
00249     //  because np is in packets and a data source
00250     //  may pass a *huge* number as a way to tell us
00251     //  to go forever, just look for the huge number
00252     //  and if it's there, pre-divide it
00253     if (np >= 0x10000000)
00254         np /= maxseg_;
00255 
00256     curseq_ += (np * maxseg_);
00257 
00258     //
00259     // state-specific operations:
00260     //  if CLOSED, do an active open/connect
00261     //  if ESTABLISHED, just try to send more
00262     //  if above ESTABLISHED, we are closing, so don't allow
00263     //  if anything else (establishing), do nothing here
00264     //
00265     if (state_ > TCPS_ESTABLISHED) {
00266         fprintf(stderr,
00267          "%f: BayFullTcpAgent::advance(%s): cannot advance while in state %d\n",
00268          now(), name(), state_);
00269         return;
00270     } else if (state_ == TCPS_CLOSED)   {
00271         connect();      // initiate new connection
00272     } else if (state_ == TCPS_ESTABLISHED)
00273         send_much(0, REASON_NORMAL, 0);
00274     return;
00275 }
00276 /*
00277  * added 7/30/97 by kmn to allow to pass bytes and set close_on_empty_
00278  */
00279 int
00280 BayFullTcpAgent::advance(int n, int close_flag)
00281 {
00282     close_on_empty_ = close_flag;
00283 
00284     //
00285     // state-specific operations:
00286     //  if CLOSED, do an active open/connect
00287     //  if ESTABLISHED, just try to send more
00288     //  if above ESTABLISHED, we are closing, so don't allow
00289     //  if anything else (establishing), do nothing here
00290     //
00291     if (state_ > TCPS_ESTABLISHED) {
00292         return 0;   //try again later, please
00293     } else if (state_ == TCPS_CLOSED)   {
00294         curseq_ = iss_ + n;
00295         reinit();
00296         connect();      // initiate new connection
00297     }
00298     else if (state_ == TCPS_ESTABLISHED)
00299         curseq_ += n;   
00300     else
00301         return 0;
00302     return 1;
00303 }
00304 /*
00305  * flags that are completely dependent on the tcp state
00306  * (in real TCP, see tcp_fsm.h, the "tcp_outflags" array)
00307  */
00308 int BayFullTcpAgent::outflags()
00309 {
00310     int flags = 0;
00311     if ((state_ != TCPS_LISTEN) && (state_ != TCPS_SYN_SENT))
00312         flags |= TH_ACK;
00313 
00314     if ((state_ == TCPS_SYN_SENT) || (state_ == TCPS_SYN_RECEIVED))
00315         flags |= TH_SYN;
00316 
00317     if ((state_ == TCPS_FIN_WAIT_1) || (state_ == TCPS_LAST_ACK))
00318         flags |= TH_FIN;
00319 
00320     return (flags);
00321 }
00322 
00323 void BayFullTcpAgent::sendpacket(int seqno, int ackno, int pflags, int datalen,
00324                   int reason)
00325 {
00326     Packet* p = allocpkt();
00327     hdr_tcp *tcph = hdr_tcp::access(p);
00328     hdr_cmn *th = hdr_cmn::access(p);
00329     tcph->seqno() = seqno;
00330     tcph->ackno() = ackno;
00331     tcph->flags() = pflags;
00332     tcph->hlen() = headersize();
00333     tcph->ts() = now();
00334     /* Open issue:  should tcph->reason map to pkt->flags_ as in ns-1?? */
00335     tcph->reason() |= reason;
00336     th->size() = datalen + headersize();
00337     if (datalen <= 0)
00338         ++nackpack_;
00339     else {
00340         ++ndatapack_;
00341         ndatabytes_ += datalen;
00342     }
00343     if (reason == REASON_TIMEOUT || reason == REASON_DUPACK) {
00344         ++nrexmitpack_;
00345         nrexmitbytes_ += datalen;
00346     }
00347     send(p, 0);
00348 }
00349 
00350 /*
00351  * see if we should send a segment, and if so, send it
00352  * (may be ACK or data)
00353  *  'maxseq_' is called 'snd_max' in "real" TCP
00354  *  and is the largest seq number we've sent
00355  *
00356  * maxseg_, largest seq# we've sent (snd_max)
00357  * flags_, flags regarding our internal state (t_state)
00358  * pflags, a local used to build up the tcp header flags (flags)
00359  * curseq_, is the highest sequence number given to us by "application"
00360  * highest_ack_, the highest ACK we've seen for our data (snd_una)
00361  * seqno, the next seq# we're going to send (snd_nxt), this will
00362  *  update t_seqno_ (the last thing we sent)
00363  */
00364 void BayFullTcpAgent::output(int seqno, int reason)
00365 {
00366     int is_retransmit = (seqno < maxseq_);
00367     int idle = (highest_ack_ == maxseq_);
00368 
00369     //kmn - changing all this for clarity 8/7/97
00370     int buffered_bytes = (curseq_ + iss_) - seqno;
00371     int datalen = min(buffered_bytes, (highest_ack_ + (window() * maxseg_)) - seqno);
00372     int pflags = outflags();
00373     int emptying_buffer = 0;
00374 
00375     if((pflags & TH_SYN) || datalen <= 0)
00376         datalen = 0;
00377     else if(datalen > maxseg_)  {
00378         datalen = maxseg_;
00379     } else if(datalen == buffered_bytes)    {
00380         emptying_buffer = 1;
00381         pflags |= TH_PUSH;
00382         //usrclosed() causes nested calls to output()
00383         if(close_on_empty_) {
00384             pflags |= TH_FIN;
00385             state_ = TCPS_FIN_WAIT_1;
00386         }
00387     }
00388 
00389     //end of kmn changes
00390 
00391     /* turn off FIN if there's really more to send */
00392     if (datalen > 0 && !emptying_buffer)
00393         pflags &= ~TH_FIN;
00394 
00395     /* sender SWS avoidance (Nagle) */
00396 
00397     if (datalen > 0) {
00398         // if full-sized segment, ok
00399         if (datalen == maxseg_)
00400             goto send;
00401         // if Nagle disabled and buffer clearing, ok
00402         if ((idle || nodelay_)  && emptying_buffer)
00403             goto send;
00404         // if a retransmission
00405         if (is_retransmit)
00406             goto send;
00407         // if big "enough", ok...
00408         //  (this is not a likely case, and would
00409         //  only happen for tiny windows)
00410         if (datalen >= ((wnd_ * maxseg_) / 2.0))
00411             goto send;
00412     }
00413 
00414     if (need_send())
00415         goto send;
00416 
00417     /*
00418      * send now if a SYN or special flag "TF_ACKNOW" is set.
00419      * TF_ACKNOW can be set during connection establishment and
00420      * to generate acks for out-of-order data
00421      * kmn 8/28 need to send if there's a push
00422      */
00423     if ((flags_ & TF_ACKNOW) || (pflags & (TH_SYN|TH_FIN|TH_PUSH)))
00424         goto send;
00425 
00426     return;     // no reason to send now
00427 
00428 send:
00429     //these changed by vj and kmn
00430     if (pflags & TH_FIN) {
00431         if (flags_ & TF_SENTFIN) {
00432             // don't allow seqno to advance past fin
00433             // (the ack generated by a discarded duplicate
00434             // may attempt to do this)
00435             if (seqno >= maxseq_)
00436                 --seqno;
00437         } else {
00438             flags_ |= TF_SENTFIN;
00439             ++t_seqno_;
00440         }
00441     }
00442 
00443     if((pflags & TH_SYN))   {
00444         if ((flags_ & TF_SENTSYN) == 0) {
00445             flags_ |= TF_SENTSYN;
00446             ++t_seqno_;
00447         }
00448     }
00449 
00450     /*
00451      * fill in packet fields.  Agent::allocpkt()
00452      * has already filled most of the network layer
00453      * fields for us.   So fill in tcp hdr and adjust
00454      * the packet size.
00455      */
00456     sendpacket(seqno, rcv_nxt_, pflags, datalen, reason);
00457     last_ack_sent_ = rcv_nxt_;
00458     flags_ &= ~(TF_ACKNOW|TF_DELACK);
00459 
00460     t_seqno_ += datalen;        // update snd_nxt (t_seqno_)
00461     if (t_seqno_ > maxseq_) {
00462         maxseq_ = t_seqno_;     // largest seq# we've sent
00463         /*
00464          * Time this transmission if not a retransmission and
00465          * not currently timing anything.
00466          */
00467         if (rtt_active_ == FALSE) {
00468             rtt_active_ = TRUE; // set timer
00469             rtt_seq_ = seqno;   // timed seq #
00470         }
00471     }
00472     /*
00473      * Set retransmit timer if not currently set,
00474      * and not doing an ack or a keep-alive probe.
00475      * Initial value for retransmit timer is smoothed
00476      * round-trip time + 2 * round-trip time variance.
00477      * Future values are rtt + 4 * rttvar.
00478      */
00479     if (!(rtx_timer_.status() == TIMER_PENDING) && (t_seqno_ > highest_ack_)) {
00480         set_rtx_timer();  // no timer pending, schedule one
00481     }
00482 }
00483 
00484 /*
00485  * Try to send as much data as the window will allow.  The link layer will 
00486  * do the buffering; we ask the application layer for the size of the packets.
00487  */
00488 void BayFullTcpAgent::send_much(int force, int reason, int maxburst)
00489 {
00490 
00491     /*
00492      * highest_ack is essentially "snd_una" in real TCP
00493      *
00494      * loop while we are in-window (seqno <= (highest_ack + win))
00495      * and there is something to send (t_seqno_ < curseq_+iss_)
00496      */
00497     int win = window() * maxseg_;   // window() in pkts
00498     int npackets = 0;
00499     int topwin = curseq_ + iss_;
00500     if (topwin > highest_ack_ + win)
00501         topwin = highest_ack_ + win;
00502 
00503     if (!force && (delsnd_timer_.status() == TIMER_PENDING))
00504         return;
00505 
00506     while (force || (t_seqno_ < topwin)) {
00507         if (overhead_ != 0 && !(delsnd_timer_.status() == TIMER_PENDING)) {
00508             delsnd_timer_.resched(Random::uniform(overhead_));
00509             return;
00510         }
00511         output(t_seqno_, reason);   // updates seqno for us
00512         force = 0;
00513         if (outflags() & TH_SYN)
00514             break;
00515         if (maxburst && ++npackets >= maxburst)
00516             break;
00517     }
00518 }
00519 
00520 void BayFullTcpAgent::cancel_rtx_timeout()
00521 {
00522     if (rtx_timer_.status() == TIMER_PENDING) {
00523         rtx_timer_.cancel();
00524     }
00525 }
00526 
00527 /*
00528  * Process an ACK
00529  *  this version of the routine doesn't necessarily
00530  *  require the ack to be one which advances the ack number
00531  *
00532  * if this ACKs a rtt estimate
00533  *  indicate we are not timing
00534  *  reset the exponential timer backoff (gamma)
00535  * update rtt estimate
00536  * cancel retrans timer if everything is sent and ACK'd, else set it
00537  * advance the ack number if appropriate
00538  * update segment to send next if appropriate
00539  */
00540 void BayFullTcpAgent::newack(Packet* pkt)
00541 {
00542     hdr_tcp *tcph = hdr_tcp::access(pkt);
00543 
00544     register int ackno = tcph->ackno();
00545 
00546     // we were timing the segment and we
00547     // got an ACK for it
00548     if (rtt_active_ && ackno >= rtt_seq_) {
00549         /* got a rtt sample */
00550         rtt_active_ = FALSE;    // no longer timing
00551         t_backoff_ = 1;     // stop exp backoff
00552     }
00553 
00554     /* always with timestamp option */
00555     double tao = now() - tcph->ts();
00556     rtt_update(tao);
00557 
00558     if (ackno >= maxseq_)
00559         cancel_rtx_timeout();
00560     else {
00561         if (ackno > highest_ack_) {
00562             set_rtx_timer();
00563         }
00564     }
00565 
00566     // advance the ack number if this is for new data
00567     if (ackno > highest_ack_)
00568         highest_ack_ = ackno;
00569     // set up the next packet to send
00570     if (t_seqno_ < highest_ack_)
00571         t_seqno_ = highest_ack_;    // thing to send next
00572 }
00573 
00574 /*
00575  * nuked this stuff, but left in method - kmn
00576  */
00577 int BayFullTcpAgent::predict_ok(Packet* )
00578 {
00579     return 0;
00580 }
00581 
00582 /*
00583  * fast_retransmit using the given seqno
00584  *  perform a fast retransmit
00585  *  kludge t_seqno_ (snd_nxt) so we do the
00586  *  retransmit then continue from where we were
00587  */
00588 
00589 void BayFullTcpAgent::fast_retransmit(int seq)
00590 {       
00591         rtt_backoff();                  // bug fix by van to avoid spurious rtx
00592     int onxt = t_seqno_;        // output() changes t_seqno_
00593     recover_ = maxseq_;     // keep a copy of highest sent
00594     recover_cause_ = REASON_DUPACK; // why we started this recovery period
00595     output(seq, REASON_DUPACK); // send one pkt
00596     t_seqno_ = onxt;
00597 }
00598 
00599 /*
00600  * real tcp determines if the remote
00601  * side should receive a window update/ACK from us, and often
00602  * results in sending an update every 2 segments, thereby
00603  * giving the familiar 2-packets-per-ack behavior of TCP.
00604  * Here, we don't advertise any windows, so we just see if
00605  * there's at least 'segs_per_ack_' pkts not yet acked
00606  */
00607  /* kmn - adding code to switch from one seg per ack to set value
00608   */
00609 
00610 int BayFullTcpAgent::need_send()
00611 {
00612     //first cut, send if anything to ack. Might need maxseg_
00613     if(flags_ & TF_ACKNOW)
00614         return 1;
00615     if(rcv_nxt_ < switch_spa_thresh_)
00616         return ((rcv_nxt_ - last_ack_sent_) >= 1);
00617     return ((rcv_nxt_ - last_ack_sent_) >= (segs_per_ack_ * maxseg_));
00618 }
00619 
00620 /*
00621  * deal with timers going off.
00622  * 2 types for now:
00623  *  retransmission timer (TCP_TIMER_RTX)
00624  *  delayed send (randomization) timer (TCP_TIMER_DELSND)
00625  *
00626  * real TCP initializes the RTO as 6 sec
00627  *              (  ^ 3sec, kmn )
00628  *  (A + 2D, where A=0, D=3), [Stevens p. 305]
00629  * and thereafter uses
00630  *  (A + 4D, where A and D are dynamic estimates)
00631  *
00632  * note that in the simulator t_srtt_, t_rttvar_ and t_rtt_
00633  * are all measured in 'tcp_tick_'-second units
00634  */
00635 void BayFullTcpAgent::timeout(int tno)
00636 {
00637     if(state_ == TCPS_CLOSED || state_ == TCPS_LISTEN)
00638         return;
00639         /* retransmit timer */
00640         if (tno == TCP_TIMER_RTX) {
00641         ++nrexmit_;
00642         recover_ = maxseq_;
00643         recover_cause_ = REASON_TIMEOUT;
00644                 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);
00645         //changed 6/10/00 to look at rtx problem -kmn
00646 /*      if(highest_ack_ == maxseq_)
00647             reset_rtx_timer(0,0);
00648         else
00649                     reset_rtx_timer(0,1);
00650 */
00651                 reset_rtx_timer(1);
00652         t_seqno_ = highest_ack_;
00653         dupacks_ = 0;
00654                 send_much(1, REASON_TIMEOUT);
00655         } else if (tno == TCP_TIMER_DELSND) {
00656                 /*
00657                  * delayed-send timer, with random overhead
00658                  * to avoid phase effects
00659                  */
00660                 send_much(1, PF_TIMEOUT);
00661         } else if (tno == TCP_TIMER_DELACK) {
00662         if (flags_ & TF_DELACK) {
00663             flags_ &= ~TF_DELACK;
00664             flags_ |= TF_ACKNOW;
00665             send_much(1, REASON_NORMAL, 0);
00666         }
00667         delack_timer_.resched(delack_interval_);
00668     } else {
00669         fprintf(stderr, "%f: (%s) UNKNOWN TIMEOUT %d\n",
00670             now(), name(), tno);
00671     }
00672 }
00673 
00674 /*
00675  * introduced kedar
00676  */
00677 
00678 void BayDelAckTimer::expire(Event *) {
00679     a_->timeout(TCP_TIMER_DELACK);
00680 }
00681 
00682 /*
00683  * main reception path - 
00684  * called from the agent that handles the data path below in its muxing mode
00685  * advance() is called when connection is established with size sent from
00686  * user/application agent
00687  */
00688 void BayFullTcpAgent::recv(Packet *pkt, Handler*)
00689 {
00690     hdr_tcp *tcph = hdr_tcp::access(pkt);
00691     hdr_cmn *th = hdr_cmn::access(pkt);
00692     hdr_ip *iph = hdr_ip::access(pkt);
00693     int needoutput = 0;
00694     int ourfinisacked = 0;
00695     int todrop = 0;
00696     int dupseg = FALSE;
00697 
00698 #ifdef notdef
00699     if (trace_)
00700         plot();
00701 #endif
00702 
00703     //
00704     // if no delayed-ACK timer is set, set one
00705     // they are set to fire every 'interval_' secs, starting
00706     // at time t0 = (0.0 + k * interval_) for some k such
00707     // that t0 > now
00708     //
00709     /*
00710     if (!pending_[TCP_TIMER_DELACK]) {
00711     */
00712     if (!(delack_timer_.status() == TIMER_PENDING)) {
00713         double now = Scheduler::instance().clock();
00714         int last = int(now / delack_interval_);
00715         delack_timer_.resched(delack_interval_ * (last + 1.0) - now);
00716 
00717     }
00718 
00719     int datalen = th->size() - tcph->hlen();
00720     int ackno = tcph->ackno();  // ack # from packet
00721 
00722     // nuked header prediction code that was here - kmn 8/5/97
00723 
00724     int tiflags = tcph->flags() ; // tcp flags from packet
00725 
00726     switch (state_) {
00727     case TCPS_LISTEN:   /* awaiting peer's SYN */
00728         if (tiflags & TH_ACK) {
00729             if (tiflags & TH_FIN) {
00730                 sendpacket(tcph->ackno(), tcph->seqno()+1,
00731                        TH_ACK, 0, REASON_NORMAL);
00732                 goto drop;
00733             }
00734             // ACK shouldn't be on here
00735     // kmn - this can be from previous connection if reusing
00736     //      fprintf(stderr,
00737     //          "%f: BayFullTcpAgent::recv(%s): got ACK(%d) while in LISTEN\n",
00738     //          now(), name(), ackno);
00739             goto drop;
00740         }
00741         if ((tiflags & TH_SYN) == 0) {
00742             // we're looking for a SYN in return
00743             fprintf(stderr,
00744                 "%f: BayFullTcpAgent::recv(%s): got a non-SYN while in LISTEN\n",
00745                 now(), name());
00746             goto drop;
00747         }
00748         flags_ |= TF_ACKNOW;
00749         state_ = TCPS_SYN_RECEIVED;
00750         rcv_nxt_ = tcph->seqno() + 1;   //kmn
00751         t_seqno_ = iss_;
00752         //kmn - switch from one to set segs per ack
00753         switch_spa_thresh_ = rcv_nxt_ + (16 * 1024);
00754         goto step6;
00755     case TCPS_SYN_SENT: /* we sent SYN, expecting SYN+ACK */
00756         if ((tiflags & TH_ACK) && (ackno > maxseq_)) {
00757             // not an ACK for our SYN, discard
00758 //          fprintf(stderr,
00759 //              "%f: BayFullTcpAgent::recv(%s): bad ACK (%d) for our SYN(%d)\n",
00760 //                  now(), name(), int(ackno), int(maxseq_));
00761             goto drop;
00762         }
00763         if ((tiflags & TH_SYN) == 0) {
00764             // we're looking for a SYN in return
00765             fprintf(stderr,
00766                 "%f: BayFullTcpAgent::recv(%s): no SYN for our SYN(%d)\n",
00767                     now(), name(), int(maxseq_));
00768             goto drop;
00769         }
00770         rcv_nxt_ = tcph->seqno()+1; // initial expected seq#
00771         //kmn - switch from one to set segs per ack
00772         switch_spa_thresh_ = rcv_nxt_ + (16 * 1024);
00773         cancel_rtx_timeout();   // cancel timer on our 1st SYN
00774         flags_ |= TF_ACKNOW;    // ACK peer's SYN
00775         if (tiflags & TH_ACK) {
00776             // got SYN+ACK (what we're expecting)
00777             // set up to ACK peer's SYN+ACK
00778             newack(pkt);
00779             state_ = TCPS_ESTABLISHED;
00780         } else {
00781             // simultaneous active opens
00782             state_ = TCPS_SYN_RECEIVED;
00783         }
00784         goto step6;
00785     }
00786 
00787     // check for redundant data at head/tail of segment
00788     //  note that the 4.4bsd [Net/3] code has
00789     //  a bug here which can cause us to ignore the
00790     //  perfectly good ACKs on duplicate segments.  The
00791     //  fix is described in (Stevens, Vol2, p. 959-960).
00792     //  This code is based on that correction.
00793     //
00794     // In addition, it has a modification so that duplicate segments
00795     // with dup acks don't trigger a fast retransmit when dupseg_fix_
00796     // is enabled.
00797     //
00798     todrop = rcv_nxt_ - tcph->seqno();  // how much overlap?
00799     if (todrop > 0) {
00800         // segment is something we've seen (perhaps partially)
00801         if (tiflags & TH_SYN) {
00802             t_seqno_ = highest_ack_;
00803             if ((tiflags & TH_ACK) == 0)
00804                 goto dropafterack;
00805             tiflags &= ~TH_SYN;
00806         }
00807         if (todrop > datalen ||
00808             (todrop == datalen && ((tiflags & TH_FIN) == 0))) {
00809             /*
00810              * Any valid FIN must be to the left of the window.
00811              * At this point the FIN must be a duplicate or out
00812              * of sequence; drop it.
00813              */
00814             tiflags &= ~TH_FIN;
00815 
00816             /*
00817              * Send an ACK to resynchronize and drop any data.
00818              * But keep on processing for RST or ACK.
00819              */
00820             flags_ |= TF_ACKNOW;
00821             todrop = datalen;
00822             dupseg = TRUE;
00823         }
00824         tcph->seqno() += todrop;
00825         datalen -= todrop;
00826     }
00827 
00828     if (tiflags & TH_SYN) {
00829         fprintf(stderr,
00830             "%f: %d.%d>%d.%d BayFullTcpAgent::recv(%s) received unexpected SYN (state:%d)\n",
00831                 now(),
00832             iph->saddr(), iph->sport(),
00833             iph->daddr(), iph->dport(),
00834                 name(), state_);
00835         goto drop;
00836     }
00837 
00838     if ((tiflags & (TH_SYN|TH_ACK)) == 0) {
00839         fprintf(stderr, "%f: %d.%d>%d.%d BayFullTcpAgent::recv(%s) got packet lacking ACK (seq %d)\n",
00840             now(),
00841             iph->saddr(), iph->sport(),
00842             iph->daddr(), iph->dport(),
00843             name(), tcph->seqno());
00844         goto drop;
00845     }
00846 
00847     /*
00848      * ACK processing
00849      */
00850 
00851     switch (state_) {
00852     case TCPS_SYN_RECEIVED: /* got ACK for our SYN+ACK */
00853         if (ackno < highest_ack_ || ackno > maxseq_) {
00854             // not in useful range
00855             goto drop;
00856         }
00857         state_ = TCPS_ESTABLISHED;
00858         /* fall into ... */
00859 
00860         /*
00861          * In ESTABLISHED state: drop duplicate ACKs; ACK out of range
00862          * ACKs.  If the ack is in the range
00863          *      tp->snd_una < ti->ti_ack <= tp->snd_max
00864          * then advance tp->snd_una to ti->ti_ack and drop
00865          * data from the retransmission queue.
00866      *
00867      * note that states CLOSE_WAIT and TIME_WAIT aren't used
00868      * in the simulator
00869          */
00870 
00871         case TCPS_ESTABLISHED:
00872         case TCPS_FIN_WAIT_1:
00873         case TCPS_FIN_WAIT_2:
00874         case TCPS_CLOSING:
00875         case TCPS_LAST_ACK:
00876 
00877         // look for dup ACKs (dup ack numbers, no data)
00878         //
00879         // do fast retransmit/recovery if at/past thresh
00880         if (ackno <= highest_ack_) {
00881             // an ACK which doesn't advance highest_ack_
00882             if (datalen == 0 && (!dupseg_fix_ || !dupseg)) {
00883                                 /*
00884                                  * If we have outstanding data
00885                                  * this is a completely
00886                                  * duplicate ack,
00887                                  * the ack is the biggest we've
00888                                  * seen and we've seen exactly our rexmt
00889                                  * threshhold of them, assume a packet
00890                                  * has been dropped and retransmit it.
00891                                  *
00892                                  * We know we're losing at the current
00893                                  * window size so do congestion avoidance.
00894                                  *
00895                                  * Dup acks mean that packets have left the
00896                                  * network (they're now cached at the receiver)
00897                                  * so bump cwnd by the amount in the receiver
00898                                  * to keep a constant cwnd packets in the
00899                                  * network.
00900                                  */
00901 
00902                     if (!(rtx_timer_.status() == TIMER_PENDING) ||
00903                     ackno != highest_ack_) {
00904                     // not timed, or re-ordered ACK
00905                     dupacks_ = 0;
00906                 } else if (bug_fix_ &&
00907                        highest_ack_ == recover_ &&
00908                        recover_cause_ == REASON_TIMEOUT) {
00909                     // doing timeout recovery not fastrxmit
00910                     dupacks_ = 0;
00911                 } else if (++dupacks_ == tcprexmtthresh_) {
00912                         slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
00913                         cancel_rtx_timeout();
00914                         rtt_active_ = FALSE;
00915                         fast_retransmit(ackno);
00916                         // we measure cwnd in packets,
00917                         // so don't scale by maxseg_
00918                         // as real TCP does
00919                         cwnd_ = ssthresh_ + dupacks_;
00920                         goto drop;
00921                 } else if (dupacks_ > tcprexmtthresh_) {
00922                     // we just measure cwnd in packets,
00923                     // so don't scale by maxset_ as real
00924                     // tcp does
00925                     cwnd_++;    // fast recovery
00926                     send_much(0, REASON_NORMAL, 0);
00927                     goto drop;
00928                 }
00929             } else {
00930                 // non-zero length segment
00931                 // (or window changed in real TCP).
00932                 if (dupack_reset_)
00933                     dupacks_ = 0;
00934             }
00935             break;  /* take us to "step6" */
00936         }
00937 
00938         /*
00939          * we've finished the fast retransmit/recovery period
00940          * (i.e. received an ACK which advances highest_ack_)
00941          */
00942 
00943                 /*
00944                  * If the congestion window was inflated to account
00945                  * for the other side's cached packets, retract it.
00946                  */
00947         if (dupacks_ >= tcprexmtthresh_ && cwnd_ > ssthresh_) {
00948             /*
00949              * make sure we send at most 2 packets due to this ack
00950              */
00951             cwnd_ = (maxseq_ - ackno + maxseg_ - 1)
00952                   / maxseg_ + 2;
00953         }
00954         dupacks_ = 0;
00955         if (ackno > maxseq_) {
00956             // ack more than we sent(!?)
00957             fprintf(stderr,
00958                 "%f: BayFullTcpAgent::recv(%s) too-big ACK (ack: %d, maxseq:%d)\n",
00959                 now(), name(), int(ackno), int(maxseq_));
00960             goto dropafterack;
00961         }
00962 
00963                 /*
00964                  * If we have a timestamp reply, update smoothed
00965                  * round trip time.  If no timestamp is present but
00966                  * transmit timer is running and timed sequence
00967                  * number was acked, update smoothed round trip time.
00968                  * Since we now have an rtt measurement, cancel the
00969                  * timer backoff (cf., Phil Karn's retransmit alg.).
00970                  * Recompute the initial retransmit timer.
00971          *
00972                  * If all outstanding data is acked, stop retransmit
00973                  * If there is more data to be acked, restart retransmit
00974                  * timer, using current (possibly backed-off) value.
00975                  */
00976         newack(pkt);
00977         if (state_ == TCPS_ESTABLISHED && ackno < maxseq_)
00978             needoutput = 1;
00979         /* kmn - 8/12/97: don't want to do this on first
00980          * data send, especially to compare IWs
00981          * So added test.
00982          */
00983         if(first_data_)
00984             opencwnd();
00985         // kmn - 8/15 added second test that is acking fin
00986         if ((state_ == TCPS_FIN_WAIT_1 || state_ == TCPS_FIN_WAIT_2
00987             || state_ == TCPS_LAST_ACK || state_ == TCPS_CLOSING)
00988             && ackno >= (curseq_ + iss_)) // && ackno == maxseq_)
00989             ourfinisacked = 1;
00990         else
00991             ourfinisacked = 0;
00992         // additional processing when we're in special states
00993 
00994         switch (state_) {
00995                 /*
00996                  * In FIN_WAIT_1 STATE in addition to the processing
00997                  * for the ESTABLISHED state if our FIN is now acknowledged
00998                  * then enter FIN_WAIT_2.
00999                  */
01000         case TCPS_FIN_WAIT_1:   /* doing active close */
01001             if (ourfinisacked)
01002                 state_ = TCPS_FIN_WAIT_2;
01003             break;
01004 
01005                 /*
01006                  * In CLOSING STATE in addition to the processing for
01007                  * the ESTABLISHED state if the ACK acknowledges our FIN
01008                  * then enter the TIME-WAIT state, otherwise ignore
01009                  * the segment.
01010                  */
01011         case TCPS_CLOSING:  /* simultaneous active close */;
01012             if (ourfinisacked)
01013                 state_ = TCPS_CLOSED;
01014             break;
01015                 /*
01016                  * In LAST_ACK, we may still be waiting for data to drain
01017                  * and/or to be acked, as well as for the ack of our FIN.
01018                  * If our FIN is now acknowledged,
01019                  * enter the closed state and return.
01020                  */
01021         case TCPS_LAST_ACK: /* passive close */
01022             if (ourfinisacked)  {
01023                 state_ = TCPS_CLOSED;   //kmn added 2 lines
01024                 /*
01025                 for(int i =0; i < NTIMER; i++)  {
01026                     cancel(i);
01027                 }
01028                 */
01029                 goto drop;
01030             } else {        //should be a FIN we've seen
01031                 fprintf(stderr,
01032                     "%f: %d.%d>%d.%d BayFullTcpAgent::recv(%s) received non-ACK (state:%d)\n",
01033                         now(),
01034                     iph->saddr(), iph->sport(),
01035                     iph->daddr(), iph->dport(),
01036                         name(), state_);
01037             }
01038 
01039         /* no case for TIME_WAIT in simulator */
01040         } // inner switch
01041     } // outer switch
01042 
01043 step6:
01044     /* real TCP handles window updates and URG data here */
01045 /* dodata: this label is in the "real" code.. here only for reference */
01046     /*
01047      * DATA processing
01048      * kmn - several changes here to talk to application agent
01049      */
01050 
01051     if (datalen > 0 || (tiflags & TH_FIN)) {
01052         first_data_ = 1;    //now seen first data
01053         // see the "TCP_REASS" macro for this code
01054         if (tcph->seqno() == rcv_nxt_ && rq_.empty()) {
01055             // got the in-order packet we were looking
01056             // for, nobody is in the reassembly queue,
01057             // so this is the common case...
01058             // note: in "real" TCP we must also be in
01059             // ESTABLISHED state to come here, because
01060             // data arriving before ESTABLISHED is
01061             // queued in the reassembly queue.  Since we
01062             // don't really have a process anyhow, just
01063             // accept the data here as-is (i.e. don't
01064             // require being in ESTABLISHED state)
01065             tiflags &= TH_FIN;
01066             if (tiflags) {
01067                 ++rcv_nxt_;
01068             }
01069             flags_ |= TF_DELACK;
01070             rcv_nxt_ += datalen;
01071             // give to "application" here
01072             // added 7/30/97 by kmn to call application with
01073             //  number of bytes since last push (if any)
01074             // the server is going to call advance before this
01075             //  completes, so changed advance to not call
01076             //  send_much if ESTABLISHED. curseq gets
01077             //  checked below.
01078             //
01079             if(datalen && app_ && (tcph->flags() & TH_PUSH)) {
01080                 //rcv_nxt_ - last_upcalled_bytes_;
01081                 app_->recv(pkt,this,DATA_PUSH);
01082                 //last_upcalled_bytes_ = rcv_nxt_;
01083             }
01084             needoutput = need_send();
01085         } else {
01086             // not the one we want next (or it
01087             // is but there's stuff on the reass queue);
01088             // do whatever we need to do for out-of-order
01089             // segments or hole-fills.  Also,
01090             // send an ACK to the other side right now.
01091             tiflags = rq_.add(pkt);
01092             if (tiflags & TH_PUSH) {
01093               if (app_ != NULL )
01094                 app_->recv(pkt,this,DATA_PUSH);
01095               needoutput = need_send();
01096             } else
01097                 flags_ |= TF_ACKNOW;
01098             //reset for losses
01099             switch_spa_thresh_ = rcv_nxt_ + (16 * 1024);
01100         }
01101     }
01102 
01103     /*
01104      * if FIN is received, ACK the FIN
01105      * (let user know if we could do so)
01106      */
01107 
01108     if (tiflags & TH_FIN) {
01109         flags_ |= TF_ACKNOW;
01110         rq_.clear();    // other side shutting down
01111         switch (state_) {
01112                 /*
01113                  * In SYN_RECEIVED and ESTABLISHED STATES
01114                  * enter the CLOSE_WAIT state.
01115          * (in the simulator, go to LAST_ACK)
01116          * (passive close)
01117                  */
01118                 case TCPS_SYN_RECEIVED:
01119                 case TCPS_ESTABLISHED:
01120                         state_ = TCPS_LAST_ACK;
01121                         break;
01122 
01123                 /*
01124                  * If still in FIN_WAIT_1 STATE FIN has not been acked so
01125                  * enter the CLOSING state.
01126          * (simultaneous close)
01127                  */
01128                 case TCPS_FIN_WAIT_1:
01129                         state_ = TCPS_CLOSING;
01130                         break;
01131                 /*
01132                  * In FIN_WAIT_2 state enter the TIME_WAIT state,
01133                  * starting the time-wait timer, turning off the other
01134                  * standard timers.
01135          * (in the simulator, just go to CLOSED)
01136          * (active close)
01137                  */
01138                 case TCPS_FIN_WAIT_2:
01139                         state_ = TCPS_CLOSED;
01140             cancel_rtx_timeout();
01141                         break;
01142         }
01143     }
01144 
01145     if (needoutput || (flags_ & TF_ACKNOW))
01146         send_much(1, REASON_NORMAL, 0);
01147     else if ((curseq_ + iss_) > highest_ack_)
01148         send_much(0, REASON_NORMAL, 0);
01149 
01150     /* kmn -  ugh, egregious hack. Can tell it's a server
01151      * so it goes to listen state. Do something
01152      * else if this becomes more stable
01153      */
01154         if(state_ == TCPS_CLOSED)   {
01155         if(close_on_empty_) {
01156             reinit();
01157             curseq_ = iss_;
01158             state_ = TCPS_LISTEN;
01159         } else {    /*"something else" - kmn 6/00 */
01160           if (app_ != NULL )
01161             app_->recv(pkt,this,CONNECTION_END);
01162         }
01163     }
01164     Packet::free(pkt);
01165     return;
01166 
01167 dropafterack:
01168     flags_ |= TF_ACKNOW;
01169     send_much(1, REASON_NORMAL, 0);
01170 drop:
01171     Packet::free(pkt);
01172     return;
01173 }
01174 
01175 void BayFullTcpAgent::reset_rtx_timer(int )
01176 {
01177     // cancel old timer,
01178     // set a new one
01179         rtt_backoff();      // double current timeout
01180         set_rtx_timer();    // set new timer
01181         rtt_active_ = FALSE;
01182 }
01183 
01184 
01185 /*
01186  * do an active open
01187  * (in real TCP, see tcp_usrreq, case PRU_CONNECT)
01188  */
01189 void BayFullTcpAgent::connect()
01190 {
01191     state_ = TCPS_SYN_SENT; // sending a SYN now
01192 
01193     if (!data_on_syn_) {
01194         // force no data in this segment
01195         int cur = curseq_;
01196         curseq_ = iss_;
01197         output(iss_, REASON_NORMAL);
01198         curseq_ = cur + 1;  //think I have to add in the syn here
01199         return;
01200     }
01201     output(iss_, REASON_NORMAL);
01202     return;
01203 }
01204 
01205 /*
01206  * be a passive opener
01207  * (in real TCP, see tcp_usrreq, case PRU_LISTEN)
01208  * (for simulation, make this peer's ptype ACKs)
01209  */
01210 void BayFullTcpAgent::listen()
01211 {
01212     state_ = TCPS_LISTEN;
01213     type_ = PT_TCP; //  changed by kmn 8/6/97
01214     //type_ = PT_ACK;   // instead of PT_TCP
01215 }
01216 
01217 /*
01218  * called when user/application performs 'close'
01219  */
01220 
01221 void BayFullTcpAgent::usrclosed()
01222 {
01223 
01224     switch (state_) {
01225     case TCPS_CLOSED:
01226     case TCPS_LISTEN:
01227     case TCPS_SYN_SENT:
01228         state_ = TCPS_CLOSED;
01229         break;
01230     case TCPS_SYN_RECEIVED:
01231     case TCPS_ESTABLISHED:
01232         state_ = TCPS_FIN_WAIT_1;
01233         send_much(1, REASON_NORMAL, 0);
01234         break;
01235     }
01236     return;
01237 }
01238 
01239 int BayFullTcpAgent::command(int argc, const char*const* argv)
01240 {
01241     // would like to have some "connect" primitive
01242     // here, but the problem is that we get called before
01243     // the simulation is running and we want to send a SYN.
01244     // Because no routing exists yet, this fails.
01245     // Instead, see code in advance() above.
01246     //
01247     // listen can happen any time because it just changes state_
01248     //
01249     // close is designed to happen at some point after the
01250     // simulation is running (using an ns 'at' command)
01251 
01252      Tcl& tcl = Tcl::instance();
01253 
01254     if (argc == 2) {
01255         if (strcmp(argv[1], "listen") == 0) {
01256             // just a state transition
01257             listen();
01258             return (TCL_OK);
01259         }
01260         if (strcmp(argv[1], "close") == 0) {
01261             usrclosed();
01262             return (TCL_OK);
01263         }
01264     }
01265     if (argc == 3) {
01266         if (strcmp(argv[1], "advance") == 0) {
01267             advance(atoi(argv[2]));
01268             return (TCL_OK);
01269         }
01270         //added 7/31/97 by kmn to work with apps, specifically www
01271         //  probably should use a special type of agent...
01272         if (strcmp(argv[1], "attach-application") == 0) { 
01273             app_ = (BayTcpAppAgent *)TclObject::lookup(argv[2]); 
01274             if (app_ == 0) {
01275                 tcl.resultf("no such agent %s", argv[2]);
01276                 return(TCL_ERROR);
01277             }
01278             return(TCL_OK);
01279         }
01280         //added by kmn 8/12/97
01281         if (strcmp(argv[1], "initial-window") == 0) { 
01282             wnd_init_ = atoi(argv[2]); 
01283             cwnd_ = wnd_init_;
01284             awnd_ = wnd_init_ /2.0;
01285             return(TCL_OK);
01286         }
01287 
01288     }
01289     return (TcpAgent::command(argc, argv));
01290 }
01291 /*
01292  * clear out reassembly queue
01293  */
01294 void BayReassemblyQueue::clear()
01295 {
01296     seginfo* p;
01297     seginfo* n;
01298     for (p = head_; p != NULL; p = n) {
01299         n = p->next_;
01300         delete p;
01301     }
01302     head_ = tail_ = NULL;
01303     return;
01304 }
01305 
01306 /*
01307  * add a packet to the reassembly queue..
01308  * will update BayFullTcpAgent::rcv_nxt_ by way of the
01309  * BayReassemblyQueue::rcv_nxt_ integer reference (an alias)
01310  */
01311 int BayReassemblyQueue::add(Packet* pkt)
01312 {
01313     hdr_tcp *tcph = hdr_tcp::access(pkt);
01314     hdr_cmn *th = hdr_cmn::access(pkt);
01315 
01316     int start = tcph->seqno();
01317     int end = start + th->size() - tcph->hlen();
01318     int tiflags = tcph->flags();
01319     seginfo *q, *p, *n;
01320 
01321     if (head_ == NULL) {
01322         // nobody there, just insert
01323         tail_ = head_ = new seginfo;
01324         head_->prev_ = NULL;
01325         head_->next_ = NULL;
01326         head_->startseq_ = start;
01327         head_->endseq_ = end;
01328         head_->flags_ = tiflags;
01329     } else {
01330         p = NULL;
01331         n = new seginfo;
01332         n->startseq_ = start;
01333         n->endseq_ = end;
01334         n->flags_ = tiflags;
01335         if (tail_->endseq_ <= start) {
01336             // common case of end of reass queue
01337             p = tail_;
01338             goto endfast;
01339         }
01340 
01341         q = head_;
01342         // look for the segment after this one
01343         while (q != NULL && (end > q->startseq_))
01344             q = q->next_;
01345         // set p to the segment before this one
01346         if (q == NULL)
01347             p = tail_;
01348         else
01349             p = q->prev_;
01350 
01351         if (p == NULL) {
01352             // insert at head
01353             n->next_ = head_;
01354             n->prev_ = NULL;
01355             head_->prev_ = n;
01356             head_ = n;
01357         } else {
01358 endfast:
01359             // insert in the middle or end
01360             n->next_ = p->next_;
01361             if (p->next_)
01362                 p->next_->prev_ = n;
01363             p->next_ = n;
01364             n->prev_ = p;
01365             if (p == tail_)
01366                 tail_ = n;
01367         }
01368     }
01369     //
01370     // look for a sequence of in-order segments and
01371     // set rcv_nxt if we can
01372     //
01373 
01374     if (head_->startseq_ > rcv_nxt_)
01375         return 0;   // still awaiting a hole-fill
01376 
01377     tiflags = 0;
01378     p = head_;
01379     while (p != NULL) {
01380         // update rcv_nxt_ to highest in-seq thing
01381         // and delete the entry from the reass queue
01382         rcv_nxt_ = p->endseq_;
01383         tiflags |= p->flags_;
01384         q = p;
01385         if (q->prev_)
01386             q->prev_->next_ = q->next_;
01387         else
01388             head_ = q->next_;
01389         if (q->next_)
01390             q->next_->prev_ = q->prev_;
01391         else
01392             tail_ = q->prev_;
01393         if (q->next_ && (q->endseq_ < q->next_->startseq_)) {
01394             delete q;
01395             break;      // only the in-seq stuff
01396         }
01397         p = p->next_;
01398         delete q;
01399     }
01400     return (tiflags);
01401 }

Generated on Tue Mar 6 16:47:52 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6