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

tcp-int.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  * Contributed by the Daedalus Research Group, U.C.Berkeley
00035  * http://daedalus.cs.berkeley.edu
00036  *
00037  * $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/tcp-int.cc,v 1.15 2000/09/01 03:04:07 haoboy Exp $
00038  */
00039 
00040 
00041 /*
00042  * We separate TCP functionality into two parts: that having to do with 
00043  * providing a reliable, ordered byte-stream service, and that having to do with
00044  * congestion control and loss recovery. The former is done on a per-connection
00045  * basis and is implemented as part of IntTcpAgent ("integrated TCP"). The 
00046  * latter is done in an integrated fashion across multiple TCP connections, and
00047  * is implemented as part of TcpSessionAgent ("TCP session"). TcpSessionAgent is
00048  * derived from CorresHost ("correspondent host"), which keeps track of the 
00049  * state of all TCP (TCP/Int) connections to a host that it is corresponding 
00050  * with.
00051  *
00052  * The motivation for this separation of functionality is to make an ensemble of
00053  * connection more well-behaved than a set of independent TCP connections.
00054  * The packet loss rate is cut down and the chances of losses being recovered 
00055  * via data-driven techniques (rather than via timeouts) is improved. At the 
00056  * same time, we do not introduce any unnecessary coupling between the 
00057  * logically-independent byte-streams that the set of connections represents. 
00058  * This is in contrast to the coupling that is inherent in the multiplexing at 
00059  * the application layer of multiple byte-streams onto a single TCP connection.
00060  */
00061 
00062 #include <stdio.h>
00063 #include <stdlib.h>
00064 #include <sys/types.h>
00065 
00066 #include "packet.h"
00067 #include "ip.h"
00068 #include "tcp.h"
00069 #include "flags.h"
00070 #include "nilist.h"
00071 #include "tcp-int.h"
00072 #include "chost.h"
00073 #include "tcp-session.h"
00074 #include "random.h"
00075 
00076 Islist<TcpSessionAgent> TcpSessionAgent::sessionList_;
00077 
00078 static class IntTcpClass : public TclClass {
00079 public:
00080         IntTcpClass() : TclClass("Agent/TCP/Int") {}
00081         TclObject* create(int, const char*const*) {
00082                 return (new IntTcpAgent());
00083         }
00084 } class_tcp_int;
00085 
00086 IntTcpAgent::IntTcpAgent() : TcpAgent(), slink(), 
00087         session_(0), closecwTS_(0), lastTS_(-1), count_(0), 
00088         wt_(1), wndIncSeqno_(0), num_thresh_dupack_segs_(0)
00089 {
00090         bind("rightEdge_", &rightEdge_);
00091         bind("uniqTS_", &uniqTS_);
00092         bind("winInc_", &winInc_);
00093         bind("winMult_", &winMult_);
00094 }
00095 
00096 int
00097 IntTcpAgent::command(int argc, const char*const* argv)
00098 {
00099         Tcl& tcl = Tcl::instance();
00100 
00101         if (argc == 3) {
00102                 if (!strcmp(argv[1], "setwt")) {
00103                         if (!session_)
00104                                 createTcpSession();
00105                         session_->set_weight(this,atoi(argv[2]));
00106                         return (TCL_OK);
00107                 }
00108         }
00109         else if (argc == 2) {
00110                 if (!strcmp(argv[1], "session")) {
00111                         if (!session_)
00112                                 createTcpSession();
00113                         tcl.resultf("%s", session_->name());
00114                         return (TCL_OK);
00115                 }
00116         }
00117         return (TcpAgent::command(argc,argv));
00118 }
00119 
00120 /* 
00121  * Update the ack information and reset the timer. RTT update is done in 
00122  * TcpSessionAgent.
00123  */
00124 void
00125 IntTcpAgent::newack(Packet* pkt)
00126 {
00127         hdr_tcp *tcph = hdr_tcp::access(pkt);
00128         last_ack_ = tcph->seqno();
00129         highest_ack_ = last_ack_;
00130 
00131         if (t_seqno_ < last_ack_ + 1)
00132                 t_seqno_ = last_ack_ + 1;
00133         /* if the connection is done, call finish() */
00134         if ((highest_ack_ >= curseq_-1) && !closed_) {
00135                 closed_ = 1;
00136                 finish();
00137         }
00138 }
00139 
00140 void 
00141 IntTcpAgent::recv(Packet *pkt, Handler *)
00142 {
00143         hdr_tcp *tcph = hdr_tcp::access(pkt);
00144         int amt_data_acked = 0;
00145 
00146         if (tcph->seqno() > last_ack_) {
00147                 amt_data_acked = tcph->seqno() - last_ack_;
00148                 newack(pkt);
00149         } 
00150         session_->recv(this, pkt, amt_data_acked);
00151 }
00152 
00153 void
00154 IntTcpAgent::createTcpSession()
00155 {
00156         Tcl& tcl = Tcl::instance();
00157 
00158         tcl.evalf("%s set node_", name());
00159         tcl.evalf("%s createTcpSession %d", tcl.result(), daddr());
00160         Islist_iter<TcpSessionAgent> session_iter(TcpSessionAgent::sessionList_);
00161         TcpSessionAgent *cur;
00162 
00163         while ((cur = session_iter()) != NULL) {
00164                 if (cur->addr()/256 == addr() && cur->daddr() == daddr()) {
00165                         session_ = cur;
00166                         break;
00167                 }
00168         }
00169         if (!session_) {
00170                 printf("In IntTcpAgent::createTcpSession(): failed\n");
00171                 abort();
00172         }
00173         session_->add_agent(this, size_, winMult_, winInc_, ssthresh_);
00174 }
00175 
00176 void
00177 IntTcpAgent::output(int seqno, int reason)
00178 {
00179         Packet *pkt = allocpkt();
00180         hdr_tcp *tcph = hdr_tcp::access(pkt);
00181         tcph->seqno() = seqno;
00182         tcph->ts() = Scheduler::instance().clock();
00183         tcph->ts_echo() = ts_peer_;
00184         tcph->reason() = reason;
00185 
00186         session_->setflags(pkt);
00187         
00188         int bytes = hdr_cmn::access(pkt)->size();
00189 
00190         /* call helper function to fill in additional fields */
00191         output_helper(pkt);
00192 
00193         ++ndatapack_;
00194         ndatabytes_ += bytes;
00195         send(pkt, 0);
00196         if (seqno == curseq_ && seqno > maxseq_)
00197                 idle();  // Tell application I have sent everything so far
00198         if (seqno > maxseq_) {
00199                 maxseq_ = seqno;
00200         }
00201         else {
00202                 ++nrexmitpack_;
00203                 nrexmitbytes_ += bytes;
00204         }
00205         if (wndIncSeqno_ == 0)
00206                 wndIncSeqno_ = maxseq_;
00207 }
00208 
00209 
00210 /*
00211  * Unlike in other flavors of TCP, IntTcpAgent does not decide when to send 
00212  * packets and how many of them to send. That decision is made by 
00213  * TcpSessionAgent. So send_much() does little more than defer to 
00214  * TcpSessionAgent.
00215  */
00216 void
00217 IntTcpAgent::send_much(int force, int reason, int /*maxburst*/)
00218 {
00219         if (!session_)
00220                 createTcpSession();
00221         if (!force && delsnd_timer_.status() == TIMER_PENDING)
00222                 return;
00223         if (overhead_ && !force) {
00224                 delsnd_timer_.resched(Random::uniform(overhead_));
00225                 return;
00226         }
00227         session_->send_much(this, force,reason);
00228 }
00229 
00230 /*
00231  * Send one new packet.
00232  */
00233 void
00234 IntTcpAgent::send_one(int sessionSeqno)
00235 {
00236         int dst_addr = daddr();
00237         int dst_port = dport();
00238         int sport = port();
00239 
00240         if (!session_)
00241                 createTcpSession();
00242         /* 
00243          * XXX We assume that the session layer has already made sure that
00244          * we have data to send.
00245          */
00246         output(t_seqno_++); 
00247         session_->add_pkts(size_, t_seqno_ - 1, sessionSeqno,
00248                            dst_addr, dst_port, sport, lastTS_, this); 
00249 }
00250 
00251 
00252 /*
00253  * open up the congestion window
00254  */
00255 void 
00256 IntTcpAgent::opencwnd()
00257 {
00258         session_->opencwnd(size_, this);
00259 }
00260 
00261 /*
00262  * close down the congestion window
00263  */
00264 void 
00265 IntTcpAgent::closecwnd(int how)
00266 {   
00267         session_->closecwnd(how, this);
00268 }
00269 
00270 Segment *
00271 IntTcpAgent::rxmit_last(int reason, int seqno, int sessionSeqno, double /*ts*/)
00272 {
00273         session_->agent_rcov(this);
00274         /* 
00275          * XXX kludge -- IntTcpAgent is not supposed to deal with 
00276          * rtx timer 
00277          */
00278         session_->reset_rtx_timer(1,0); 
00279         output(seqno, reason);
00280         daddr_ = daddr();
00281         dport_ = dport();
00282         sport_ = port();
00283         return (session_->add_pkts(size_, seqno, sessionSeqno, daddr_, 
00284                                    dport_, sport_, lastTS_, this));
00285         return NULL;
00286 }
00287 unsigned long output_helper_count=0;
00288 double last_clock=0;
00289 void
00290 IntTcpAgent::output_helper(Packet *p)
00291 {
00292         double now = Scheduler::instance().clock();
00293         output_helper_count++;
00294         last_clock = now;
00295         hdr_tcp *tcph = hdr_tcp::access(p);
00296 
00297         /* This is to make sure that we get unique times for each xmission */
00298         while (uniqTS_ && now <= lastTS_) {
00299                 now += 0.000001; // something arbitrarily small
00300         }
00301 
00302         lastTS_ = now;
00303         tcph->ts() = now;
00304         /* if this is a fast start pkt and not a retransmission, mark it */
00305         if (session_->fs_pkt() && tcph->seqno() > maxseq_)
00306                 hdr_flags::access(p)->fs_ = 1;
00307         return;
00308 }
00309 
00310 int 
00311 IntTcpAgent::data_left_to_send() {
00312         return (curseq_ > t_seqno_);
00313 }

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