Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

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 Apr 20 12:14:34 2004 for NS2.26SourcesOriginal by doxygen 1.3.3