IBR-DTN  1.0.0
BundleMerger.cpp
Go to the documentation of this file.
1 /*
2  * BundleMerger.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "ibrdtn/config.h"
24 #include "ibrdtn/data/Block.h"
26 #include "ibrdtn/data/Exceptions.h"
27 #include <ibrcommon/thread/MutexLock.h>
28 #include <ibrcommon/Logger.h>
29 
30 namespace dtn
31 {
32  namespace data
33  {
34  BundleMerger::Container::Container(ibrcommon::BLOB::Reference &ref)
35  : _bundle(), _blob(ref), _initialized(false), _hasFirstFragBlocksAdded(false), _hasLastFragBlocksAdded(false), _appdatalength(0)
36  {
37  }
38 
40  {
41 
42  }
43 
45  {
46  return Chunk::isComplete(_appdatalength, _chunks);
47  }
48 
50  {
51  return _bundle;
52  }
53 
54  bool BundleMerger::Container::contains(Length offset, Length length) const
55  {
56  // check if the offered payload is already in the chunk list
57  for (std::set<Chunk>::const_iterator iter = _chunks.begin(); iter != _chunks.end(); ++iter)
58  {
59  const Chunk &chunk = (*iter);
60 
61  if (offset < chunk.offset) break;
62 
63  if ( (offset >= chunk.offset) && (offset < (chunk.offset + chunk.length)) )
64  {
65  if ((offset + length) <= (chunk.offset + chunk.length)) return true;
66  }
67  }
68 
69  return false;
70  }
71 
72  void BundleMerger::Container::add(Length offset, Length length)
73  {
74  BundleMerger::Chunk chunk(offset, length);
75  _chunks.insert(chunk);
76  }
77 
79  {
80  // check if the given bundle is a fragment
82  {
83  throw ibrcommon::Exception("This bundle is not a fragment!");
84  }
85 
86  if (c._initialized)
87  {
88  if ( (c._bundle.timestamp != obj.timestamp) ||
89  (c._bundle.sequencenumber != obj.sequencenumber) ||
90  (c._bundle.source != obj.source) )
91  throw ibrcommon::Exception("This fragment does not belongs to the others.");
92 
93  // set verification status to 'false' if one fragment was not verified
96  }
97  }
98  else
99  {
100  // copy the bundle
101  c._bundle = obj;
102 
103  // store the app data length
104  c._appdatalength = obj.appdatalength.get<dtn::data::Length>();
105 
106  // remove all block of the copy
107  c._bundle.clear();
108 
109  // mark the copy as non-fragment
110  c._bundle.set(dtn::data::Bundle::FRAGMENT, false);
111 
112  // add a new payloadblock
113  c._bundle.push_back(c._blob);
114 
115  c._hasFirstFragBlocksAdded = false;
116  c._hasLastFragBlocksAdded = false;
117 
118  c._initialized = true;
119  }
120 
121  ibrcommon::BLOB::iostream stream = c._blob.iostream();
122  (*stream).seekp(obj.fragmentoffset.get<std::streampos>());
123 
125  const Length plength = p.getLength();
126 
127  // skip write operation if chunk is already in the merged bundle
128  if (c.contains(obj.fragmentoffset.get<dtn::data::Length>(), plength)) return c;
129 
130  // copy payload of the fragment into the new blob
131  {
132  ibrcommon::BLOB::Reference ref = p.getBLOB();
133  ibrcommon::BLOB::iostream s = ref.iostream();
134  (*stream) << (*s).rdbuf() << std::flush;
135  }
136 
137  // add the chunk to the list of chunks
138  c.add(obj.fragmentoffset.get<dtn::data::Length>(), plength);
139 
140  // check if fragment is the first one
141  // add blocks only once
142  if (!c._hasFirstFragBlocksAdded && obj.fragmentoffset == 0)
143  {
144  c._hasFirstFragBlocksAdded = true;
145 
147 
148  // abort if the bundle do not contains a payload block
149  if (payload_it == obj.end()) throw ibrcommon::Exception("Payload block missing.");
150 
151  // iterate from begin to the payload block
152  for (dtn::data::Bundle::const_iterator block_it = obj.begin(); block_it != payload_it; ++block_it)
153  {
154  // get the current block and type
155  const Block &current_block = (**block_it);
156  block_t block_type = current_block.getType();
157 
158  // search the position of the payload block
160  if (p == c._bundle.end()) throw ibrcommon::Exception("Payload block missing.");
161 
162  try
163  {
165 
166  // insert new Block before payload block and copy block
167  dtn::data::Block &block = c._bundle.insert(p, f);
168  block = current_block;
169 
170  IBRCOMMON_LOGGER_DEBUG_TAG("BundleMerger", 5) << "Reassemble: Added Block before Payload: " << obj.toString() << " " << block_type << IBRCOMMON_LOGGER_ENDL;
171  }
172  catch(const ibrcommon::Exception &ex)
173  {
174  // insert new Block before payload block and copy block
175  dtn::data::Block &block = c._bundle.insert<dtn::data::ExtensionBlock>(p);
176  block = current_block;
177 
178  IBRCOMMON_LOGGER_DEBUG_TAG("BundleMerger", 5) << "Reassemble: Added Block before Payload: " << obj.toString() << " " << block_type << IBRCOMMON_LOGGER_ENDL;
179  }
180  }
181 
182  }
183 
184  //check if fragment is the last one
185  //add blocks only once
186  if(!c._hasLastFragBlocksAdded && obj.fragmentoffset + plength == obj.appdatalength)
187  {
188  c._hasLastFragBlocksAdded = true;
189 
190  // start to iterate after the payload block
192 
193  // abort if the bundle do not contains a payload block
194  if (payload_it == obj.end()) throw ibrcommon::Exception("Payload block missing.");
195 
196  // start with the block after the payload block
197  for (payload_it++; payload_it != obj.end(); ++payload_it)
198  {
199  //get the current block and type
200  const Block &current_block = (**payload_it);
201  block_t block_type = current_block.getType();
202 
203  try
204  {
206 
207  //push back new Block after payload block and copy block
208  dtn::data::Block &block = c._bundle.push_back(f);
209  block = current_block;
210 
211  IBRCOMMON_LOGGER_DEBUG_TAG("BundleMerger", 5) << "Reassemble: Added Block after Payload: " << obj.toString()<< " " << block_type << IBRCOMMON_LOGGER_ENDL;
212  }
213  catch(const ibrcommon::Exception &ex)
214  {
215  //push back new Block after payload block and copy block
217  block = current_block;
218 
219  IBRCOMMON_LOGGER_DEBUG_TAG("BundleMerger", 5) << "Reassemble: Added Block after Payload: " << obj.toString()<< " " << block_type << IBRCOMMON_LOGGER_ENDL;
220  }
221  }
222  }
223 
224  return c;
225  }
226 
228  {
229  ibrcommon::BLOB::Reference ref = ibrcommon::BLOB::create();
230  return Container(ref);
231  }
232 
233  BundleMerger::Container BundleMerger::getContainer(ibrcommon::BLOB::Reference &ref)
234  {
235  return Container(ref);
236  }
237 
239  : offset(o), length(l)
240  {
241  }
242 
244  {
245  }
246 
247  bool BundleMerger::Chunk::operator<(const Chunk &other) const
248  {
249  if (offset < other.offset) return true;
250  if (offset != other.offset) return false;
251 
252  return (length < other.length);
253  }
254 
255  bool BundleMerger::Chunk::isComplete(Length length, const std::set<Chunk> &chunks)
256  {
257  // check if the bundle payload is complete
258  Length position = 0;
259 
260  for (std::set<Chunk>::const_iterator iter = chunks.begin(); iter != chunks.end(); ++iter)
261  {
262  const Chunk &chunk = (*iter);
263 
264  // if the next offset is too small, we do not got all fragments
265  if (chunk.offset > position) return false;
266 
267  position = chunk.offset + chunk.length;
268  }
269 
270  // return true, if we reached the application data length
271  return (position >= length);
272  }
273  }
274 }
std::string toString() const
Definition: BundleID.cpp:190
static bool isComplete(Length length, const std::set< Chunk > &chunks)
std::ostream & operator<<(std::ostream &stream, const BundleID &obj)
Definition: BundleID.cpp:206
size_t Length
Definition: Number.h:33
dtn::data::Timestamp timestamp
Definition: BundleID.h:54
static Container getContainer()
iterator begin()
Definition: Bundle.cpp:49
T & insert(iterator before)
Definition: Bundle.h:200
dtn::data::Number sequencenumber
Definition: BundleID.h:55
bool get(FLAGS flag) const
block_list::const_iterator const_iterator
Definition: Bundle.h:77
T get() const
Definition: SDNV.h:113
virtual Length getLength() const
Container(ibrcommon::BLOB::Reference &ref)
block_list::iterator iterator
Definition: Bundle.h:76
static Factory & get(block_t type)
static const dtn::data::block_t BLOCK_TYPE
Definition: PayloadBlock.h:38
unsigned char block_t
Definition: Number.h:37
T & push_back()
Definition: Bundle.h:180
iterator find(block_t blocktype)
Definition: Bundle.cpp:307
ibrcommon::BLOB::Reference getBLOB() const
bool operator<(const Chunk &other) const
const block_t & getType() const
Definition: Block.h:73
iterator end()
Definition: Bundle.cpp:54
dtn::data::Number fragmentoffset
Definition: BundleID.h:57
void set(FLAGS flag, bool value)
dtn::data::EID source
Definition: BundleID.h:53