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

chost.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) 1997 Regents of the University of California.
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 the Daedalus Research
00017  *      Group at the University of California Berkeley.
00018  * 4. Neither the name of the University nor of the Research Group may be
00019  *    used to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  * 
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  *
00034  * $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/chost.cc,v 1.13 2000/09/01 03:04:05 haoboy Exp $
00035  */
00036 
00037 /*
00038  * Functions invoked by TcpSessionAgent
00039  */
00040 #include "nilist.h"
00041 #include "chost.h"
00042 #include "tcp-int.h"
00043 #include "random.h"
00044 
00045 CorresHost::CorresHost() : slink(), TcpFsAgent(),
00046         lastackTS_(0), dontAdjustOwnd_(0), dontIncrCwnd_(0), rexmtSegCount_(0),
00047         connWithPktBeforeFS_(NULL)
00048 {
00049         nActive_ = nTimeout_ = nFastRec_ = 0;
00050         ownd_ = 0;
00051         owndCorrection_ = 0;
00052         closecwTS_ = 0;
00053         connIter_ = new Islist_iter<IntTcpAgent> (conns_);
00054         rtt_seg_ = NULL;
00055 }
00056 
00057 
00058 /*
00059  * Open up the congestion window.
00060  */
00061 void 
00062 CorresHost::opencwnd(int /*size*/, IntTcpAgent *sender)
00063 {
00064         if (cwnd_ < ssthresh_) {
00065                 /* slow-start (exponential) */
00066                 cwnd_ += 1;
00067         } else {
00068                 /* linear */
00069                 //double f;
00070                 if (!proxyopt_) {
00071                         switch (wnd_option_) {
00072                         case 0:
00073                                 if ((count_ = count_ + winInc_) >= cwnd_) {
00074                                         count_ = 0;
00075                                         cwnd_ += winInc_;
00076                                 }
00077                                 break;
00078                         case 1:
00079                                 /* This is the standard algorithm. */
00080                                 cwnd_ += winInc_ / cwnd_;
00081                                 break;
00082                         default:
00083 #ifdef notdef
00084                                 /*XXX*/
00085                                 error("illegal window option %d", wnd_option_);
00086 #endif
00087                                 abort();
00088                         }
00089                 } else {        // proxy
00090                         switch (wnd_option_) {
00091                         case 0: 
00092                         case 1:
00093                                 if (sender->highest_ack_ >= sender->wndIncSeqno_) {
00094                                         cwnd_ += winInc_;
00095                                         sender->wndIncSeqno_ = 0;
00096                                 }
00097                                 break;
00098                         default:
00099 #ifdef notdef
00100                                 /*XXX*/
00101                                 error("illegal window option %d", wnd_option_);
00102 #endif
00103                                 abort();
00104                         }
00105                 }
00106         }
00107         // if maxcwnd_ is set (nonzero), make it the cwnd limit
00108         if (maxcwnd_ && (int(cwnd_) > maxcwnd_))
00109                 cwnd_ = maxcwnd_;
00110         
00111         return;
00112 }
00113 
00114 void 
00115 CorresHost::closecwnd(int how, double ts, IntTcpAgent *sender)
00116 {
00117         if (proxyopt_) {
00118                 if (!sender || ts > sender->closecwTS_)
00119                         closecwnd(how, sender);
00120         }
00121         else {
00122                 if (ts > closecwTS_)
00123                         closecwnd(how, sender);
00124         }
00125 }
00126 
00127 void 
00128 CorresHost::closecwnd(int how, IntTcpAgent *sender)
00129 {
00130         int sender_ownd = 0;
00131         if (sender)
00132                 sender_ownd = sender->maxseq_ - sender->highest_ack_;
00133         closecwTS_ = Scheduler::instance().clock();
00134         if (proxyopt_) {
00135                 if (sender)
00136                         sender->closecwTS_ = closecwTS_;
00137                 how += 10;
00138         }
00139         switch (how) {
00140         case 0:
00141         case 10:
00142                 /* timeouts */
00143 
00144                 /* 
00145                  * XXX we use cwnd_ instead of ownd_ here, which may not be
00146                  * appropriate if the sender does not fully utilize the
00147                  * available congestion window (ownd_ < cwnd_).
00148                  */
00149                 ssthresh_ = int(cwnd_ * winMult_);
00150                 cwnd_ = int(wndInit_);
00151                 break;
00152                 
00153         case 1:
00154                 /* Reno dup acks, or after a recent congestion indication. */
00155 
00156                 /* 
00157                  * XXX we use cwnd_ instead of ownd_ here, which may not be
00158                  * appropriate if the sender does not fully utilize the
00159                  * available congestion window (ownd_ < cwnd_).
00160                  */
00161                 cwnd_ *= winMult_;
00162                 ssthresh_ = int(cwnd_);
00163                 if (ssthresh_ < 2)
00164                         ssthresh_ = 2;
00165                 break;
00166 
00167         case 11:
00168                 /* Reno dup acks, or after a recent congestion indication. */
00169                 /* XXX fix this -- don't make it dependent on ownd */
00170                 cwnd_ = ownd_ - sender_ownd*(1-winMult_);
00171                 ssthresh_ = int(cwnd_);
00172                 if (ssthresh_ < 2)
00173                         ssthresh_ = 2;
00174                 break;
00175 
00176         case 3:
00177         case 13:
00178                 /* idle time >= t_rtxcur_ */
00179                 cwnd_ = wndInit_;
00180                 break;
00181                 
00182         default:
00183                 abort();
00184         }
00185         fcnt_ = 0.;
00186         count_ = 0;
00187         if (sender)
00188                 sender->count_ = 0;
00189 }
00190 
00191 Segment* 
00192 CorresHost::add_pkts(int /*size*/, int seqno, int sessionSeqno, int daddr, int dport, 
00193                      int sport, double ts, IntTcpAgent *sender)
00194 {
00195         class Segment *news;
00196 
00197         ownd_ += 1;
00198         news = new Segment;
00199         news->seqno_ = seqno;
00200         news->sessionSeqno_ = sessionSeqno;
00201         news->daddr_ = daddr;
00202         news->dport_ = dport;
00203         news->sport_ = sport;
00204         news->ts_ = ts;
00205         news->size_ = 1;
00206         news->dupacks_ = 0;
00207         news->later_acks_ = 0;
00208         news->thresh_dupacks_ = 0;
00209         news->partialack_ = 0;
00210         news->rxmitted_ = 0;
00211         news->sender_ = sender;
00212         seglist_.append(news);
00213         return news;
00214 }
00215 
00216 void
00217 CorresHost::adjust_ownd(int size) 
00218 {
00219         if (double(owndCorrection_) < size)
00220                 ownd_ -= min(double(ownd_), size - double(owndCorrection_));
00221         owndCorrection_ -= min(double(owndCorrection_),size);
00222         if (double(ownd_) < -0.5 || double(owndCorrection_ < -0.5))
00223                 printf("In adjust_ownd(): ownd_ = %g  owndCorrection_ = %g\n", double(ownd_), double(owndCorrection_));
00224 }
00225 
00226 int
00227 CorresHost::clean_segs(int /*size*/, Packet *pkt, IntTcpAgent *sender, int sessionSeqno, int amt_data_acked)
00228 { 
00229     Segment *cur, *prev=NULL, *newseg;
00230     int i;
00231     //int rval = -1;
00232 
00233     /* remove all acked pkts from list */
00234     int latest_susp_loss = rmv_old_segs(pkt, sender, amt_data_acked);
00235     /* 
00236      * XXX If no new data is acked and the last time we shrunk the window 
00237      * covers the most recent suspected loss, update the estimate of the amount
00238      * of outstanding data.
00239      */
00240     if (amt_data_acked == 0 && latest_susp_loss <= recover_ && 
00241         !dontAdjustOwnd_ && last_cwnd_action_ != CWND_ACTION_TIMEOUT) {
00242             owndCorrection_ += min(double(ownd_),1);
00243             ownd_ -= min(double(ownd_),1);
00244     }
00245     /*
00246      * A pkt is a candidate for retransmission if it is the leftmost one in the
00247      * unacked window for the connection AND has at least numdupacks_
00248      * dupacks/later acks AND (at least one dupack OR a later packet also
00249      * with the threshold number of dup/later acks). A pkt is also a candidate
00250      * for immediate retransmission if it has partialack_ set, indicating that
00251      * a partial new ack has been received for it.
00252      */
00253 
00254     for (i=0; i < rexmtSegCount_; i++) {
00255             int remove_flag = 0;
00256             /* 
00257              * curArray_ only contains segments that are the first oldest
00258              * unacked segments of their connection (i.e., they are at the left
00259              * edge of their window) and have either received a
00260              * partial ack and/or have received at least cur->numdupacks_
00261              * dupacks/later acks. Thus, segments in curArray_ have a high
00262              * probability (but not certain) of being eligible for 
00263              * retransmission. Using curArray_ avoids having to scan
00264              * through all the segments.
00265              */
00266             cur = curArray_[i];
00267             prev = prevArray_[i];
00268             if (cur->partialack_ || cur->dupacks_ > 0 || 
00269                 cur->sender_->num_thresh_dupack_segs_ > 1 ) {
00270                     if (cur->thresh_dupacks_) {
00271                             cur->thresh_dupacks_ = 0;
00272                             cur->sender_->num_thresh_dupack_segs_--;
00273                     }
00274                     if (cur->sessionSeqno_ <= recover_ && 
00275                         last_cwnd_action_ != CWND_ACTION_TIMEOUT /* XXX 2 */)
00276                             dontAdjustOwnd_ = 1;
00277                     if ((cur->sessionSeqno_ > recover_) || 
00278                         (last_cwnd_action_ == CWND_ACTION_TIMEOUT /* XXX 2 */)
00279                         || (proxyopt_ && cur->seqno_ > cur->sender_->recover_)
00280                         || (proxyopt_ && cur->sender_->last_cwnd_action_ == CWND_ACTION_TIMEOUT /* XXX 2 */)) { 
00281                             /* new loss window */
00282                             closecwnd(1, cur->ts_, cur->sender_);
00283                             recover_ = sessionSeqno - 1;
00284                             last_cwnd_action_ = CWND_ACTION_DUPACK /* XXX 1 */;
00285                             cur->sender_->recover_ = cur->sender_->maxseq_;
00286                             cur->sender_->last_cwnd_action_ = 
00287                                     CWND_ACTION_DUPACK /* XXX 1 */;
00288                             dontAdjustOwnd_ = 0;
00289                     }
00290                     if ((newseg = cur->sender_->rxmit_last(TCP_REASON_DUPACK, 
00291                            cur->seqno_, cur->sessionSeqno_, cur->ts_))) {
00292                             newseg->rxmitted_ = 1;
00293                             adjust_ownd(cur->size_);
00294                             if (!dontAdjustOwnd_) {
00295                                     owndCorrection_ += 
00296                                             min(double(ownd_),cur->dupacks_);
00297                                     ownd_ -= min(double(ownd_),cur->dupacks_);
00298                             }
00299                             seglist_.remove(cur, prev);
00300                             remove_flag = 1;
00301                             delete cur;
00302                     }
00303                     /* 
00304                      * if segment just removed used to be the one just previous
00305                      * to the next segment in the array, update prev for the
00306                      * next segment
00307                      */
00308                     if (remove_flag && cur == prevArray_[i+1])
00309                             prevArray_[i+1] = prev;
00310             }
00311     }
00312     rexmtSegCount_ = 0;
00313     return(0);
00314 }
00315                     
00316 
00317 int
00318 CorresHost::rmv_old_segs(Packet *pkt, IntTcpAgent *sender, int amt_data_acked)
00319 {
00320         Islist_iter<Segment> seg_iter(seglist_);
00321         Segment *cur, *prev=0;
00322         int found = 0;
00323         int done = 0;
00324         int new_data_acked = 0;
00325         int partialack = 0;
00326         int latest_susp_loss = -1;
00327         hdr_tcp *tcph = hdr_tcp::access(pkt);
00328 
00329         if (tcph->ts_echo() > lastackTS_)
00330                 lastackTS_ = tcph->ts_echo();
00331 
00332         while (((cur = seg_iter()) != NULL) &&
00333                (!done || tcph->ts_echo() > cur->ts_)) {
00334                 int remove_flag = 0;
00335                 /* ack for older pkt of another connection */
00336                 if (sender != cur->sender_ && tcph->ts_echo() > cur->ts_) { 
00337                         if (!disableIntLossRecov_)
00338                                 cur->later_acks_++;
00339                         latest_susp_loss = 
00340                                 max(latest_susp_loss,cur->sessionSeqno_);
00341                         dontIncrCwnd_ = 1;
00342                 } 
00343                 /* ack for same connection */
00344                 else if (sender == cur->sender_) {
00345                         /* found packet acked */
00346                         if (tcph->seqno() == cur->seqno_ && 
00347                             tcph->ts_echo() == cur->ts_) 
00348                                 found = 1;
00349                         /* higher ack => clean up acked packets */
00350                         if (tcph->seqno() >= cur->seqno_) {
00351                                 adjust_ownd(cur->size_);
00352                                 seglist_.remove(cur, prev);
00353                                 remove_flag = 1;
00354                                 new_data_acked += cur->size_;
00355                                 if (new_data_acked >= amt_data_acked)
00356                                         done = 1;
00357                                 if (prev == cur) 
00358                                         prev = NULL;
00359                                 if (cur == rtt_seg_)
00360                                         rtt_seg_ = NULL;
00361                                 delete cur;
00362                                 if (seg_iter.get_cur() && prev)
00363                                         seg_iter.set_cur(prev);
00364                                 else if (seg_iter.get_cur())
00365                                         seg_iter.set_cur(seg_iter.get_last());
00366                         } 
00367                         /* partial new ack => rexmt immediately */
00368                         /* XXX should we check recover for session? */
00369                         else if (amt_data_acked > 0 && 
00370                                  tcph->seqno() == cur->seqno_-1 &&
00371                                  cur->seqno_ <= sender->recover_ &&
00372                                  sender->last_cwnd_action_ == CWND_ACTION_DUPACK) {
00373                                 cur->partialack_ = 1;
00374                                 partialack = 1;
00375                                 latest_susp_loss = 
00376                                         max(latest_susp_loss,cur->sessionSeqno_);
00377                                 if (new_data_acked >= amt_data_acked)
00378                                         done = 1;
00379                                 dontIncrCwnd_ = 1;
00380                         }
00381                         /* 
00382                          * If no new data has been acked AND this segment has
00383                          * not been retransmitted before AND the ack indicates 
00384                          * that this is the next segment to be acked, then
00385                          * increment dupack count.
00386                          */
00387                         else if (!amt_data_acked && !cur->rxmitted_ &&
00388                                  tcph->seqno() == cur->seqno_-1) {
00389                                 cur->dupacks_++;
00390                                 latest_susp_loss = 
00391                                         max(latest_susp_loss,cur->sessionSeqno_);
00392                                 done = 1;
00393                                 dontIncrCwnd_ = 1;
00394                         } 
00395                 }
00396                 if (cur->dupacks_+cur->later_acks_ >= sender->numdupacks_ &&
00397                     !cur->thresh_dupacks_) {
00398                         cur->thresh_dupacks_ = 1;
00399                         cur->sender_->num_thresh_dupack_segs_++;
00400                 }
00401 
00402                 if (amt_data_acked==0 && tcph->seqno()==cur->seqno_-1)
00403                         done = 1;
00404                 /* XXX we could check for rexmt candidates here if we ignore 
00405                    the num_thresh_dupack_segs_ check */
00406                 if (!remove_flag &&
00407                     cur->seqno_ == cur->sender_->highest_ack_ + 1 &&
00408                     (cur->dupacks_ + cur->later_acks_ >= sender->numdupacks_ ||
00409                      cur->partialack_)) {
00410                         curArray_[rexmtSegCount_] = cur;
00411                         prevArray_[rexmtSegCount_] = prev;
00412                         rexmtSegCount_++;
00413                 }
00414                 if (!remove_flag)
00415                         prev = cur;
00416         }
00417         /* partial ack => terminate fast start mode */
00418         if (partialack && fs_enable_ && fs_mode_) {
00419                 timeout(TCP_TIMER_RESET);
00420                 rexmtSegCount_ = 0;
00421         }
00422         return latest_susp_loss;
00423 }
00424         
00425 void
00426 CorresHost::add_agent(IntTcpAgent *agent, int /*size*/, double winMult, 
00427                       int winInc, int /*ssthresh*/)
00428 {
00429         if (nActive_ >= MAX_PARALLEL_CONN) {
00430                 printf("In add_agent(): reached limit of number of parallel conn (%d); returning\n", nActive_);
00431                 return;
00432         }
00433         nActive_++;
00434         if ((!fixedIw_ && nActive_ > 1) || cwnd_ == 0)
00435                 cwnd_ += 1; /* XXX should this be done? */
00436         wndInit_ = 1;
00437         winMult_ = winMult;
00438         winInc_ = winInc;
00439 /*      ssthresh_ = ssthresh;*/
00440         conns_.append(agent);
00441 }
00442 
00443 int
00444 CorresHost::ok_to_snd(int /*size*/)
00445 {
00446         if (ownd_ <= -0.5)
00447                 printf("In ok_to_snd(): ownd_ = %g  owndCorrection_ = %g\n", double(ownd_), double(owndCorrection_));
00448         return (cwnd_ >= ownd_+1);
00449 }
00450 
00451 
00452 
00453 
00454 

Generated on Tue Apr 20 12:14:11 2004 for NS2.26SourcesOriginal by doxygen 1.3.3