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

ack-recons.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 The 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 at Berkeley.
00018  * 4. Neither the name of the University nor of the Research Group may be used
00019  *    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  * ack-recons.cc: contributed by the Daedalus Research Group, 
00035  * UC Berkeley (http://daedalus.cs.berkeley.edu).
00036  *
00037  * $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/ack-recons.cc,v 1.6 2000/09/01 03:04:05 haoboy Exp $
00038  */
00039 
00040 /*
00041  * TCP Ack reconstructor.  This object sits on the other end of a constrained 
00042  * link and intersperses TCP acks to the source (without violating the e2e 
00043  * semantics of TCP acks).  This allows us to get good performance for TCP 
00044  * over various asymmetric networks, in conjunction with techniques to reduce 
00045  * the frequency of acks (such as ack filtering) with making any changes to 
00046  * the TCP source (e.g., like those implemented in tcp-asym.cc).  
00047  */
00048 
00049 #include "template.h"
00050 #include "ack-recons.h"
00051 
00052 static class AckReconsControllerClass : public TclClass {
00053 public:
00054         AckReconsControllerClass() : TclClass("AckReconsControllerClass") { }
00055         TclObject* create(int, const char*const*) {
00056                 return (new AckReconsController);
00057         }
00058 } class_ackrecons_controller;
00059 
00060 static class AckReconsClass : public TclClass {
00061 public:
00062         AckReconsClass() : TclClass("Agent/AckReconsClass") { }
00063         TclObject* create(int, const char*const* argv) {
00064                 return new AckRecons(atoi(argv[4]), atoi(argv[5]));
00065         }
00066 } class_ackrecons;
00067 
00068 /*
00069  * Demux a packet to the right ack reconstructor.
00070  */
00071 void
00072 AckReconsController::recv(Packet *p, Handler *)
00073 {
00074         Tcl& tcl = Tcl::instance();
00075         hdr_ip *ip = hdr_ip::access(p);
00076         tcl.evalf("%s demux %d %d", name(),
00077                   ip->saddr(), ip->daddr());
00078         AckRecons *ackRecons = 
00079                 (AckRecons *) TclObject::lookup(tcl.result());
00080         if (ackRecons == NULL) {
00081                 printf("Error: malformed ack reconstructor\n");
00082                 abort();
00083         }
00084         ackRecons->spq_ = spq_;
00085         ackRecons->recv(p);
00086 }
00087 
00088 void 
00089 AckRecons::recv(Packet *pkt)
00090 {
00091         double now = Scheduler::instance().clock();
00092         hdr_tcp *tcph = hdr_tcp::access(pkt);
00093         int &ack = tcph->seqno(), a, i;
00094         Tcl& tcl = Tcl::instance();
00095 #ifdef DEBUG
00096         printf("%f\tRecd ack %d\n", now, ack);
00097 #endif
00098         if (ackTemplate_ == 0)
00099                 ackTemplate_ = pkt->copy();
00100         if (adaptive_)
00101                 tcl.evalf("%s ackbw %d %f\n", name(), ack, now);
00102         /* The ack spacing policy is implemented in Tcl for flexibility */
00103         tcl.evalf("%s spacing %d\n", name(), ack);
00104         /* 
00105          * If the difference in acks is less than a threshold, let
00106          * it go through.  Later, we will look for rapid ack arrivals
00107          * to smooth them out and avoid the adverse effects of ack comp.
00108          */
00109         if ((!ackPending_ && ack-lastAck_ <= deltaAckThresh_) || dupacks_) {
00110                 if (ack == lastRealAck_)
00111                         dupacks_++;
00112                 else if (ack > lastAck_) {
00113                         dupacks_ = 0;
00114                         lastAck_ = ack;
00115                         lastTime_ = now;
00116                 }
00117                 spq_->reconsAcks_ = 0;
00118                 spq_->enque(pkt);
00119                 spq_->reconsAcks_ = 1;
00120 #ifdef DEBUG
00121                 printf("\t%f\tEnqueuing ack %d in order\n", now, ack);
00122 #endif
00123         } else {
00124                 if (ack == lastRealAck_)
00125                         dupacks_++;
00126                 /* Intersperse some acks and schedule their transmissions. */
00127                 double starttime = max(now, lastTime_);
00128                 for (a = lastAck_+delack_, i=0; a <= ack; a += delack_, i++)
00129                         sendack(a, starttime + i*ackSpacing_ - now);
00130                 if ((a-ack)%delack_)
00131                         sendack(ack, starttime + i*ackSpacing_ - now);
00132                 Packet::free(pkt);
00133         }
00134         if (ack >= lastRealAck_) {
00135                 lastRealAck_ = ack;
00136                 lastRealTime_ = now;
00137         }
00138 }
00139 
00140 int
00141 AckRecons::command(int argc, const char*const* argv)
00142 {
00143         return Agent::command(argc, argv);
00144 }
00145 
00146 /*
00147  * Arrange to send ack a at time t from now.
00148  */
00149 void
00150 AckRecons::sendack(int ack, double t)
00151 {
00152         Packet *ackp = ackTemplate_->copy();
00153         Scheduler &s = Scheduler::instance();
00154         hdr_tcp *th = hdr_tcp::access(ackp);
00155         th->seqno() = ack;
00156         /* Set no_ts_ in flags because we don't want an rtt sample for this */
00157         if (th->ts() == hdr_tcp::access(ackp)->ts()) {
00158                 hdr_flags *fh = hdr_flags::access(ackp);
00159                 fh->no_ts_ = 1;
00160                 th->ts_ = s.clock();    /* for debugging purposes only */
00161         }
00162         s.schedule((Handler *)this, (Event *)ackp, t);
00163         ackPending_++;
00164 #ifdef DEBUG
00165         printf("\t%f\tScheduling ack %d to be sent at %f\n", 
00166                s.clock(), ack, s.clock() + t);
00167 #endif
00168 }
00169 
00170 /* 
00171  * Handle scheduling of acks.
00172  */
00173 void
00174 AckRecons::handle(Event *e)
00175 {
00176         Packet *p = (Packet *) e;
00177         hdr_tcp *th = hdr_tcp::access(p);
00178         ackPending_--;
00179         if (lastAck_ < th->seqno()) {
00180                 spq_->reconsAcks_ = 0;
00181                 /* 
00182                  * need to do queue's recv here, so that a deque is
00183                  * forced if the queue isn't blocked.  It's not
00184                  * sufficient to call spq_->recv() alone.
00185                  */
00186                 target_->recv(p); /* maybe do acksfirst for this ack? */
00187                 spq_->reconsAcks_ = 1;
00188                 lastTime_ = Scheduler::instance().clock();
00189                 lastAck_ = th->seqno();
00190 #ifdef DEBUG
00191                 printf("%f\tSending scheduled ack %d\n",lastTime_,th->seqno());
00192 #endif
00193         } else {
00194                 Packet::free(p);
00195 #ifdef DEBUG
00196                 printf("%f\tack %d superceded by ack %d at %f\n", 
00197                        Scheduler::instance().clock(), th->seqno(), lastAck_,
00198                        lastTime_);
00199 #endif
00200         }
00201 }

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