User Manual, Developers Guide and API Documentation

GoBackN.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002  * This file is part of openWNS (open Wireless Network Simulator)
00003  * _____________________________________________________________________________
00004  *
00005  * Copyright (C) 2004-2007
00006  * Chair of Communication Networks (ComNets)
00007  * Kopernikusstr. 5, D-52074 Aachen, Germany
00008  * phone: ++49-241-80-27910,
00009  * fax: ++49-241-80-22242
00010  * email: info@openwns.org
00011  * www: http://www.openwns.org
00012  * _____________________________________________________________________________
00013  *
00014  * openWNS is free software; you can redistribute it and/or modify it under the
00015  * terms of the GNU Lesser General Public License version 2 as published by the
00016  * Free Software Foundation;
00017  *
00018  * openWNS is distributed in the hope that it will be useful, but WITHOUT ANY
00019  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
00020  * A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00021  * details.
00022  *
00023  * You should have received a copy of the GNU Lesser General Public License
00024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00025  *
00026  ******************************************************************************/
00027 
00028 #include <WNS/ldk/arq/GoBackN.hpp>
00029 #include <WNS/ldk/Layer.hpp>
00030 #include <WNS/pyconfig/View.hpp>
00031 #include <WNS/Assure.hpp>
00032 
00033 using namespace wns::ldk;
00034 using namespace wns::ldk::arq;
00035 
00036 
00037 STATIC_FACTORY_REGISTER_WITH_CREATOR(
00038     GoBackN,
00039     ARQ,
00040     "wns.arq.GoBackN",
00041     FUNConfigCreator);
00042 
00043 
00044 STATIC_FACTORY_REGISTER_WITH_CREATOR(
00045     GoBackN,
00046     FunctionalUnit,
00047     "wns.arq.GoBackN",
00048     FUNConfigCreator);
00049 
00050 GoBackN::GoBackN(fun::FUN* fuNet, const wns::pyconfig::View& config) :
00051         ARQ(config),
00052 
00053         wns::ldk::fu::Plain<GoBackN, GoBackNCommand>(fuNet),
00054         Delayed<GoBackN>(),
00055         SuspendSupport(fuNet, config),
00056         CanTimeout(),
00057 
00058         windowSize(config.get<int>("windowSize")),
00059         sequenceNumberSize(config.get<int>("sequenceNumberSize")),
00060         NS(0),
00061         NR(0),
00062         LA(0),
00063         activeCompound(CompoundPtr()),
00064         sentPDUs(),
00065         toRetransmit(),
00066         ackPDUs(),
00067         receivedPDUs(),
00068         sendNow(false),
00069         resendTimeout(config.get<double>("resendTimeout")),
00070         transmissionAttempts( new wns::probe::bus::ContextCollector( wns::probe::bus::ContextProviderCollection(&getFUN()->getLayer()->getContextProviderCollection()),
00071                                          config.get<std::string>("probeName"))),
00072         delayingDelivery(false),
00073         delayedDeliveryNR(0),
00074         logger(config.get("logger"))
00075 {
00076     assure(windowSize >= 2, "Invalid windowSize.");
00077     assure(sequenceNumberSize >= 2*windowSize, "Maximum sequence number is to small for chosen windowSize");
00078     // this calculation here is done only once, not each time when
00079     // GoBackN::calculateSizes() is called:
00080     bitsPerACKFrame = bitsPerIFrame = (int) ceil(log(sequenceNumberSize) / log(2));
00081 }
00082 
00083 
00084 GoBackN::~GoBackN()
00085 {
00086     // empty internal buffers
00087     ackPDUs.clear();
00088     sentPDUs.clear();
00089     toRetransmit.clear();
00090     receivedPDUs.clear();
00091 }
00092 
00093 
00094 bool
00095 GoBackN::hasCapacity() const
00096 {
00097     /* Make sure we
00098        1. don't have an active PDU we are processing
00099        2. aren't occupied with retransmissions
00100        3. don't exceed the sending window
00101     */
00102     return (activeCompound == CompoundPtr()
00103         && retransmissionState() == false
00104         && NS - LA < windowSize);
00105 }
00106 
00107 
00108 void
00109 GoBackN::processOutgoing(const CompoundPtr& compound)
00110 {
00111     assure(hasCapacity(), "processOutgoing called although not accepting.");
00112     // argument=SDU from above, stored in class member
00113     activeCompound = compound;
00114 
00115     // construct info element with SEQNR which is glued to outgoing data packet
00116     GoBackNCommand* command = activateCommand(compound->getCommandPool());
00117 
00118     // indicate that packet is data (+ seqnr)
00119     command->peer.type = GoBackNCommand::I;
00120     // pack SEQNR into it
00121     command->setNS(NS);
00122 
00123     MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00124     m << " processOutgoing: SEQNR NS=" << command->getNS();
00125     MESSAGE_END();
00126 
00127     ++NS;
00128 
00129     sendNow = true;
00130 }
00131 
00132 
00133 const wns::ldk::CompoundPtr
00134 GoBackN::hasACK() const
00135 {
00136     if(!ackPDUs.empty())
00137     {
00138         return ackPDUs.front();
00139     }
00140 
00141     return CompoundPtr();
00142 }
00143 
00144 
00145 const wns::ldk::CompoundPtr
00146 GoBackN::hasData() const
00147 {
00148     if(retransmissionState())
00149     {
00150         return toRetransmit.front();
00151     }
00152 
00153     if(activeCompound != CompoundPtr() && sendNow)
00154     {
00155         return activeCompound;
00156     }
00157 
00158     return CompoundPtr();
00159 }
00160 
00161 
00162 wns::ldk::CompoundPtr
00163 GoBackN::getACK()
00164 {
00165     assure(hasACK(), getFUN()->getName() + " hasSomethingToSend has not been called to check whether there is something to send.");
00166 
00167     CompoundPtr nextACKToBeSent = ackPDUs.front();
00168     ackPDUs.pop_front();
00169 
00170     MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00171     m << " Sent "
00172       << (getCommand(nextACKToBeSent->getCommandPool())->getFrameType()==GoBackNCommand::ACK    ?"ACK":"NAK")
00173       << " frame. NS="
00174       << getCommand(nextACKToBeSent->getCommandPool())->getNS();
00175     MESSAGE_END();
00176 
00177     return nextACKToBeSent;
00178 }
00179 
00180 
00181 wns::ldk::CompoundPtr
00182 GoBackN::getData()
00183 {
00184     MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00185     m << " getData(): RetransmitQueue=" << toRetransmit.size()
00186       << ", SentQueue=" << sentPDUs.size() << " frames";
00187     MESSAGE_END();
00188 
00189     if(retransmissionState() == true)
00190     {
00191         assure( !toRetransmit.empty(), getFUN()->getName() + " is in retransmission state without anything to retransmit.");
00192 
00193         CompoundPtr nextPDUToBeRetransmit = toRetransmit.front();
00194         // keep track of the number of retransmissions (counter per PDU)
00195         GoBackNCommand* command = this->getCommand(nextPDUToBeRetransmit);
00196         command->localTransmissionCounter++;
00197 
00198         toRetransmit.pop_front();
00199         sentPDUs.push_back(nextPDUToBeRetransmit);
00200 
00201         MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00202         m << " getData(): Outgoing/downstack: Re-Sent I frame NS=" << command->getNS();
00203         MESSAGE_END();
00204 
00205         if( retransmissionState() == false )
00206         {
00207             MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00208             m << " getData(): Leaving retransmission state";
00209             MESSAGE_END();
00210         }
00211 
00212         // set the Timer
00213         setNewTimeout(resendTimeout);
00219         // and send a copy
00220         return nextPDUToBeRetransmit->copy();
00221     }
00222 
00223     // send a copy
00224     sendNow = false; // nothing more to send after this packet
00225     // if packet isn't ACK'd within this time it will be retransmitted.
00226     setNewTimeout(resendTimeout); // inherited from events::CanTimeout
00227 
00228     CompoundPtr it = activeCompound->copy();
00229     // store the PDU we now send in the Retransmission FIFO Buffer
00230     sentPDUs.push_back(activeCompound); // queue it in sentPDUs
00231     // keep track of the number of retransmissions
00232     getCommand(activeCompound)->localTransmissionCounter++; // first transmission of this packet here
00233     // empty the space for new outgoing compounds
00234     activeCompound = CompoundPtr(); // empty
00235 
00236 
00237     MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00238     m << " getData(): Outgoing/downstack: Sent I frame. NS=" << getCommand(it->getCommandPool())->getNS();
00239     MESSAGE_END();
00240 
00241     return it; // current packet (copy)
00242 }
00243 
00244 
00245 void
00246 GoBackN::onTimeout()
00247 {
00248     assure(!sentPDUs.empty(), "No timeout without any sent frames possible");
00249 
00250     MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00251     m << " Entering retransmission state on timeout";
00252     MESSAGE_END();
00253 
00254     // search & find first packet out of sentPDUs to put into toRetransmit
00255     // queue
00256     prepareRetransmission();
00257 
00258     // initiate retransmissions
00259     tryToSend(); // inherited from  wns::ldk::Delayed< GoBackN >
00260     // Use this method if the FunctionalUnit changes state
00261     // spontanteously. That is, if it may have compounds ready to send while
00262     // not in processIncoming/processOutgoing.  For example functional units
00263     // that send compounds after a timeout have to inform the Delayed
00264     // implementation that they are to be queried again for compounds to be
00265     // sent.
00266 }
00267 
00268 
00269 void
00270 GoBackN::processIncoming(const CompoundPtr& compound)
00271 {
00272     GoBackNCommand *command = getCommand(compound->getCommandPool());
00273 
00274     switch(command->peer.type) {
00275     case GoBackNCommand::I:
00276         this->onIFrame(compound);
00277         break;
00278     case GoBackNCommand::ACK:
00279         this->onACKFrame(compound);
00280         break;
00281     case GoBackNCommand::NAK:
00282         this->onNAKFrame(compound);
00283         break;
00284     }
00285 }
00286 
00287 void
00288 GoBackN::onIFrame(const CompoundPtr& compound)
00289 {
00290 
00291     GoBackNCommand* command = getCommand(compound);
00292     ARQCommand::SequenceNumber receivedNS = command->getNS();
00293     ARQCommand::SequenceNumber ACKNS = receivedNS;
00294     GoBackNCommand::FrameType ack_type = GoBackNCommand::I; // means none
00295 
00296     MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00297     m << " Received I frame "
00298       << " expected NR=" << NR
00299       << " received NS=" << receivedNS;
00300     MESSAGE_END();
00301 
00302     if(receivedNS == NR) {
00303         if (delayingDelivery)
00304         {
00305             if (receivedNS - delayedDeliveryNR < windowSize)
00306             {
00307                 MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00308                 m << " Delaying delivery of I frame " << NR;
00309                 MESSAGE_END();
00310 
00311                 receivedPDUs.push_back(compound);
00312                 ++NR;
00313 
00314                 ack_type = GoBackNCommand::ACK; // return ACK
00315                 ACKNS = receivedNS;
00316             }
00317         }
00318         else
00319         {
00320             // this is the I frame we waited for.
00321             MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00322             m << " Delivering I frame " << NR;
00323             MESSAGE_END();
00324 
00325             getDeliverer()->getAcceptor(compound)->onData(compound); // send to upper layer
00326             ++NR;
00327 
00328             // check if there are subsequent frames we have already received
00329             // should not occur for GoBackN
00330             assure( receivedPDUs.empty() , "receivedPDUs nonempty (impossible for GoBackN)");
00331             ack_type = GoBackNCommand::ACK; // return ACK
00332             ACKNS = receivedNS;
00333         }
00334     } else {
00335         // we received an out-of-sequence frame
00336         MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00337         m << " Discarding out-of-sequence I frame NS=" << command->getNS() << ", sending NAK for NR=" << NR;
00338         MESSAGE_END();
00339         //assure( distance(command->getNS(),NR)>0 , "received old/duplicate I frame (impossible for GoBackN)");
00340         //if( distance(receivedNS, NR ) > 0 ) { // NS to high (missing frame in between)
00341         //m << " Buffering out-of-sequence I frame NS=" << command->getNS();
00342         // store the received frame for later
00343         //keepSorted(compound, receivedPDUs);
00344         ack_type = GoBackNCommand::NAK; // return NAK
00345         ACKNS = NR; // NAK for oldest missing frame+1
00346         //} else {
00347         /* we received an old frame (ACK got lost)
00348            re-send the ACK and discard the frame */
00349         // should not occur for GoBackN
00350         //ack_type = GoBackNCommand::I; // no ACK
00351         //}
00352     }
00353 
00354     if (delayingDelivery == false || receivedNS - delayedDeliveryNR < windowSize)
00355     {
00356         switch (ack_type) {
00357         case (GoBackNCommand::ACK):
00358         case (GoBackNCommand::NAK): {
00359             // acknowledge the received I-Frame by ACK or NAK
00360             CommandPool* ackPCI = getFUN()->getProxy()->createReply(compound->getCommandPool(), this);
00361             // warum wird der ackPCI-compund jetzt schon reingesteckt?
00362             ackPDUs.push_back(CompoundPtr(new Compound(ackPCI)));
00363             // und wie kommt diese Ergaenzung dann da rein?
00364             GoBackNCommand* ackCommand = activateCommand(ackPCI);
00365             ackCommand->setNS(ACKNS);
00366             ackCommand->peer.type = ack_type;
00367             MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00368             m << " Created ACK/NAK type=" << (int)ack_type << " NS=" << ACKNS;
00369             MESSAGE_END();
00370             break;
00371         }
00372         case (GoBackNCommand::I): // no ACK
00373         default:
00374             break;
00375         }
00376 
00377         MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00378         m << " Number of ACKs pending: " << ackPDUs.size();
00379         MESSAGE_END();
00380     }
00381 
00382 }
00383 
00384 void
00385 GoBackN::onACKFrame(const CompoundPtr& compound)
00386 {
00387     GoBackNCommand* command = getCommand(compound->getCommandPool());
00388     ARQCommand::SequenceNumber ackedNS = command->getNS();
00389 
00390     MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00391     m << " ACK frame received: NS=" << ackedNS << " LA=" << LA;
00392     MESSAGE_END();
00393 
00394     // Delete ACKed frame from one of the retransmission buffers
00395     // it may happen, that due to duplicate ACKs the PDU is neither in sentPDUs
00396     // nor in toRetransmit
00397     removeACKed(ackedNS, sentPDUs);
00398     removeACKed(ackedNS, toRetransmit);
00399 
00400     // LA = last ACK received in order
00401     if(ackedNS == LA) {
00402         // received the expected ACK
00403         MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00404         m << " ACK frame" << " expected=" << LA << " received=" << ackedNS;
00405         MESSAGE_END();
00406         // advance sending window
00407         ++LA;
00408         trySuspend();
00409     } else {
00410         //received out-of-sequence ACK
00411         MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00412         m << " Out-of-sequence ACK frame"
00413           << " expected LA=" << LA << " received=" << ackedNS;
00414         MESSAGE_END();
00415 
00416 
00417         if (ackedNS > LA) {
00418             // ackedNS too high means all lower numbers are acked
00419             // too
00420             MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00421             m << " ACK for NS=" << ackedNS << " also ACKs older frames: "
00422               << LA << "..." << ackedNS;
00423             MESSAGE_END();
00424             LA=ackedNS;
00425             ++LA;
00426             trySuspend();
00427             // TODO: remove all acked frames from sentPDUs / toRetransmit
00428             // done in removeACKed()
00429         } else {
00430             // else we received a duplicate and discard it.
00431             MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00432             m << " ACK for NS=" << ackedNS << " must not occur for GoBackN";
00433             MESSAGE_END();
00434         }
00435     }
00436 
00437     if (sentPDUs.empty() && hasTimeoutSet()) {
00438         cancelTimeout();
00439     }
00440     // Take care of pending retransmissions, if any
00441     if (retransmissionState())
00442         tryToSend();
00443 }
00444 
00445 
00446 void
00447 GoBackN::onNAKFrame(const CompoundPtr& compound)
00448 {
00449     GoBackNCommand* command = getCommand(compound->getCommandPool());
00450     ARQCommand::SequenceNumber ackedNS = command->getNS();
00451 
00452     // NAK(SN) means repeat all frames beginning with SN
00453     // also, this means frames LA...SN-1 are acked
00454 
00455     MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00456     m << " NAK frame received: NS=" << ackedNS << " LA=" << LA;
00457     MESSAGE_END();
00458 
00459     ARQCommand::SequenceNumber SNacked(ackedNS-1);
00460     removeACKed(SNacked, sentPDUs);
00461     removeACKed(SNacked, toRetransmit);
00462 
00463     assure( ackedNS >= LA, "NAK for already ACKed frame received");
00464 
00465     // frames LA...ackedNS-1 are acked (counter LA is always acked+1)
00466     LA=ackedNS;
00467 
00468     // prepare PDU List for Retransmission
00469     prepareRetransmission();
00470     if (!retransmissionState())
00471     {
00472         MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00473         m << " Leaving retransmission state, no Retransmissions pending";
00474         MESSAGE_END();
00475     }
00476 
00477     if (sentPDUs.empty() && hasTimeoutSet()) {
00478         cancelTimeout();
00479     }
00480     // Take care of pending retransmissions, if any
00481     if (retransmissionState())
00482         tryToSend();
00483 }
00484 
00485 
00486 void
00487 GoBackN::calculateSizes(const CommandPool* commandPool, Bit& commandPoolSize, Bit& sduSize) const
00488 {
00489     //What are the sizes in the upper Layers
00490     getFUN()->calculateSizes(commandPool, commandPoolSize, sduSize, this);
00491 
00492     //Calculate PCI size
00493     commandPoolSize += bitsPerACKFrame;
00494     commandPoolSize += 1; // 2 Frametypes can be represented with 1Bit
00495 
00496 }
00497 
00498 
00499 void
00500 GoBackN::prepareRetransmission()
00501 {
00502     MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00503     m << " prepareRetransmission(): RetransmitQueue=" << toRetransmit.size()
00504       << ", SentQueue=" << sentPDUs.size() << " frames";
00505     MESSAGE_END();
00506     show_seqnr_list("sentPDUs=",sentPDUs);
00507     show_seqnr_list("toRetransmit=",toRetransmit);
00508 
00509     // announce failed transmission to status collector for statistic collection (usable by other FUs)
00510     for ( CompoundContainer::iterator it = sentPDUs.begin() ; it != sentPDUs.end() ; it++ )
00511     {
00512         this->statusCollector->onFailedTransmission((*it));
00513     }
00514 
00515     toRetransmit.insert(toRetransmit.end(), sentPDUs.begin(), sentPDUs.end());
00516     sentPDUs.clear();
00517 
00518     MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00519     m << " prepareRetransmission(): RetransmitQueue=" << toRetransmit.size()
00520       << ", SentQueue=" << sentPDUs.size() << " frames";
00521     MESSAGE_END();
00522 }
00523 
00524 void
00525 GoBackN::removeACKed(const ARQCommand::SequenceNumber ackedNS, CompoundContainer& container)
00526 {
00527     MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00528     m << " removeACKed(" << ackedNS << ")";
00529     MESSAGE_END();
00530     show_seqnr_list("before removal: ",container);
00531     CompoundPtr compoundElement;
00532     while( !container.empty() ) {
00533         compoundElement = container.front();
00534         ARQCommand::SequenceNumber NS = getCommand(compoundElement)->getNS();
00535         if(NS <= ackedNS) {
00536             // a probe counting the number of transmissions needed
00537             transmissionAttempts->put(getCommand(compoundElement)->localTransmissionCounter);
00538 
00539             // collect the arq statistics for other FUs
00540             this->statusCollector->onSuccessfullTransmission(compoundElement);
00541 
00542             MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00543             m << " ACK for NS=" << NS
00544               << " received after " << getCommand(compoundElement)->localTransmissionCounter << " transmission attempts";
00545             MESSAGE_END();
00546             container.pop_front();
00547         } else {
00548             break;
00549         }
00550     }
00551     show_seqnr_list("after  removal: ",container);
00552 }
00553 
00554 bool
00555 GoBackN::retransmissionState() const
00556 {
00557     return !toRetransmit.empty();
00558 }
00559 
00560 void
00561 GoBackN::show_seqnr_list(const char* name, CompoundContainer& compoundList) const
00562 {
00563     MESSAGE_BEGIN(NORMAL, logger, m, getFUN()->getName());
00564     m << " " << name << " [";
00565     for ( CompoundContainer::iterator it = compoundList.begin() ; it != compoundList.end() ; it++ ) {
00566         int seqnr = getCommand( (*it)->getCommandPool() )->getNS();
00567         m << seqnr << " ";
00568     }
00569     m << "]";
00570     MESSAGE_END();
00571 }
00572 
00573 bool
00574 GoBackN::onSuspend() const
00575 {
00576     return NS == LA;
00577 }
00578 
00579 void
00580 GoBackN::doDelayDelivery()
00581 {
00582     delayingDelivery = true;
00583     delayedDeliveryNR = NR;
00584 }
00585 
00586 void
00587 GoBackN::doDeliver()
00588 {
00589     // check if there are subsequent frames we have already received
00590     while (!receivedPDUs.empty())
00591     {
00592 #ifndef NDEBUG
00593         ARQCommand::SequenceNumber toDeliver =  getCommand(receivedPDUs.front())->getNS();
00594 #endif
00595         assure(toDeliver == delayedDeliveryNR,
00596                "NS must be equal to NR since the loop will not be entered if it's greater zero and it cannot be smaller!!");
00597         // if so, deliver them
00598         MESSAGE_BEGIN(NORMAL, logger, m, "Delivering I frame ");
00599         m << delayedDeliveryNR;
00600         MESSAGE_END();
00601 
00602         getDeliverer()->getAcceptor(receivedPDUs.front())->onData(receivedPDUs.front());
00603 
00604         // and remove them from the receivedPDUs list.
00605         receivedPDUs.pop_front();
00606         MESSAGE_BEGIN(NORMAL, logger, m, "Removing from receivedPDUs: I-Frame ");
00607         m << delayedDeliveryNR;
00608         MESSAGE_END();
00609 
00610         // adjust received PDU counter
00611         ++delayedDeliveryNR;
00612     }
00613 
00614     delayingDelivery = false;
00615 
00616 }
00617 
00618 

Generated on Thu May 24 03:31:36 2012 for openWNS by  doxygen 1.5.5