![]() |
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/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 }
1.5.5