tfrc.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) 1999  International Computer Science Institute
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *  This product includes software developed by ACIRI, the AT&T 
00017  *      Center for Internet Research at ICSI (the International Computer
00018  *      Science Institute).
00019  * 4. Neither the name of ACIRI nor of ICSI may be used
00020  *    to endorse or promote products derived from this software without
00021  *    specific prior written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY ICSI AND CONTRIBUTORS ``AS IS'' AND
00024  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026  * ARE DISCLAIMED.  IN NO EVENT SHALL ICSI OR CONTRIBUTORS BE LIABLE
00027  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00028  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00029  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00032  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00033  * SUCH DAMAGE.
00034  */
00035 
00036 #include <stdlib.h>
00037 #include <sys/types.h>
00038 #include <math.h>
00039  
00040 #include "tfrc.h"
00041 #include "formula.h"
00042 #include "flags.h"
00043 
00044 int hdr_tfrc::offset_;
00045 int hdr_tfrc_ack::offset_;
00046 
00047 static class TFRCHeaderClass : public PacketHeaderClass {
00048 public:
00049     TFRCHeaderClass() : PacketHeaderClass("PacketHeader/TFRC",
00050                           sizeof(hdr_tfrc)) {
00051         bind_offset(&hdr_tfrc::offset_);
00052     }
00053 } class_tfrchdr;
00054 
00055 static class TFRC_ACKHeaderClass : public PacketHeaderClass {
00056 public:
00057     TFRC_ACKHeaderClass() : PacketHeaderClass("PacketHeader/TFRC_ACK",
00058                           sizeof(hdr_tfrc_ack)) {
00059         bind_offset(&hdr_tfrc_ack::offset_);
00060     }
00061 } class_tfrc_ackhdr;
00062 
00063 static class TfrcClass : public TclClass {
00064 public:
00065     TfrcClass() : TclClass("Agent/TFRC") {}
00066     TclObject* create(int, const char*const*) {
00067             return (new TfrcAgent());
00068     }
00069 } class_tfrc;
00070 
00071 
00072 TfrcAgent::TfrcAgent() : Agent(PT_TFRC), send_timer_(this), 
00073      NoFeedbacktimer_(this), rate_(0), oldrate_(0), maxrate_(0)
00074 {
00075     bind("packetSize_", &size_);
00076     bind("rate_", &rate_);
00077     bind("df_", &df_);
00078     bind("tcp_tick_", &tcp_tick_);
00079     bind("ndatapack_", &ndatapack_);
00080     bind("ndatabytes_", &ndatabytes_);
00081     bind("true_loss_rate_", &true_loss_rate_);
00082     bind("srtt_init_", &srtt_init_);
00083     bind("rttvar_init_", &rttvar_init_);
00084     bind("rtxcur_init_", &rtxcur_init_);
00085     bind("rttvar_exp_", &rttvar_exp_);
00086     bind("T_SRTT_BITS", &T_SRTT_BITS);
00087     bind("T_RTTVAR_BITS", &T_RTTVAR_BITS);
00088     bind("InitRate_", &InitRate_);
00089     bind("overhead_", &overhead_);
00090     bind("ssmult_", &ssmult_);
00091     bind("bval_", &bval_);
00092     bind("ca_", &ca_);
00093     bind_bool("printStatus_", &printStatus_);
00094     bind_bool("conservative_", &conservative_);
00095     bind_bool("ecn_", &ecn_);
00096     bind("minrto_", &minrto_);
00097     bind("maxHeavyRounds_", &maxHeavyRounds_);
00098     bind("SndrType_", &SndrType_); 
00099     bind("scmult_", &scmult_);
00100     bind_bool("oldCode_", &oldCode_);
00101     bind("rate_init_", &rate_init_);
00102     bind("rate_init_option_", &rate_init_option_);
00103     bind_bool("slow_increase_", &slow_increase_); 
00104     bind_bool("ss_changes_", &ss_changes_);
00105     bind_bool("voip_", &voip_);
00106     bind("voip_max_pkt_rate_", &voip_max_pkt_rate_);
00107     bind("fsize_", &fsize_);
00108     bind_bool("useHeaders_", &useHeaders_);
00109     bind("headersize_", &headersize_);
00110     seqno_ = -1;
00111     maxseq_ = 0;
00112     datalimited_ = 0;
00113     last_pkt_time_ = 0.0;
00114     bind("maxqueue_", &maxqueue_);
00115     maxqueue_ = MAXSEQ;
00116 }
00117 
00118 /*
00119  * Must convert bytes into packets. 
00120  * If nbytes == -1, this corresponds to infinite send.  We approximate
00121  * infinite by a very large number (MAXSEQ).
00122  * For simplicity, when bytes are converted to packets, fractional packets 
00123  * are always rounded up.  
00124  */
00125 void TfrcAgent::sendmsg(int nbytes, const char* /*flags*/)
00126 {
00127         if (nbytes == -1 && maxseq_ < MAXSEQ)
00128         advanceby(MAXSEQ - maxseq_);
00129         else if (size_ > 0) {
00130         int npkts = int(nbytes/size_);
00131         npkts += (nbytes%size_ ? 1 : 0);
00132         // maxqueue was added by Tom Phelan, to control the
00133         //   transmit queue from the application.
00134         if ((maxseq_ - seqno_) < maxqueue_) {
00135             advanceby(npkts);
00136         }
00137     }
00138 }
00139 
00140 
00141 void TfrcAgent::advanceby(int delta)
00142 {
00143     maxseq_ += delta;
00144     
00145     if (seqno_ == -1) {
00146         // if no packets hve been sent so far, call start. 
00147         start(); 
00148     } else if (datalimited_ && maxseq_ > seqno_) {
00149         // We were data-limited - send a packet now!
00150         // The old code always waited for a timer to expire!!
00151         datalimited_ = 0;
00152         if (!oldCode_) {
00153             sendpkt();
00154         }
00155     }
00156 } 
00157 
00158 int TfrcAgent::command(int argc, const char*const* argv)
00159 {
00160     if (argc==2) {
00161         // are we an infinite sender?
00162         if ( (strcmp(argv[1],"start")==0) && (SndrType_ == 0)) {
00163             start();
00164             return TCL_OK;
00165         }
00166         if (strcmp(argv[1],"stop")==0) {
00167             stop();
00168             return TCL_OK;
00169         }
00170     }
00171     if ((argc == 3) && (SndrType_ == 1)) {
00172         // or do we need an FTP type app? 
00173         if (strcmp(argv[1], "advance") == 0) {
00174                 int newseq = atoi(argv[2]);
00175         // THIS ISN"T USED.
00176         // newseq: new sequence
00177         // seqno_: next sequence to be sent
00178         // maxseq_: max seq_  produced by app so far.
00179                 if (newseq > maxseq_)
00180                     advanceby(newseq - maxseq_);
00181                 return (TCL_OK);
00182         }
00183         if (strcmp(argv[1], "advanceby") == 0) {
00184             advanceby(atoi(argv[2]));
00185             return (TCL_OK);
00186             }
00187     }
00188     return (Agent::command(argc, argv));
00189 }
00190 
00191 void TfrcAgent::start()
00192 {
00193     seqno_=0;               
00194     rate_ = InitRate_;
00195     delta_ = 0;
00196     oldrate_ = rate_;  
00197     rate_change_ = SLOW_START;
00198     UrgentFlag = 1;
00199     rtt_=0;  
00200     sqrtrtt_=1;
00201     rttcur_=1;
00202     tzero_ = 0;
00203     last_change_=0;
00204     maxrate_ = 0; 
00205     ss_maxrate_ = 0;
00206     ndatapack_=0;
00207     ndatabytes_ = 0;
00208     true_loss_rate_ = 0;
00209     active_ = 1; 
00210     round_id = 0;
00211     heavyrounds_ = 0;
00212     t_srtt_ = int(srtt_init_/tcp_tick_) << T_SRTT_BITS;
00213     t_rttvar_ = int(rttvar_init_/tcp_tick_) << T_RTTVAR_BITS;
00214     t_rtxcur_ = rtxcur_init_;
00215     rcvrate = 0 ;
00216 
00217     first_pkt_rcvd = 0 ;
00218     // send the first packet
00219     sendpkt();
00220     // ... at initial rate
00221     send_timer_.resched(size_/rate_);
00222     // ... and start timer so we can cut rate 
00223     // in half if we do not get feedback
00224     NoFeedbacktimer_.resched(2*size_/rate_); 
00225 }
00226 
00227 void TfrcAgent::stop()
00228 {
00229     active_ = 0;
00230     send_timer_.force_cancel();
00231 }
00232 
00233 void TfrcAgent::nextpkt()
00234 {
00235     double next = -1;
00236     double xrate = -1; 
00237 
00238     if (SndrType_ == 0) {
00239         sendpkt();
00240     }
00241     else {
00242         if (maxseq_ > seqno_) {
00243             sendpkt();
00244         } else
00245             datalimited_ = 1;
00246     }
00247     
00248     // If slow_increase_ is set, then during slow start, we increase rate
00249     // slowly - by amount delta per packet 
00250     if (slow_increase_ && (!ss_changes_ || round_id > 2) 
00251         && (rate_change_ == SLOW_START) 
00252                && (oldrate_+SMALLFLOAT< rate_)) {
00253         oldrate_ = oldrate_ + delta_;
00254         xrate = oldrate_;
00255     } else {
00256         if (ca_) 
00257             xrate = rate_ * sqrtrtt_/sqrt(rttcur_);
00258         else
00259             xrate = rate_;
00260     }
00261     if (xrate > SMALLFLOAT) {
00262         next = size_/xrate;
00263         if (voip_) {
00264                 double min_interval = 1.0/voip_max_pkt_rate_;
00265                 if (next < min_interval)
00266                 next = min_interval;
00267         }
00268         //
00269         // randomize between next*(1 +/- woverhead_) 
00270         //
00271         next = next*(2*overhead_*Random::uniform()-overhead_+1);
00272         if (next > SMALLFLOAT)
00273             send_timer_.resched(next);
00274     }
00275 }
00276 
00277 void TfrcAgent::update_rtt (double tao, double now) 
00278 {
00279     /* the TCP update */
00280     t_rtt_ = int((now-tao) /tcp_tick_ + 0.5);
00281     if (t_rtt_==0) t_rtt_=1;
00282     if (t_srtt_ != 0) {
00283         register short rtt_delta;
00284         rtt_delta = t_rtt_ - (t_srtt_ >> T_SRTT_BITS);    
00285         if ((t_srtt_ += rtt_delta) <= 0)    
00286             t_srtt_ = 1;
00287         if (rtt_delta < 0)
00288             rtt_delta = -rtt_delta;
00289         rtt_delta -= (t_rttvar_ >> T_RTTVAR_BITS);
00290         if ((t_rttvar_ += rtt_delta) <= 0)  
00291             t_rttvar_ = 1;
00292     } else {
00293         t_srtt_ = t_rtt_ << T_SRTT_BITS;        
00294         t_rttvar_ = t_rtt_ << (T_RTTVAR_BITS-1);    
00295     }
00296     t_rtxcur_ = (((t_rttvar_ << (rttvar_exp_ + (T_SRTT_BITS - T_RTTVAR_BITS))) + t_srtt_)  >> T_SRTT_BITS ) * tcp_tick_;
00297     tzero_=t_rtxcur_;
00298     if (tzero_ < minrto_) 
00299         tzero_ = minrto_;
00300 
00301     /* fine grained RTT estimate for use in the equation */
00302     if (rtt_ > 0) {
00303         rtt_ = df_*rtt_ + ((1-df_)*(now - tao));
00304         sqrtrtt_ = df_*sqrtrtt_ + ((1-df_)*sqrt(now - tao));
00305     } else {
00306         rtt_ = now - tao;
00307         sqrtrtt_ = sqrt(now - tao);
00308     }
00309     rttcur_ = now - tao;
00310 }
00311 
00312 /*
00313  * Receive a status report from the receiver.
00314  */
00315 void TfrcAgent::recv(Packet *pkt, Handler *)
00316 {
00317     double now = Scheduler::instance().clock();
00318     hdr_tfrc_ack *nck = hdr_tfrc_ack::access(pkt);
00319     //double ts = nck->timestamp_echo;
00320     double ts = nck->timestamp_echo + nck->timestamp_offset;
00321     double rate_since_last_report = nck->rate_since_last_report;
00322     // double NumFeedback_ = nck->NumFeedback_;
00323     double flost = nck->flost; 
00324     int losses = nck->losses;
00325     true_loss_rate_ = nck->true_loss;
00326 
00327     round_id ++ ;
00328     UrgentFlag = 0;
00329 
00330     if (rate_since_last_report > 0) {
00331         /* compute the max rate for slow-start as two times rcv rate */ 
00332         ss_maxrate_ = 2*rate_since_last_report*size_;
00333         if (conservative_) { 
00334             if (losses >= 1) {
00335                 /* there was a loss in the most recent RTT */
00336                 if (debug_) printf("time: %5.2f losses: %d rate %5.2f\n", 
00337                   now, losses, rate_since_last_report);
00338                 maxrate_ = rate_since_last_report*size_;
00339             } else { 
00340                 /* there was no loss in the most recent RTT */
00341                 maxrate_ = scmult_*rate_since_last_report*size_;
00342             }
00343             if (debug_) printf("time: %5.2f losses: %d rate %5.2f maxrate: %5.2f\n", now, losses, rate_since_last_report, maxrate_);
00344         } else 
00345             maxrate_ = 2*rate_since_last_report*size_;
00346     } else {
00347         ss_maxrate_ = 0;
00348         maxrate_ = 0; 
00349     }
00350 
00351         
00352     /* update the round trip time */
00353     update_rtt (ts, now);
00354 
00355     /* .. and estimate of fair rate */
00356     if (voip_ != 1) {
00357         // From RFC 3714:
00358         // The voip flow gets to send at the same rate as
00359         //  a TCP flow with 1460-byte packets.
00360         fsize_ = size_;
00361     }
00362     rcvrate = p_to_b(flost, rtt_, tzero_, fsize_, bval_);
00363     // rcvrate is in bytes per second, based on fairness with a    
00364     // TCP connection with the same packet size size_.        
00365     if (voip_) {
00366         // Subtract the bandwidth used by headers.
00367         double temp = rcvrate*(size_/(1.0*headersize_+size_));
00368         rcvrate = temp;
00369     }
00370 
00371     /* if we get no more feedback for some time, cut rate in half */
00372     double t = 2*rtt_ ; 
00373     if (t < 2*size_/rate_) 
00374         t = 2*size_/rate_ ; 
00375     NoFeedbacktimer_.resched(t);
00376     
00377     /* if we are in slow start and we just saw a loss */
00378     /* then come out of slow start */
00379 
00380     if (first_pkt_rcvd == 0) {
00381         first_pkt_rcvd = 1 ; 
00382         slowstart();
00383         nextpkt();
00384     }
00385     else {
00386         if (rate_change_ == SLOW_START) {
00387             if (flost > 0) {
00388                 rate_change_ = OUT_OF_SLOW_START;
00389                 oldrate_ = rate_ = rcvrate;
00390             }
00391             else {
00392                 slowstart();
00393                 nextpkt();
00394             }
00395         }
00396         else {
00397             if (rcvrate>rate_) 
00398                 increase_rate(flost);
00399             else 
00400                 decrease_rate ();       
00401         }
00402     }
00403     if (printStatus_) {
00404         printf("time: %5.2f rate: %5.2f\n", now, rate_);
00405         double packetrate = rate_ * rtt_ / size_;
00406         printf("time: %5.2f packetrate: %5.2f\n", now, packetrate);
00407     }
00408     Packet::free(pkt);
00409 }
00410 
00411 /*
00412  * Used in setting the initial rate.
00413  * This is from TcpAgent::initial_wnd().
00414  */
00415 double TfrcAgent::initial_rate()
00416 {
00417         if (rate_init_option_ == 1) {
00418         // init_option = 1: static initial rate of rate_init_
00419                 return (rate_init_);
00420         }
00421         else if (rate_init_option_ == 2) {
00422                 // do initial rate according to RFC 3390.
00423                 if (size_ <= 1095) {
00424                         return (4.0);
00425                 } else if (size_ < 2190) {
00426                         return (3.0);
00427                 } else {
00428                         return (2.0);
00429                 }
00430         }
00431         // XXX what should we return here???
00432         fprintf(stderr, "Wrong number of rate_init_option_ %d\n",
00433                 rate_init_option_);
00434         abort();
00435         return (2.0); // XXX make msvc happy.
00436 }
00437 
00438 
00439 // ss_maxrate_ = 2*rate_since_last_report*size_;
00440 // rate_: the rate set from the last pass through slowstart()
00441 // oldrate_: the rate the time before that.
00442 void TfrcAgent::slowstart () 
00443 {
00444     double now = Scheduler::instance().clock(); 
00445 
00446     if (round_id <= 1) {
00447         /* This is the first report, so */
00448         /*   change rate to initial rate.*/
00449         oldrate_ = rate_;
00450         rate_ =  initial_rate()*size_/rtt_;
00451         /* Compute delta so that if slow_increase_ is set to true, */
00452         /*  rate increases slowly to new value. */
00453         delta_ = (rate_ - oldrate_)/(rate_*rtt_/size_);
00454         last_change_ = now;
00455     } else if (!ss_changes_ && rate_+SMALLFLOAT< size_/rtt_) {
00456         oldrate_ = rate_;
00457         rate_ = size_/rtt_;
00458         delta_ = (rate_ - oldrate_)/(rate_*rtt_/size_);
00459         last_change_ = now;
00460     } else if (ss_maxrate_ > 0) {
00461         /* Compute delta, so that if slow_increase_ is set,   */
00462         /*  the rate increases slowly to its new value.       */
00463         if (ssmult_*rate_ < ss_maxrate_ && now - last_change_ > rtt_) {
00464             /* Multiply the rate by ssmult_.                 */
00465             if (ss_changes_) oldrate_ = rate_;
00466             rate_ = ssmult_*rate_; 
00467             delta_ = (rate_ - oldrate_)/(rate_*rtt_/size_);
00468             last_change_=now;
00469         } else if (oldrate_ > ss_maxrate_) {
00470             // Time to reduce the sending rate,
00471             //   to emulate ack-clocking.
00472             rate_ = oldrate_ = 0.5*ss_maxrate_;
00473             delta_ = 0; 
00474             last_change_ = now;
00475         } else if ((!ss_changes_ || round_id > 2) 
00476             && rate_ > ss_maxrate_) {
00477             // if round_id is 2, then ss_maxrate_ doesn't
00478             //   reflect the slow-start sending rate yet.
00479             if (ss_changes_) oldrate_ = rate_;
00480             rate_ = ss_maxrate_; 
00481             delta_ = (rate_ - oldrate_)/ (rate_*rtt_/size_);
00482             last_change_ = now; 
00483         } else {
00484             // rate < ss_maxrate < ssmult_*rate_
00485             if (now - last_change_ > rtt_) {
00486                 if (ss_changes_) oldrate_ = rate_;
00487                 rate_ = ss_maxrate_;
00488                 delta_ = (rate_ - oldrate_)/ (rate_*rtt_/size_);
00489                 last_change_=now;
00490             }
00491         }
00492     } else {
00493         // If we get here, ss_maxrate <= 0, so the receive rate is 0.
00494         // We should go back to a very small sending rate!!!
00495         // Changed by Sally on 10/20/2004.
00496         if (ss_changes_) oldrate_ = rate_;
00497         if (ss_changes_) rate_ = size_/rtt_; else rate_ = ssmult_*rate_;
00498         delta_ = (rate_ - oldrate_)/(rate_*rtt_/size_);
00499         last_change_=now;
00500     }
00501     
00502 }
00503 
00504 void TfrcAgent::increase_rate (double p)
00505 {               
00506         double now = Scheduler::instance().clock();
00507 
00508     double mult = (now-last_change_)/rtt_ ;
00509     if (mult > 2) mult = 2 ;
00510 
00511     rate_ = rate_ + (size_/rtt_)*mult ;
00512     double maximumrate = (maxrate_>size_/rtt_)?maxrate_:size_/rtt_ ;
00513     maximumrate = (maximumrate>rcvrate)?rcvrate:maximumrate;
00514     rate_ = (rate_ > maximumrate)?maximumrate:rate_ ;
00515     
00516         rate_change_ = CONG_AVOID;  
00517         last_change_ = now;
00518     heavyrounds_ = 0;
00519 }       
00520 
00521 void TfrcAgent::decrease_rate () 
00522 {
00523     double now = Scheduler::instance().clock(); 
00524     rate_ = rcvrate;
00525     double maximumrate = (maxrate_>size_/rtt_)?maxrate_:size_/rtt_ ;
00526 
00527     // Allow sending rate to be greater than maximumrate
00528     //   (which is by default twice the receiving rate)
00529     //   for at most maxHeavyRounds_ rounds.
00530     if (rate_ > maximumrate)
00531         heavyrounds_++;
00532     else
00533         heavyrounds_ = 0;
00534     if (heavyrounds_ > maxHeavyRounds_) {
00535         rate_ = (rate_ > maximumrate)?maximumrate:rate_ ;
00536     }
00537 
00538     rate_change_ = RATE_DECREASE;
00539     last_change_ = now;
00540 }
00541 
00542 void TfrcAgent::sendpkt()
00543 {
00544     if (active_) {
00545         double now = Scheduler::instance().clock(); 
00546         Packet* p = allocpkt();
00547         hdr_tfrc *tfrch = hdr_tfrc::access(p);
00548         hdr_flags* hf = hdr_flags::access(p);
00549         if (ecn_) {
00550             hf->ect() = 1;  // ECN-capable transport
00551         }
00552         tfrch->seqno=seqno_++;
00553         tfrch->timestamp=Scheduler::instance().clock();
00554         tfrch->rtt=rtt_;
00555         tfrch->tzero=tzero_;
00556         tfrch->rate=rate_;
00557         tfrch->psize=size_;
00558         tfrch->fsize=fsize_;
00559         tfrch->UrgentFlag=UrgentFlag;
00560         tfrch->round_id=round_id;
00561         ndatapack_++;
00562         ndatabytes_ += size_;
00563         if (useHeaders_ == true) {
00564             hdr_cmn::access(p)->size() += headersize_;
00565         }
00566         last_pkt_time_ = now;
00567         send(p, 0);
00568     }
00569 }
00570 
00571 void TfrcAgent::reduce_rate_on_no_feedback()
00572 {
00573     rate_change_ = RATE_DECREASE; 
00574     if (oldCode_ || !datalimited_ || rate_ > 4.0 * size_/rtt_ ) {
00575         // if we are not datalimited,
00576         //   or the current rate is greater than four pkts per RTT
00577         rate_*=0.5;
00578     }
00579     UrgentFlag = 1;
00580     round_id ++ ;
00581     double t = 2*rtt_ ; 
00582     if (t < 2*size_/rate_) 
00583         t = 2*size_/rate_ ; 
00584     NoFeedbacktimer_.resched(t);
00585     nextpkt();
00586 }
00587 
00588 void TfrcSendTimer::expire(Event *) {
00589     a_->nextpkt();
00590 }
00591 
00592 void TfrcNoFeedbackTimer::expire(Event *) {
00593     a_->reduce_rate_on_no_feedback ();
00594     // TODO: if the first (SYN) packet was dropped, then don't use
00595     //   the larger initial rates from RFC 3390:
00596         // if (highest_ack_ == -1 && wnd_init_option_ == 2)
00597     //     wnd_init_option_ = 1;
00598 
00599 }

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