chost.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:13k
- /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
- /*
- * Copyright (c) 1997 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the Daedalus Research
- * Group at the University of California Berkeley.
- * 4. Neither the name of the University nor of the Research Group may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Header: /cvsroot/nsnam/ns-2/tcp/chost.cc,v 1.13 2000/09/01 03:04:05 haoboy Exp $
- */
- /*
- * Functions invoked by TcpSessionAgent
- */
- #include "nilist.h"
- #include "chost.h"
- #include "tcp-int.h"
- #include "random.h"
- CorresHost::CorresHost() : slink(), TcpFsAgent(),
- lastackTS_(0), dontAdjustOwnd_(0), dontIncrCwnd_(0), rexmtSegCount_(0),
- connWithPktBeforeFS_(NULL)
- {
- nActive_ = nTimeout_ = nFastRec_ = 0;
- ownd_ = 0;
- owndCorrection_ = 0;
- closecwTS_ = 0;
- connIter_ = new Islist_iter<IntTcpAgent> (conns_);
- rtt_seg_ = NULL;
- }
- /*
- * Open up the congestion window.
- */
- void
- CorresHost::opencwnd(int /*size*/, IntTcpAgent *sender)
- {
- if (cwnd_ < ssthresh_) {
- /* slow-start (exponential) */
- cwnd_ += 1;
- } else {
- /* linear */
- //double f;
- if (!proxyopt_) {
- switch (wnd_option_) {
- case 0:
- if ((count_ = count_ + winInc_) >= cwnd_) {
- count_ = 0;
- cwnd_ += winInc_;
- }
- break;
- case 1:
- /* This is the standard algorithm. */
- cwnd_ += winInc_ / cwnd_;
- break;
- default:
- #ifdef notdef
- /*XXX*/
- error("illegal window option %d", wnd_option_);
- #endif
- abort();
- }
- } else { // proxy
- switch (wnd_option_) {
- case 0:
- case 1:
- if (sender->highest_ack_ >= sender->wndIncSeqno_) {
- cwnd_ += winInc_;
- sender->wndIncSeqno_ = 0;
- }
- break;
- default:
- #ifdef notdef
- /*XXX*/
- error("illegal window option %d", wnd_option_);
- #endif
- abort();
- }
- }
- }
- // if maxcwnd_ is set (nonzero), make it the cwnd limit
- if (maxcwnd_ && (int(cwnd_) > maxcwnd_))
- cwnd_ = maxcwnd_;
-
- return;
- }
- void
- CorresHost::closecwnd(int how, double ts, IntTcpAgent *sender)
- {
- if (proxyopt_) {
- if (!sender || ts > sender->closecwTS_)
- closecwnd(how, sender);
- }
- else {
- if (ts > closecwTS_)
- closecwnd(how, sender);
- }
- }
- void
- CorresHost::closecwnd(int how, IntTcpAgent *sender)
- {
- int sender_ownd = 0;
- if (sender)
- sender_ownd = sender->maxseq_ - sender->highest_ack_;
- closecwTS_ = Scheduler::instance().clock();
- if (proxyopt_) {
- if (sender)
- sender->closecwTS_ = closecwTS_;
- how += 10;
- }
- switch (how) {
- case 0:
- case 10:
- /* timeouts */
- /*
- * XXX we use cwnd_ instead of ownd_ here, which may not be
- * appropriate if the sender does not fully utilize the
- * available congestion window (ownd_ < cwnd_).
- */
- ssthresh_ = int(cwnd_ * winMult_);
- cwnd_ = int(wndInit_);
- break;
-
- case 1:
- /* Reno dup acks, or after a recent congestion indication. */
- /*
- * XXX we use cwnd_ instead of ownd_ here, which may not be
- * appropriate if the sender does not fully utilize the
- * available congestion window (ownd_ < cwnd_).
- */
- cwnd_ *= winMult_;
- ssthresh_ = int(cwnd_);
- if (ssthresh_ < 2)
- ssthresh_ = 2;
- break;
- case 11:
- /* Reno dup acks, or after a recent congestion indication. */
- /* XXX fix this -- don't make it dependent on ownd */
- cwnd_ = ownd_ - sender_ownd*(1-winMult_);
- ssthresh_ = int(cwnd_);
- if (ssthresh_ < 2)
- ssthresh_ = 2;
- break;
- case 3:
- case 13:
- /* idle time >= t_rtxcur_ */
- cwnd_ = wndInit_;
- break;
-
- default:
- abort();
- }
- fcnt_ = 0.;
- count_ = 0;
- if (sender)
- sender->count_ = 0;
- }
- Segment*
- CorresHost::add_pkts(int /*size*/, int seqno, int sessionSeqno, int daddr, int dport,
- int sport, double ts, IntTcpAgent *sender)
- {
- class Segment *news;
- ownd_ += 1;
- news = new Segment;
- news->seqno_ = seqno;
- news->sessionSeqno_ = sessionSeqno;
- news->daddr_ = daddr;
- news->dport_ = dport;
- news->sport_ = sport;
- news->ts_ = ts;
- news->size_ = 1;
- news->dupacks_ = 0;
- news->later_acks_ = 0;
- news->thresh_dupacks_ = 0;
- news->partialack_ = 0;
- news->rxmitted_ = 0;
- news->sender_ = sender;
- seglist_.append(news);
- return news;
- }
- void
- CorresHost::adjust_ownd(int size)
- {
- if (double(owndCorrection_) < size)
- ownd_ -= min(double(ownd_), size - double(owndCorrection_));
- owndCorrection_ -= min(double(owndCorrection_),size);
- if (double(ownd_) < -0.5 || double(owndCorrection_ < -0.5))
- printf("In adjust_ownd(): ownd_ = %g owndCorrection_ = %gn", double(ownd_), double(owndCorrection_));
- }
- int
- CorresHost::clean_segs(int /*size*/, Packet *pkt, IntTcpAgent *sender, int sessionSeqno, int amt_data_acked)
- {
- Segment *cur, *prev=NULL, *newseg;
- int i;
- //int rval = -1;
- /* remove all acked pkts from list */
- int latest_susp_loss = rmv_old_segs(pkt, sender, amt_data_acked);
- /*
- * XXX If no new data is acked and the last time we shrunk the window
- * covers the most recent suspected loss, update the estimate of the amount
- * of outstanding data.
- */
- if (amt_data_acked == 0 && latest_susp_loss <= recover_ &&
- !dontAdjustOwnd_ && last_cwnd_action_ != CWND_ACTION_TIMEOUT) {
- owndCorrection_ += min(double(ownd_),1);
- ownd_ -= min(double(ownd_),1);
- }
- /*
- * A pkt is a candidate for retransmission if it is the leftmost one in the
- * unacked window for the connection AND has at least numdupacks_
- * dupacks/later acks AND (at least one dupack OR a later packet also
- * with the threshold number of dup/later acks). A pkt is also a candidate
- * for immediate retransmission if it has partialack_ set, indicating that
- * a partial new ack has been received for it.
- */
- for (i=0; i < rexmtSegCount_; i++) {
- int remove_flag = 0;
- /*
- * curArray_ only contains segments that are the first oldest
- * unacked segments of their connection (i.e., they are at the left
- * edge of their window) and have either received a
- * partial ack and/or have received at least cur->numdupacks_
- * dupacks/later acks. Thus, segments in curArray_ have a high
- * probability (but not certain) of being eligible for
- * retransmission. Using curArray_ avoids having to scan
- * through all the segments.
- */
- cur = curArray_[i];
- prev = prevArray_[i];
- if (cur->partialack_ || cur->dupacks_ > 0 ||
- cur->sender_->num_thresh_dupack_segs_ > 1 ) {
- if (cur->thresh_dupacks_) {
- cur->thresh_dupacks_ = 0;
- cur->sender_->num_thresh_dupack_segs_--;
- }
- if (cur->sessionSeqno_ <= recover_ &&
- last_cwnd_action_ != CWND_ACTION_TIMEOUT /* XXX 2 */)
- dontAdjustOwnd_ = 1;
- if ((cur->sessionSeqno_ > recover_) ||
- (last_cwnd_action_ == CWND_ACTION_TIMEOUT /* XXX 2 */)
- || (proxyopt_ && cur->seqno_ > cur->sender_->recover_)
- || (proxyopt_ && cur->sender_->last_cwnd_action_ == CWND_ACTION_TIMEOUT /* XXX 2 */)) {
- /* new loss window */
- closecwnd(1, cur->ts_, cur->sender_);
- recover_ = sessionSeqno - 1;
- last_cwnd_action_ = CWND_ACTION_DUPACK /* XXX 1 */;
- cur->sender_->recover_ = cur->sender_->maxseq_;
- cur->sender_->last_cwnd_action_ =
- CWND_ACTION_DUPACK /* XXX 1 */;
- dontAdjustOwnd_ = 0;
- }
- if ((newseg = cur->sender_->rxmit_last(TCP_REASON_DUPACK,
- cur->seqno_, cur->sessionSeqno_, cur->ts_))) {
- newseg->rxmitted_ = 1;
- adjust_ownd(cur->size_);
- if (!dontAdjustOwnd_) {
- owndCorrection_ +=
- min(double(ownd_),cur->dupacks_);
- ownd_ -= min(double(ownd_),cur->dupacks_);
- }
- seglist_.remove(cur, prev);
- remove_flag = 1;
- delete cur;
- }
- /*
- * if segment just removed used to be the one just previous
- * to the next segment in the array, update prev for the
- * next segment
- */
- if (remove_flag && cur == prevArray_[i+1])
- prevArray_[i+1] = prev;
- }
- }
- rexmtSegCount_ = 0;
- return(0);
- }
-
- int
- CorresHost::rmv_old_segs(Packet *pkt, IntTcpAgent *sender, int amt_data_acked)
- {
- Islist_iter<Segment> seg_iter(seglist_);
- Segment *cur, *prev=0;
- int found = 0;
- int done = 0;
- int new_data_acked = 0;
- int partialack = 0;
- int latest_susp_loss = -1;
- hdr_tcp *tcph = hdr_tcp::access(pkt);
- if (tcph->ts_echo() > lastackTS_)
- lastackTS_ = tcph->ts_echo();
- while (((cur = seg_iter()) != NULL) &&
- (!done || tcph->ts_echo() > cur->ts_)) {
- int remove_flag = 0;
- /* ack for older pkt of another connection */
- if (sender != cur->sender_ && tcph->ts_echo() > cur->ts_) {
- if (!disableIntLossRecov_)
- cur->later_acks_++;
- latest_susp_loss =
- max(latest_susp_loss,cur->sessionSeqno_);
- dontIncrCwnd_ = 1;
- }
- /* ack for same connection */
- else if (sender == cur->sender_) {
- /* found packet acked */
- if (tcph->seqno() == cur->seqno_ &&
- tcph->ts_echo() == cur->ts_)
- found = 1;
- /* higher ack => clean up acked packets */
- if (tcph->seqno() >= cur->seqno_) {
- adjust_ownd(cur->size_);
- seglist_.remove(cur, prev);
- remove_flag = 1;
- new_data_acked += cur->size_;
- if (new_data_acked >= amt_data_acked)
- done = 1;
- if (prev == cur)
- prev = NULL;
- if (cur == rtt_seg_)
- rtt_seg_ = NULL;
- delete cur;
- if (seg_iter.get_cur() && prev)
- seg_iter.set_cur(prev);
- else if (seg_iter.get_cur())
- seg_iter.set_cur(seg_iter.get_last());
- }
- /* partial new ack => rexmt immediately */
- /* XXX should we check recover for session? */
- else if (amt_data_acked > 0 &&
- tcph->seqno() == cur->seqno_-1 &&
- cur->seqno_ <= sender->recover_ &&
- sender->last_cwnd_action_ == CWND_ACTION_DUPACK) {
- cur->partialack_ = 1;
- partialack = 1;
- latest_susp_loss =
- max(latest_susp_loss,cur->sessionSeqno_);
- if (new_data_acked >= amt_data_acked)
- done = 1;
- dontIncrCwnd_ = 1;
- }
- /*
- * If no new data has been acked AND this segment has
- * not been retransmitted before AND the ack indicates
- * that this is the next segment to be acked, then
- * increment dupack count.
- */
- else if (!amt_data_acked && !cur->rxmitted_ &&
- tcph->seqno() == cur->seqno_-1) {
- cur->dupacks_++;
- latest_susp_loss =
- max(latest_susp_loss,cur->sessionSeqno_);
- done = 1;
- dontIncrCwnd_ = 1;
- }
- }
- if (cur->dupacks_+cur->later_acks_ >= sender->numdupacks_ &&
- !cur->thresh_dupacks_) {
- cur->thresh_dupacks_ = 1;
- cur->sender_->num_thresh_dupack_segs_++;
- }
- if (amt_data_acked==0 && tcph->seqno()==cur->seqno_-1)
- done = 1;
- /* XXX we could check for rexmt candidates here if we ignore
- the num_thresh_dupack_segs_ check */
- if (!remove_flag &&
- cur->seqno_ == cur->sender_->highest_ack_ + 1 &&
- (cur->dupacks_ + cur->later_acks_ >= sender->numdupacks_ ||
- cur->partialack_)) {
- curArray_[rexmtSegCount_] = cur;
- prevArray_[rexmtSegCount_] = prev;
- rexmtSegCount_++;
- }
- if (!remove_flag)
- prev = cur;
- }
- /* partial ack => terminate fast start mode */
- if (partialack && fs_enable_ && fs_mode_) {
- timeout(TCP_TIMER_RESET);
- rexmtSegCount_ = 0;
- }
- return latest_susp_loss;
- }
-
- void
- CorresHost::add_agent(IntTcpAgent *agent, int /*size*/, double winMult,
- int winInc, int /*ssthresh*/)
- {
- if (nActive_ >= MAX_PARALLEL_CONN) {
- printf("In add_agent(): reached limit of number of parallel conn (%d); returningn", nActive_);
- return;
- }
- nActive_++;
- if ((!fixedIw_ && nActive_ > 1) || cwnd_ == 0)
- cwnd_ += 1; /* XXX should this be done? */
- wndInit_ = 1;
- winMult_ = winMult;
- winInc_ = winInc;
- /* ssthresh_ = ssthresh;*/
- conns_.append(agent);
- }
- int
- CorresHost::ok_to_snd(int /*size*/)
- {
- if (ownd_ <= -0.5)
- printf("In ok_to_snd(): ownd_ = %g owndCorrection_ = %gn", double(ownd_), double(owndCorrection_));
- return (cwnd_ >= ownd_+1);
- }