![]() |
User Manual, Developers Guide and API Documentation |
![]() |
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
1.5.5