IBR-DTNSuite  0.10
BundleCore.cpp
Go to the documentation of this file.
1 /*
2  * BundleCore.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 "config.h"
23 #include "Configuration.h"
24 #include "core/EventDispatcher.h"
25 #include "core/BundleCore.h"
26 #include "core/GlobalEvent.h"
27 #include "core/BundleEvent.h"
28 #include "core/BundlePurgeEvent.h"
35 
36 #include <ibrcommon/data/BLOB.h>
38 #include <ibrdtn/data/MetaBundle.h>
39 #include <ibrdtn/data/Exceptions.h>
40 #include <ibrdtn/data/EID.h>
41 #include <ibrdtn/utils/Clock.h>
42 #include <ibrcommon/Logger.h>
43 
44 #include "limits.h"
45 #include <iostream>
46 #include <typeinfo>
47 #include <stdint.h>
48 
49 #ifdef WITH_BUNDLE_SECURITY
52 #endif
53 
54 #ifdef WITH_COMPRESSION
56 #endif
57 
58 using namespace dtn::data;
59 using namespace dtn::utils;
60 using namespace std;
61 
62 namespace dtn
63 {
64  namespace core
65  {
66  const std::string BundleCore::TAG = "BundleCore";
67  dtn::data::EID BundleCore::local;
68 
69  dtn::data::Length BundleCore::blocksizelimit = 0;
70  dtn::data::Length BundleCore::foreign_blocksizelimit = 0;
71  dtn::data::Length BundleCore::max_lifetime = 0;
72  dtn::data::Length BundleCore::max_timestamp_future = 0;
73  dtn::data::Size BundleCore::max_bundles_in_transit = 5;
74 
75  bool BundleCore::forwarding = true;
76 
77  BundleCore& BundleCore::getInstance()
78  {
79  static BundleCore instance;
80  return instance;
81  }
82 
83  BundleCore::BundleCore()
84  : _clock(1), _storage(NULL), _seeker(NULL), _router(NULL), _globally_connected(true)
85  {
91  }
92 
93  BundleCore::~BundleCore()
94  {
100  }
101 
102  void BundleCore::componentUp() throw ()
103  {
104  // routine checked for throw() on 15.02.2013
106 
107  _connectionmanager.initialize();
108  _clock.initialize();
109 
110  // start a clock
111  _clock.startup();
112  }
113 
115  {
117 
118  _connectionmanager.terminate();
119  _clock.terminate();
120  }
121 
123  {
124  // set the timezone
125  dtn::utils::Clock::setTimezone(config.getTimezone());
126 
127  // set local eid
128  dtn::core::BundleCore::local = config.getNodename();
129  IBRCOMMON_LOGGER_TAG(BundleCore::TAG, info) << "Local node name: " << config.getNodename() << IBRCOMMON_LOGGER_ENDL;
130 
131  // set block size limit
132  dtn::core::BundleCore::blocksizelimit = config.getLimit("blocksize");
134  {
136  }
137 
138  // set block size limit
139  dtn::core::BundleCore::foreign_blocksizelimit = config.getLimit("foreign_blocksize");
141  {
142  IBRCOMMON_LOGGER_TAG(BundleCore::TAG, info) << "Block size of foreign bundles limited to " << dtn::core::BundleCore::foreign_blocksizelimit << " bytes" << IBRCOMMON_LOGGER_ENDL;
143  }
144 
145  // set the lifetime limit
146  dtn::core::BundleCore::max_lifetime = config.getLimit("lifetime");
148  {
150  }
151 
152  // set the timestamp limit
153  dtn::core::BundleCore::max_timestamp_future = config.getLimit("predated_timestamp");
155  {
156  IBRCOMMON_LOGGER_TAG(BundleCore::TAG, info) << "Pre-dated timestamp limited to " << dtn::core::BundleCore::max_timestamp_future << " seconds in the future" << IBRCOMMON_LOGGER_ENDL;
157  }
158 
159  // set the maximum count of bundles in transit (bundles to send to the CL queue)
160  dtn::data::Size transit_limit = config.getLimit("bundles_in_transit");
161  if (transit_limit > 0)
162  {
165  }
166 
167  // enable or disable forwarding of bundles
168  if (config.getNetwork().doForwarding())
169  {
170  IBRCOMMON_LOGGER_TAG(BundleCore::TAG, info) << "Forwarding of bundles enabled." << IBRCOMMON_LOGGER_ENDL;
171  BundleCore::forwarding = true;
172  }
173  else
174  {
175  IBRCOMMON_LOGGER_TAG(BundleCore::TAG, info) << "Forwarding of bundles disabled." << IBRCOMMON_LOGGER_ENDL;
176  BundleCore::forwarding = false;
177  }
178 
179  const std::set<ibrcommon::vinterface> &global_nets = config.getNetwork().getInternetDevices();
180 
181  // remove myself from all listeners
183 
184  // add all listener in the configuration
185  for (std::set<ibrcommon::vinterface>::const_iterator iter = global_nets.begin(); iter != global_nets.end(); ++iter)
186  {
188  }
189 
190  // check connection state
191  check_connection_state();
192  }
193 
195  {
196  _storage = storage;
197  }
198 
200  {
201  _seeker = seeker;
202  }
203 
205  {
206  _router = router;
207  }
208 
210  {
211  if (_router == NULL)
212  {
213  throw ibrcommon::Exception("router not set");
214  }
215 
216  return *_router;
217  }
218 
220  {
221  if (_storage == NULL)
222  {
223  throw ibrcommon::Exception("No bundle storage is set! Use BundleCore::setStorage() to set a storage.");
224  }
225  return *_storage;
226  }
227 
229  {
230  if (_seeker == NULL)
231  {
232  throw ibrcommon::Exception("No bundle seeker is set! Use BundleCore::setSeeker() to set a seeker.");
233  }
234  return *_seeker;
235  }
236 
238  {
239  return _clock;
240  }
241 
243  {
244  try {
245  _connectionmanager.queue(transfer);
246  } catch (const dtn::net::NeighborNotAvailableException &ex) {
247  // signal interruption of the transfer
249  } catch (const dtn::net::ConnectionNotAvailableException &ex) {
250  } catch (const P2PDialupException&) {
251  // re-throw the P2PDialupException
252  throw;
253  } catch (const ibrcommon::Exception&) {
254  }
255  }
256 
258  {
259  return _connectionmanager;
260  }
261 
262  void BundleCore::addRoute(const dtn::data::EID &destination, const dtn::data::EID &nexthop, const dtn::data::Timeout timeout)
263  {
265  }
266 
267  void BundleCore::removeRoute(const dtn::data::EID &destination, const dtn::data::EID &nexthop)
268  {
270  }
271 
273  {
274  return _globally_connected;
275  }
276 
277  void BundleCore::raiseEvent(const dtn::core::Event *evt) throw ()
278  {
279  try {
280  const dtn::routing::QueueBundleEvent &queued = dynamic_cast<const dtn::routing::QueueBundleEvent&>(*evt);
281 
282  // get reference to the meta data of the bundle
283  const dtn::data::MetaBundle &meta = queued.bundle;
284 
285  // ignore fragments
286  if (meta.fragment) return;
287 
288  // if the destination is equal this node...
289  if (meta.destination == local)
290  {
291  // if the delivered variable is still false at the end of this block,
292  // we discard the bundle
293  bool delivered = false;
294 
295  // process this bundle locally
296  dtn::data::Bundle bundle = getStorage().get(meta);
297 
299  try {
300  // check for a custody signal
302 
303  CustodySignalBlock custody;
304  custody.read(payload);
305 
306  getStorage().releaseCustody(bundle.source, custody.bundleid);
307 
308  IBRCOMMON_LOGGER_DEBUG_TAG("BundleCore", 5) << "custody released for " << bundle.toString() << IBRCOMMON_LOGGER_ENDL;
309 
310  delivered = true;
312  // no custody signal available
314  // no payload block available
315  }
316 
317  if (delivered)
318  {
319  // gen a report
321  }
322  else
323  {
324  // gen a report
326  }
327 
329  {
330  // delete the bundle
332  }
333  }
334 
335  return;
336  } catch (const dtn::storage::NoBundleFoundException&) {
337  return;
338  } catch (const std::bad_cast&) {}
339 
340  try {
341  const dtn::net::TransferCompletedEvent &completed = dynamic_cast<const dtn::net::TransferCompletedEvent&>(*evt);
342  const dtn::data::MetaBundle &meta = completed.getBundle();
343  const dtn::data::EID &peer = completed.getPeer();
344 
345  if ((meta.destination.getNode() == peer.getNode())
347  {
348  // bundle has been delivered to its destination
349  // delete it from our storage
351 
352  IBRCOMMON_LOGGER_TAG("BundleCore", notice) << "singleton bundle delivered: " << meta.toString() << IBRCOMMON_LOGGER_ENDL;
353 
354  // gen a report
356  }
357 
358  return;
359  } catch (const std::bad_cast&) { }
360 
361  try {
362  const dtn::net::TransferAbortedEvent &aborted = dynamic_cast<const dtn::net::TransferAbortedEvent&>(*evt);
363 
365 
366  const dtn::data::EID &peer = aborted.getPeer();
367  const dtn::data::BundleID &id = aborted.getBundleID();
368 
369  try {
370  const dtn::data::MetaBundle meta = this->getStorage().get(id);
371 
373 
374  // if the bundle has been sent by this module delete it
375  if (meta.destination.getNode() == peer.getNode())
376  {
377  // bundle is not deliverable
379  }
380  } catch (const dtn::storage::NoBundleFoundException&) { };
381 
382  return;
383  } catch (const std::bad_cast&) { };
384 
385  try {
386  const dtn::core::BundlePurgeEvent &purge = dynamic_cast<const dtn::core::BundlePurgeEvent&>(*evt);
387 
388  // get the global storage
390 
391  try {
392  // delete the bundle
393  storage.remove(purge.bundle);
394  } catch (const dtn::storage::NoBundleFoundException&) { };
395 
396  return;
397  } catch (const std::bad_cast&) { }
398 
399  try {
400  const dtn::core::TimeAdjustmentEvent &timeadj = dynamic_cast<const dtn::core::TimeAdjustmentEvent&>(*evt);
401 
402  // set the local clock to the new timestamp
404  } catch (const std::bad_cast&) { }
405  }
406 
408  {
409  if (dtn::utils::Clock::isExpired(obj.expiretime)) {
410  // ... bundle is expired
411  IBRCOMMON_LOGGER_DEBUG_TAG("BundleCore", 35) << "bundle rejected: bundle has expired (" << obj.toString() << ")" << IBRCOMMON_LOGGER_ENDL;
412  throw dtn::data::Validator::RejectedException("bundle is expired");
413  }
414 
415  // check if the lifetime of the bundle is too long
416  if (BundleCore::max_lifetime > 0)
417  {
418  if (obj.lifetime > BundleCore::max_lifetime)
419  {
420  // ... we reject bundles with such a long lifetime
421  IBRCOMMON_LOGGER_DEBUG_TAG("BundleCore", 35) << "lifetime of bundle rejected: " << obj.toString() << IBRCOMMON_LOGGER_ENDL;
422  throw dtn::data::Validator::RejectedException("lifetime of the bundle is too long");
423  }
424  }
425 
426  // check if the timestamp is in the future
428  {
429  // first check if the local clock is reliable
431  // then check the timestamp
433  {
434  // ... we reject bundles with a timestamp so far in the future
435  IBRCOMMON_LOGGER_TAG("BundleCore", warning) << "timestamp of bundle rejected: " << obj.toString() << IBRCOMMON_LOGGER_ENDL;
436  throw dtn::data::Validator::RejectedException("timestamp is too far in the future");
437  }
438  }
439  }
440 
442  {
443  // if we do not forward bundles
445  {
446  if (!p.destination.sameHost(BundleCore::local))
447  {
448  // ... we reject all non-local bundles.
449  IBRCOMMON_LOGGER_TAG("BundleCore", warning) << "non-local bundle rejected: " << p.toString() << IBRCOMMON_LOGGER_ENDL;
450  throw dtn::data::Validator::RejectedException("bundle is not local");
451  }
452  }
453 
454  // check if the lifetime of the bundle is too long
455  if (BundleCore::max_lifetime > 0)
456  {
457  if (p.lifetime > BundleCore::max_lifetime)
458  {
459  // ... we reject bundles with such a long lifetime
460  IBRCOMMON_LOGGER_TAG("BundleCore", warning) << "lifetime of bundle rejected: " << p.toString() << IBRCOMMON_LOGGER_ENDL;
461  throw dtn::data::Validator::RejectedException("lifetime of the bundle is too long");
462  }
463  }
464 
465  // check if the timestamp is in the future
467  {
468  // first check if the local clock is reliable
470  // then check the timestamp
472  {
473  // ... we reject bundles with a timestamp so far in the future
474  IBRCOMMON_LOGGER_TAG("BundleCore", warning) << "timestamp of bundle rejected: " << p.toString() << IBRCOMMON_LOGGER_ENDL;
475  throw dtn::data::Validator::RejectedException("timestamp is too far in the future");
476  }
477  }
478  }
479 
481  {
482  // check for the size of the block
483  // reject a block if it exceeds the payload limit
485  {
486  IBRCOMMON_LOGGER_TAG("BundleCore", warning) << "bundle rejected: block size of " << size.toString() << " is too big" << IBRCOMMON_LOGGER_ENDL;
487  throw dtn::data::Validator::RejectedException("block size is too big");
488  }
489  }
490 
492  {
493  // check for the size of the foreign block
494  // reject a block if it exceeds the payload limit
497  if (bundle.source.getNode() != dtn::core::BundleCore::local) {
498  if (bundle.destination.getNode() != dtn::core::BundleCore::local) {
499  IBRCOMMON_LOGGER_TAG("BundleCore", warning) << "foreign bundle " << bundle.toString() << " rejected: block size of " << size.toString() << " is too big" << IBRCOMMON_LOGGER_ENDL;
500  throw dtn::data::Validator::RejectedException("foreign block size is too big");
501  }
502  }
503  }
504  }
505 
506  // check for the size of the block
507  // reject a block if it exceeds the payload limit
509  {
510  if (size > BundleCore::blocksizelimit)
511  {
512  IBRCOMMON_LOGGER_TAG("BundleCore", warning) << "bundle " << bundle.toString() << " rejected: block size of " << size.toString() << " is too big" << IBRCOMMON_LOGGER_ENDL;
513  throw dtn::data::Validator::RejectedException("block size is too big");
514  }
515  }
516  }
517 
519  {
520  // reject bundles without destination
521  if (b.destination.isNone())
522  {
523  IBRCOMMON_LOGGER_TAG("BundleCore", warning) << "bundle rejected: the destination is null" << IBRCOMMON_LOGGER_ENDL;
524  throw dtn::data::Validator::RejectedException("bundle destination is none");
525  }
526 
527  // check if the bundle is expired
529  {
530  IBRCOMMON_LOGGER_TAG("BundleCore", warning) << "bundle rejected: bundle has expired (" << b.toString() << ")" << IBRCOMMON_LOGGER_ENDL;
531  throw dtn::data::Validator::RejectedException("bundle is expired");
532  }
533 
534 #ifdef WITH_BUNDLE_SECURITY
535  // do a fast security check
536  try {
539  IBRCOMMON_LOGGER_DEBUG_TAG("BundleCore", 5) << "[bundle rejected] security checks failed, reason: " << ex.what() << ", bundle: " << b.toString() << IBRCOMMON_LOGGER_ENDL;
540  throw dtn::data::Validator::RejectedException("security checks failed");
541  }
542 #endif
543 
544  // check for invalid blocks
545  for (dtn::data::Bundle::const_iterator iter = b.begin(); iter != b.end(); ++iter)
546  {
547  try {
548  const dtn::data::ExtensionBlock &e = dynamic_cast<const dtn::data::ExtensionBlock&>(**iter);
549 
551  {
552  // reject the hole bundle
553  throw dtn::data::Validator::RejectedException("bundle contains unintelligible blocks");
554  }
555 
557  {
558  // transmit status report, because we can not process this block
560  }
561  } catch (const std::bad_cast&) { }
562  }
563  }
564 
565  const std::string BundleCore::getName() const
566  {
567  return "BundleCore";
568  }
569 
571  {
572  // walk through the block and process them when needed
573  for (dtn::data::Bundle::iterator iter = b.begin(); iter != b.end(); ++iter)
574  {
575  const dtn::data::Block &block = (**iter);
576 #ifdef WITH_BUNDLE_SECURITY
578  {
579  // try to decrypt the bundle
580  try {
583  // decrypt needed, but no key is available
584  IBRCOMMON_LOGGER_TAG("BundleCore", warning) << "No key available for decrypt bundle." << IBRCOMMON_LOGGER_ENDL;
586  // decrypt failed
587  IBRCOMMON_LOGGER_TAG("BundleCore", warning) << "Decryption of bundle failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
588  }
589  break;
590  }
591 #endif
592 
593 #ifdef WITH_COMPRESSION
595  {
596  // try to decompress the bundle
597  try {
599  } catch (const ibrcommon::Exception&) { };
600  break;
601  }
602 #endif
603  }
604  }
605 
607  {
608  const std::set<ibrcommon::vinterface> &global_nets = dtn::daemon::Configuration::getInstance().getNetwork().getInternetDevices();
609  if (global_nets.find(evt.getInterface()) != global_nets.end()) {
610  check_connection_state();
611  }
612  }
613 
615  {
616  if (val == _globally_connected) return;
617 
618  if (val) {
620  } else {
622  }
623 
624  _globally_connected = val;
625  }
626 
627  void BundleCore::check_connection_state() throw ()
628  {
629  const std::set<ibrcommon::vinterface> &global_nets = dtn::daemon::Configuration::getInstance().getNetwork().getInternetDevices();
630 
631  if (global_nets.empty()) {
632  // no configured internet devices
633  // assume we are connected globally
634  setGloballyConnected(true);
635  } else {
636  bool found = false;
637  for (std::set<ibrcommon::vinterface>::const_iterator iter = global_nets.begin(); iter != global_nets.end(); ++iter)
638  {
639  const ibrcommon::vinterface &iface = (*iter);
640  if (!iface.getAddresses(ibrcommon::vaddress::SCOPE_GLOBAL).empty()) {
641  found = true;
642  }
643  }
644  setGloballyConnected(found);
645  }
646  }
647  }
648 }