User Manual, Developers Guide and API Documentation

ReassemblyBuffer.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/sar/reassembly/ReassemblyBuffer.hpp>
00029 #include <WNS/ldk/sar/SegAndConcat.hpp>
00030 
00031 #include <WNS/simulator/ISimulator.hpp>
00032 #include <WNS/ldk/probe/TickTack.hpp>
00033 
00034 #include <sstream>
00035 
00036 using namespace wns::ldk::sar::reassembly;
00037 
00038 ReassemblyBuffer::ReassemblyBuffer():
00039     commandReader_(NULL),
00040     delayProbingEnabled_(false)
00041 {
00042 }
00043 
00044 void
00045 ReassemblyBuffer::initialize(wns::ldk::CommandReaderInterface* cr)
00046 {
00047     assure(cr != NULL, "Invalid command reader given in ReassemblyBuffer");
00048 
00049     commandReader_ = cr;
00050 
00051     assure(integrityCheck(), "Invalid state after initialization in ReassemblyBuffer");
00052 }
00053 
00054 bool
00055 ReassemblyBuffer::isEmpty()
00056 {
00057     return buffer_.size() == 0;
00058 }
00059 
00060 long
00061 ReassemblyBuffer::getNextExpectedSN()
00062 {
00063     if (isEmpty())
00064     {
00065         return -1;
00066     }
00067     else
00068     {
00069         return (1 + readCommand(buffer_.back())->peer.sn_);
00070     }
00071 }
00072 
00073 bool
00074 ReassemblyBuffer::isNextExpectedSegment(const wns::ldk::CompoundPtr& c)
00075 {
00076     // accept if the buffer is empty and either the begin flag is set
00077     // or the segment contains at least one other SDU which must be the beginning of a fragment
00078     if (isEmpty() && (readCommand(c)->getBeginFlag() || readCommand(c)->peer.pdus_.size() > 1))
00079     {
00080         return true;
00081     }
00082 
00083     long expectedSN = getNextExpectedSN();
00084     long currentSN = readCommand(c)->peer.sn_;
00085 
00086     if (expectedSN == currentSN)
00087     {
00088         return true;
00089     }
00090     else
00091     {
00092         return false;
00093     }
00094 }
00095 
00096 bool
00097 ReassemblyBuffer::accepts(const wns::ldk::CompoundPtr& c)
00098 {
00099     SegAndConcatCommand* command = NULL;
00100     command = readCommand(c);
00101 
00102     // accept if the buffer is empty and either the begin flag is set
00103     // or the segment contains at least one other SDU which must be the beginning of a fragment
00104     if (isEmpty() && (readCommand(c)->getBeginFlag() || readCommand(c)->peer.pdus_.size() > 1))
00105     {
00106         return true;
00107     }
00108     else
00109     {
00110         return isNextExpectedSegment(c);
00111     }
00112 }
00113 
00114 void
00115 ReassemblyBuffer::insert(wns::ldk::CompoundPtr c)
00116 {
00117     assure(accepts(c), "Trying to insert an unacceptable compound");
00118 
00119     if(isEmpty() && !readCommand(c)->getBeginFlag())
00120     {
00121         assure(readCommand(c)->peer.pdus_.size() > 1, "Buffer Emtpy, isBegin flag set to false and segment contains only fragments of one SDU: should have been dropped by accepts()");
00122         readCommand(c)->peer.pdus_.pop_front();
00123         readCommand(c)->setBeginFlag();
00124     }
00125 
00126     buffer_.push_back(c);
00127 
00128     integrityCheck();
00129 }
00130 
00131 wns::ldk::sar::SegAndConcatCommand*
00132 ReassemblyBuffer::readCommand(const wns::ldk::CompoundPtr& c)
00133 {
00134     wns::ldk::sar::SegAndConcatCommand* command = NULL;
00135     command = commandReader_->readCommand<SegAndConcatCommand>(c->getCommandPool());
00136     assure(command!=NULL, "Command could not be retrieved");
00137     return command;
00138 }
00139 
00140 ReassemblyBuffer::SegmentContainer
00141 ReassemblyBuffer::getReassembledSegments(int &reassembledSegmentCounter)
00142 {
00143     delays_.clear();
00144 
00145     reassembledSegmentCounter = 0;
00146 
00147     assure(integrityCheck(), "IntegrityCheck failed!");
00148 
00149     ReassemblyBuffer::SegmentContainer sc;
00150 
00151     while (buffer_.size() > 0)
00152     {
00153         assure(integrityCheck(), "IntegrityCheck failed!");
00154 
00155         SegAndConcatCommand* frontCommand = readCommand(buffer_.front());
00156 
00157         // Segment starts with an entire PDU and ends with an entire PDU, 
00158         // we can reassemble all PDUs within this segment
00159         if (frontCommand->getEndFlag())
00160         {
00161             std::list<wns::ldk::CompoundPtr>::iterator it;
00162 
00163             for(it = frontCommand->peer.pdus_.begin(); it!=frontCommand->peer.pdus_.end(); ++it)
00164             {
00165                 sc.push_back( (*it) );
00166                 prepareForProbing(sc.size() - 1, buffer_.front());
00167             }
00168 
00169             buffer_.pop_front();
00170             reassembledSegmentCounter++;
00171 
00172             // Whole PDU(s) was/were unpacked. IntegrityCheck must hold.
00173             assure(integrityCheck(), "IntegrityCheck failed!");
00174         }
00175         else
00176         {
00177             // Is there a follow-up segment with either more than one PDU
00178             // or with the end flag set? If yes, we can reassemble.
00179             // Else we cannot reassamble any more.
00180             ReassemblyBuffer::SegmentContainer::iterator endOfSDU;
00181 
00182             for(endOfSDU = buffer_.begin();
00183                 endOfSDU!=buffer_.end();
00184                 ++endOfSDU)
00185             {
00186                 SegAndConcatCommand* currentCommand = readCommand(*endOfSDU);
00187 
00188                 if (currentCommand->getEndFlag() || (currentCommand->peer.pdus_.size() > 1))
00189                 {
00190                     break;
00191                 }
00192             }
00193 
00194             // If we can reassemble
00195             if (endOfSDU != buffer_.end())
00196             {
00197                 while(buffer_.size() > 0)
00198                 {
00199                     SegAndConcatCommand* frontCommand = readCommand(buffer_.front());
00200 
00201                     // A whole PDU was in this one segment, more PDUs
00202                     // behind it in this segment. Take out the one PDU
00203                     // and mark the next segment as the start segment of the next PDU
00204                     if (frontCommand->peer.pdus_.size() > 1)
00205                     {
00206                         sc.push_front(frontCommand->peer.pdus_.front());
00207                         prepareForProbing(sc.size() - 1, buffer_.front());
00208 
00209                         frontCommand->peer.pdus_.pop_front();
00210                         reassembledSegmentCounter++;
00211                         frontCommand->setBeginFlag();
00212                         break;
00213                     }
00214                     // One PDU spans over the entire segment. But it could
00215                     // span over even more segments
00216                     else
00217                     {
00218                         sc.push_back(frontCommand->peer.pdus_.front());
00219                         prepareForProbing(sc.size() - 1, buffer_.front());
00220                     }
00221 
00222                     // The PDU does not span over more segments
00223                     if (frontCommand->getEndFlag())
00224                     {
00225                         buffer_.pop_front();
00226                         reassembledSegmentCounter++;
00227                         break;
00228                     }
00229                     // The PDU does span over more segments.
00230                     // Take the rest of the PDU out of the next
00231                     // segment and assure the counter is right after that.
00232                     // The next segment now starts with a new PDU marked
00233                     // by the "StartFlag".
00234                     else
00235                     {
00236                         buffer_.pop_front();
00237                         reassembledSegmentCounter++;
00238                         // The next segment continues this PDU
00239                         // The PDU needs to be removed from the list of the next segment,
00240                         // since we already pushed the PDU in this segment.
00241                         reassembledSegmentCounter += dropSegmentsOfSDU(sc.size() - 1);
00242                         break;
00243                     }
00244                 }
00245             }
00246             else
00247             {
00248                 break;
00249             }
00250         }
00251     }
00252 
00253     probe(sc); 
00254     return sc;
00255 } // getReassembledSegments
00256 
00257 std::string
00258 ReassemblyBuffer::dump()
00259 {
00260     std::stringstream s;
00261     SegmentContainer::iterator it;
00262 
00263     for(it=buffer_.begin(); it!=buffer_.end(); ++it)
00264     {
00265         SegAndConcatCommand* c = readCommand(*it);
00266 
00267         s << "|(" << std::string(c->getBeginFlag() ? "B":"")
00268           << std::string(c->getEndFlag() ? "E":"")
00269           << ")|" << c->peer.pdus_.size() << ":(";
00270 
00271         std::list<wns::ldk::CompoundPtr>::iterator pit;
00272 
00273         for(pit=c->peer.pdus_.begin(); pit!=c->peer.pdus_.end(); ++pit)
00274         {
00275             s << (*pit)->getBirthmark() << ",";
00276         }
00277         s << ")   ";
00278     }
00279 
00280     return s.str();
00281 }
00282 
00283 void
00284 ReassemblyBuffer::clear()
00285 {
00286     buffer_.clear();
00287 }
00288 
00289 size_t
00290 ReassemblyBuffer::size()
00291 {
00292     return buffer_.size();
00293 }
00294 
00295 bool
00296 ReassemblyBuffer::integrityCheck()
00297 {
00298     if (commandReader_ == NULL)
00299         return false;
00300 
00301     if (buffer_.size() == 0)
00302     {
00303         return true;
00304     }
00305 
00306     if (!(readCommand(buffer_.front())->peer.isBegin_))
00307     {
00308         return false;
00309     }
00310 
00311     return true;
00312 }
00313 
00314 // We have extracted a PDU from the last segment but the PDU continues in the next segments
00315 int
00316 ReassemblyBuffer::dropSegmentsOfSDU(int index)
00317 {
00318     assure(buffer_.size() > 0, "You cannot drop SDU segments from an empty buffer!");
00319     // This first Segment in buffer_ is the first to be dropped
00320     // until the next segment border
00321     int droppedSegmentCounter = 0;
00322 
00323     while(true)
00324     {
00325         SegAndConcatCommand* frontCommand = readCommand(buffer_.front());
00326         // The PDU ends in this segment. There are no other PDUs in the segment
00327         if ( (frontCommand->peer.pdus_.size() == 1) && (frontCommand->getEndFlag()) )
00328         {
00329             prepareForProbing(index, buffer_.front());
00330             buffer_.pop_front();
00331             droppedSegmentCounter++;
00332             break;
00333         }
00334 
00335         // The PDU ends in this segment. There are other PDUs in the segment.
00336         // Take out the PDU and set the beginning of the segment to the next PDU.
00337         if (frontCommand->peer.pdus_.size() > 1)
00338         {
00339             prepareForProbing(index, buffer_.front());
00340             frontCommand->peer.pdus_.pop_front();
00341             frontCommand->setBeginFlag();
00342             break;
00343         }
00344 
00345         // The PDU spans through the entire segment and continues in the next. 
00346         // Continue the loop until we find the end of the PDU.
00347         if ( (frontCommand->peer.pdus_.size() == 1) && (!frontCommand->getEndFlag()) )
00348         {
00349             prepareForProbing(index, buffer_.front());
00350             buffer_.pop_front();
00351             droppedSegmentCounter++;
00352             continue;
00353         }
00354     }
00355     return droppedSegmentCounter;
00356 }
00357 
00358 void
00359 ReassemblyBuffer::enableDelayProbing(const wns::probe::bus::ContextCollectorPtr& minDelayCC,
00360         const wns::probe::bus::ContextCollectorPtr& maxDelayCC,
00361         wns::ldk::CommandReaderInterface* cmdReader)
00362 {
00363     assure(minDelayCC != NULL, "No valid min delay probe");
00364     assure(maxDelayCC != NULL, "No valid max delay probe");
00365     assure(cmdReader != NULL, "No valid command reader");
00366 
00367     delayProbingEnabled_ = true;
00368     minDelayCC_ = minDelayCC;
00369     maxDelayCC_ = maxDelayCC;
00370     probeCmdReader_ = cmdReader;
00371 }
00372 
00373 void
00374 ReassemblyBuffer::prepareForProbing(int position,
00375     const wns::ldk::CompoundPtr& segment)
00376 {    
00377     if(delayProbingEnabled_)
00378     {
00379         assure(position >= 0, "Invalid position " << position);
00380         assure(segment != wns::ldk::CompoundPtr(), "No valid compound");
00381         assure(probeCmdReader_ != NULL, "No valid command reader");
00382 
00383         if(delays_.find(position) == delays_.end())
00384             delays_[position] = std::set<wns::simulator::Time>();
00385 
00386         wns::ldk::probe::TickTackCommand* cmd;
00387         cmd = probeCmdReader_->readCommand<wns::ldk::probe::TickTackCommand>(segment->getCommandPool());
00388         assure(cmd != NULL, "Cannot get TickTackCommand to probe delay");
00389 
00390         wns::simulator::Time now = wns::simulator::getEventScheduler()->getTime();
00391 
00392         delays_[position].insert(now - cmd->magic.tickTime);
00393     }
00394 }
00395 
00396 void
00397 ReassemblyBuffer::probe(const SegmentContainer& sc)
00398 {
00399     if(delayProbingEnabled_)
00400     {
00401         assure(minDelayCC_ != NULL, "No valid min delay probe");
00402         assure(maxDelayCC_ != NULL, "No valid max delay probe");
00403     
00404         SegmentContainer::const_iterator it;
00405         int i = 0;
00406         for (it = sc.begin(); it != sc.end(); ++it)
00407         {
00408             assure(!delays_[i].empty(), "No delay probed for " << i << "th PDU.");
00409             minDelayCC_->put((*it), *(delays_[i].begin()));
00410             maxDelayCC_->put((*it), *(delays_[i].rbegin()));
00411             i++;
00412         }
00413     }
00414 }

Generated on Fri May 25 03:31:46 2012 for openWNS by  doxygen 1.5.5