tcp-abs.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 
00003 /*
00004  * Copyright (C) 1999 by the University of Southern California
00005  * $Id: tcp-abs.cc,v 1.3 2005/08/25 18:58:12 johnh Exp $
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License,
00009  * version 2, as published by the Free Software Foundation.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License along
00017  * with this program; if not, write to the Free Software Foundation, Inc.,
00018  * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
00019  *
00020  *
00021  * The copyright of this module includes the following
00022  * linking-with-specific-other-licenses addition:
00023  *
00024  * In addition, as a special exception, the copyright holders of
00025  * this module give you permission to combine (via static or
00026  * dynamic linking) this module with free software programs or
00027  * libraries that are released under the GNU LGPL and with code
00028  * included in the standard release of ns-2 under the Apache 2.0
00029  * license or under otherwise-compatible licenses with advertising
00030  * requirements (or modified versions of such code, with unchanged
00031  * license).  You may copy and distribute such a system following the
00032  * terms of the GNU GPL for this module and the licenses of the
00033  * other code concerned, provided that you include the source code of
00034  * that other code when and as the GNU GPL requires distribution of
00035  * source code.
00036  *
00037  * Note that people who make modified versions of this module
00038  * are not obligated to grant this special exception for their
00039  * modified versions; it is their choice whether to do so.  The GNU
00040  * General Public License gives permission to release a modified
00041  * version without this exception; this exception also makes it
00042  * possible to release a modified version which carries forward this
00043  * exception.
00044  *
00045  */
00046 /* 
00047  * Contributed by Polly Huang (USC/ISI), http://www-scf.usc.edu/~bhuang
00048  * @(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/tcp-abs.cc,v 1.3 2005/08/25 18:58:12 johnh Exp $ (LBL)";
00049  */
00050 
00051 #include "ip.h"
00052 #include "tcp.h"
00053 #include "tcp-abs.h"
00054 
00055 //AbsTcp
00056 AbsTcpAgent::AbsTcpAgent() : Agent(PT_TCP), rtt_(0), current_(NULL),offset_(0), seqno_lb_(-1), connection_size_(0), timer_(this), rescheduled_(0)
00057 {
00058     size_ = 1000;
00059 }
00060 
00061 void AbsTcpAgent::timeout()
00062 {
00063     if (rescheduled_ == 0 && current_->transition_[offset_]!= current_->transition_[0]) {
00064         set_timer(2*rtt_);
00065         rescheduled_ = 1;
00066     } else {
00067         rescheduled_ = 0;
00068         seqno_lb_ += current_->batch_size_;
00069         if (current_->drop_[offset_] == NULL) {
00070             printf("Error: This fsm can't handle multi losses per connection\n");
00071             exit(0);
00072         }
00073         current_ = current_->drop_[offset_];
00074         send_batch();
00075     }
00076 }
00077 
00078 void AbsTcpAgent::sendmsg(int pktcnt)
00079 {
00080     connection_size_ = pktcnt;
00081     start();
00082 }
00083 
00084 void AbsTcpAgent::advanceby(int pktcnt)
00085 {
00086     connection_size_ = pktcnt;
00087     start();
00088 }
00089 
00090 void AbsTcpAgent::start()
00091 {
00092     //printf("starting fsm tcp, %d\n", connection_size_);
00093     send_batch();
00094 }
00095 
00096 void AbsTcpAgent::send_batch() 
00097 {
00098     int seqno = seqno_lb_;
00099     
00100     offset_ = 0;
00101     //printf("sending batch, %d\n", current_->batch_size_);
00102     for (int i=0; i<current_->batch_size_ && seqno < connection_size_-1; i++) {
00103         seqno++;
00104         output(seqno);
00105     }
00106     if (seqno == connection_size_-1) {
00107         finish();
00108     }
00109     else if (seqno < connection_size_-1) {
00110         if (current_->drop_[offset_] == NULL) {
00111             printf("Error: current fsm can't handle this tcp connection flow id %d (possibly too long)\n", fid_);
00112             exit(0);
00113         } 
00114         //printf("start timer %d\n", current_->transition_[offset_]);
00115         if (current_->transition_[offset_] == 0) {
00116             current_ = current_->drop_[offset_];
00117             send_batch();
00118         } else if (current_->transition_[offset_] == RTT) {
00119             set_timer(rtt_);
00120         } else if (current_->transition_[offset_] == TIMEOUT) {
00121             set_timer(rtt_ * 3);
00122         } else {
00123             printf("Error: weird transition timer\n");
00124             exit(0);
00125         }
00126     } else {
00127         printf("Error: sending more than %d packets\n", connection_size_);
00128         exit(0);
00129     }
00130 }
00131 
00132 void AbsTcpAgent::drop(int seqno)
00133 {
00134     //printf("dropped: %d\n", seqno);
00135     if (offset_ != 0) {
00136         printf("Error: Sorry, can't handle multiple drops per batch\n");
00137         exit(0);
00138     }
00139     offset_ = seqno - seqno_lb_;
00140     connection_size_++;
00141 }
00142 
00143 void AbsTcpAgent::finish()
00144 {
00145     //printf("finish: sent %d\n", seqno_lb_+1);
00146     cancel_timer();
00147 }
00148 
00149 void AbsTcpAgent::output(int seqno)
00150 {
00151         Packet* p = allocpkt();
00152         hdr_tcp *tcph = hdr_tcp::access(p);
00153         tcph->seqno() = seqno;
00154         send(p, 0);
00155 }
00156 
00157 void AbsTcpAgent::recv(Packet* pkt, Handler*)
00158 {
00159     Packet::free(pkt);
00160 }
00161 
00162 int AbsTcpAgent::command(int argc, const char*const* argv)
00163 {
00164         if (argc == 3 ) {
00165                 if (strcmp(argv[1], "rtt") == 0) {
00166             rtt_ = atof(argv[2]);
00167             //printf("rtt %f\n", rtt_);
00168             return (TCL_OK);
00169         }
00170                 if (strcmp(argv[1], "advance") == 0) {
00171             advanceby(atoi(argv[2]));
00172             return (TCL_OK);
00173                 }
00174                 if (strcmp(argv[1], "advanceby") == 0) {
00175                         advanceby(atoi(argv[2]));
00176                         return (TCL_OK);
00177                 }
00178         if(strcmp(argv[1], "print-stats") == 0) {
00179             // xxx: works best if invoked on a new fsm
00180             // (otherwise you don't get the whole thing).
00181             int n = atoi(argv[2]);
00182             if (n < 0 || n >= 17)
00183                 return TCL_ERROR;
00184             FSM::print_FSM_stats(current_, n);
00185                         return (TCL_OK);
00186         };
00187     } else if (argc == 2) {
00188                 if (strcmp(argv[1], "print") == 0) {
00189             // xxx: works best if invoked on a new fsm
00190             // (otherwise you don't get the whole thing).
00191             FSM::print_FSM(current_);
00192                         return (TCL_OK);
00193         };
00194     };
00195     return (Agent::command(argc, argv));
00196 }
00197 
00198 void AbsTcpTimer::expire(Event*)
00199 {
00200         a_->timeout();
00201 }
00202 
00203 
00204 //AbsTCP/TahoeAck
00205 static class AbsTcpTahoeAckClass : public TclClass {
00206 public:
00207     AbsTcpTahoeAckClass() : TclClass("Agent/AbsTCP/TahoeAck") {}
00208     TclObject* create(int, const char*const*) {
00209         return (new AbsTcpTahoeAckAgent());
00210     }
00211 } class_abstcptahoeack;
00212 
00213 AbsTcpTahoeAckAgent::AbsTcpTahoeAckAgent() : AbsTcpAgent()
00214 {
00215     size_ = 1000;
00216     current_ = TahoeAckFSM::instance().start_state();
00217     DropTargetAgent::instance().insert_tcp(this);
00218 }
00219 
00220 
00221 //AbsTCP/RenoAck
00222 static class AbsTcpRenoAckClass : public TclClass {
00223 public:
00224     AbsTcpRenoAckClass() : TclClass("Agent/AbsTCP/RenoAck") {}
00225     TclObject* create(int, const char*const*) {
00226         return (new AbsTcpRenoAckAgent());
00227     }
00228 } class_abstcprenoack;
00229 
00230 AbsTcpRenoAckAgent::AbsTcpRenoAckAgent() : AbsTcpAgent()
00231 {
00232     size_ = 1000;
00233     current_ = RenoAckFSM::instance().start_state();
00234     DropTargetAgent::instance().insert_tcp(this);
00235 }
00236 
00237 
00238 //AbsTCP/TahoeDelAck
00239 static class AbsTcpTahoeDelAckClass : public TclClass {
00240 public:
00241     AbsTcpTahoeDelAckClass() : TclClass("Agent/AbsTCP/TahoeDelAck") {}
00242     TclObject* create(int, const char*const*) {
00243         return (new AbsTcpTahoeDelAckAgent());
00244     }
00245 } class_abstcptahoedelack;
00246 
00247 AbsTcpTahoeDelAckAgent::AbsTcpTahoeDelAckAgent() : AbsTcpAgent()
00248 {
00249     size_ = 1000;
00250     current_ = TahoeDelAckFSM::instance().start_state();
00251     DropTargetAgent::instance().insert_tcp(this);
00252 }
00253 
00254 
00255 //AbsTCP/RenoDelAck
00256 static class AbsTcpRenoDelAckClass : public TclClass {
00257 public:
00258     AbsTcpRenoDelAckClass() : TclClass("Agent/AbsTCP/RenoDelAck") {}
00259     TclObject* create(int, const char*const*) {
00260         return (new AbsTcpRenoDelAckAgent());
00261     }
00262 } class_abstcprenodelack;
00263 
00264 AbsTcpRenoDelAckAgent::AbsTcpRenoDelAckAgent() : AbsTcpAgent()
00265 {
00266     size_ = 1000;
00267     current_ = RenoDelAckFSM::instance().start_state();
00268     DropTargetAgent::instance().insert_tcp(this);
00269 }
00270 
00271 
00272 //AbsTcpSink
00273 static class AbsTcpSinkClass : public TclClass {
00274 public:
00275         AbsTcpSinkClass() : TclClass("Agent/AbsTCPSink") {}
00276         TclObject* create(int, const char*const*) {
00277                 return (new AbsTcpSink());
00278         }
00279 } class_abstcpsink;
00280 
00281 AbsTcpSink::AbsTcpSink() : Agent(PT_ACK)
00282 {
00283     size_ = 40;
00284 }
00285 
00286 void AbsTcpSink::recv(Packet* pkt, Handler*)
00287 {
00288     Packet* p = allocpkt();
00289     send(p, 0);
00290         Packet::free(pkt);
00291 }
00292 
00293 static class AbsDelAckSinkClass : public TclClass {
00294 public:
00295         AbsDelAckSinkClass() : TclClass("Agent/AbsTCPSink/DelAck") {}
00296         TclObject* create(int, const char*const*) {
00297                 return (new AbsDelAckSink());
00298         }
00299 } class_absdelacksink;
00300 
00301 AbsDelAckSink::AbsDelAckSink() : AbsTcpSink(), delay_timer_(this)
00302 {
00303     size_ = 40;
00304     interval_ = 0.1;
00305 }
00306 
00307 void AbsDelAckSink::recv(Packet* pkt, Handler*)
00308 {
00309         if (delay_timer_.status() != TIMER_PENDING) {
00310         delay_timer_.resched(interval_);
00311     } else {
00312                 delay_timer_.cancel();
00313         Packet* p = allocpkt();
00314         send(p, 0);
00315     }
00316         Packet::free(pkt);
00317 }
00318 
00319 void AbsDelAckSink::timeout()
00320 {
00321         /*
00322          * The timer expired so we ACK the last packet seen.
00323          * (shouldn't this check for a particular time out#?  -kf)
00324          */
00325     Packet* p = allocpkt();
00326     send(p, 0);
00327 }
00328 
00329 void AbsDelayTimer::expire(Event */*e*/) {
00330         a_->timeout();
00331 }
00332 
00333 //Special drop target agent
00334 DropTargetAgent* DropTargetAgent::instance_;
00335 
00336 static class DropTargetClass : public TclClass {
00337 public:
00338         DropTargetClass() : TclClass("DropTargetAgent") {}
00339         TclObject* create(int, const char*const*) {
00340                 return (new DropTargetAgent());
00341         }
00342 } class_droptarget;
00343 
00344 DropTargetAgent::DropTargetAgent(): Connector(), dropper_list_(NULL)
00345 {
00346     instance_ = this;
00347 }
00348 
00349 void DropTargetAgent::recv(Packet* pkt, Handler*)
00350 {
00351     Dropper* tmp = dropper_list_;
00352 
00353         hdr_tcp *tcph = hdr_tcp::access(pkt);
00354         hdr_ip *iph = hdr_ip::access(pkt);
00355         //printf("flow %d dropping seqno %d\n", iph->flowid(),tcph->seqno());
00356     while(tmp != NULL) {
00357         if(tmp->agent_->flowid() == iph->flowid())
00358             tmp->agent_->drop(tcph->seqno());
00359         tmp = tmp->next_;
00360     }
00361     Packet::free(pkt);
00362 }
00363 
00364 void DropTargetAgent::insert_tcp(AbsTcpAgent* tcp)
00365 {
00366     Dropper* dppr = new Dropper;
00367     dppr->agent_=tcp;
00368     dppr->next_ = dropper_list_;
00369     dropper_list_ = dppr;
00370 }
00371 

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