IBR-DTNSuite  0.12
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"
34 
35 #include <ibrcommon/data/BLOB.h>
37 #include <ibrdtn/data/MetaBundle.h>
38 #include <ibrdtn/data/Exceptions.h>
39 #include <ibrdtn/data/EID.h>
40 #include <ibrdtn/utils/Clock.h>
41 #include <ibrcommon/Logger.h>
42 
43 #include "limits.h"
44 #include <iostream>
45 #include <typeinfo>
46 #include <stdint.h>
47 
48 #ifdef WITH_BUNDLE_SECURITY
51 #endif
52 
53 #ifdef WITH_COMPRESSION
55 #endif
56 
57 using namespace dtn::data;
58 using namespace dtn::utils;
59 using namespace std;
60 
61 namespace dtn
62 {
63  namespace core
64  {
65  const std::string BundleCore::TAG = "BundleCore";
66  dtn::data::EID BundleCore::local;
67 
68  dtn::data::Length BundleCore::blocksizelimit = 0;
69  dtn::data::Length BundleCore::foreign_blocksizelimit = 0;
70  dtn::data::Length BundleCore::max_lifetime = 0;
71  dtn::data::Length BundleCore::max_timestamp_future = 0;
72  dtn::data::Size BundleCore::max_bundles_in_transit = 5;
73 
74  bool BundleCore::forwarding = true;
75 
76  BundleCore& BundleCore::getInstance()
77  {
78  static BundleCore instance;
79  return instance;
80  }
81 
82  BundleCore::BundleCore()
83  : _clock(1), _storage(NULL), _seeker(NULL), _router(NULL), _globally_connected(true)
84  {
89  }
90 
91  BundleCore::~BundleCore()
92  {
97  }
98 
99  void BundleCore::componentUp() throw ()
100  {
101  // routine checked for throw() on 15.02.2013
103 
104  // initialize connection manager
105  _connectionmanager.initialize();
106 
107  // initialize wall clock
108  _clock.initialize();
109 
110  // initialize discovery agent
111  _disco_agent.initialize();
112 
113  // start a clock
114  _clock.startup();
115 
116  // start discovery agent
117  _disco_agent.startup();
118  }
119 
121  {
123 
124  // terminate discovery agent
125  _disco_agent.terminate();
126 
127  // terminate connection manager
128  _connectionmanager.terminate();
129 
130  // terminate wall clock
131  _clock.terminate();
132  }
133 
135  {
136  // set local eid
137  dtn::core::BundleCore::local = config.getNodename();
138  IBRCOMMON_LOGGER_TAG(BundleCore::TAG, info) << "Local node name: " << config.getNodename() << IBRCOMMON_LOGGER_ENDL;
139 
140  // set block size limit
141  dtn::core::BundleCore::blocksizelimit = config.getLimit("blocksize");
143  {
144  IBRCOMMON_LOGGER_TAG(BundleCore::TAG, info) << "Block size limited to " << dtn::core::BundleCore::blocksizelimit << " bytes" << IBRCOMMON_LOGGER_ENDL;
145  }
146 
147  // set block size limit
148  dtn::core::BundleCore::foreign_blocksizelimit = config.getLimit("foreign_blocksize");
150  {
151  IBRCOMMON_LOGGER_TAG(BundleCore::TAG, info) << "Block size of foreign bundles limited to " << dtn::core::BundleCore::foreign_blocksizelimit << " bytes" << IBRCOMMON_LOGGER_ENDL;
152  }
153 
154  // set the lifetime limit
155  dtn::core::BundleCore::max_lifetime = config.getLimit("lifetime");
157  {
158  IBRCOMMON_LOGGER_TAG(BundleCore::TAG, info) << "Lifetime limited to " << dtn::core::BundleCore::max_lifetime << " seconds" << IBRCOMMON_LOGGER_ENDL;
159  }
160 
161  // set the timestamp limit
162  dtn::core::BundleCore::max_timestamp_future = config.getLimit("predated_timestamp");
164  {
165  IBRCOMMON_LOGGER_TAG(BundleCore::TAG, info) << "Pre-dated timestamp limited to " << dtn::core::BundleCore::max_timestamp_future << " seconds in the future" << IBRCOMMON_LOGGER_ENDL;
166  }
167 
168  // set the maximum count of bundles in transit (bundles to send to the CL queue)
169  dtn::data::Size transit_limit = config.getLimit("bundles_in_transit");
170  if (transit_limit > 0)
171  {
173  IBRCOMMON_LOGGER_TAG(BundleCore::TAG, info) << "Limit the number of bundles in transit to " << dtn::core::BundleCore::max_bundles_in_transit << IBRCOMMON_LOGGER_ENDL;
174  }
175 
176  // enable or disable forwarding of bundles
177  if (config.getNetwork().doForwarding())
178  {
179  IBRCOMMON_LOGGER_TAG(BundleCore::TAG, info) << "Forwarding of bundles enabled." << IBRCOMMON_LOGGER_ENDL;
180  BundleCore::forwarding = true;
181  }
182  else
183  {
184  IBRCOMMON_LOGGER_TAG(BundleCore::TAG, info) << "Forwarding of bundles disabled." << IBRCOMMON_LOGGER_ENDL;
185  BundleCore::forwarding = false;
186  }
187 
188  const std::set<ibrcommon::vinterface> &global_nets = config.getNetwork().getInternetDevices();
189 
190  // remove myself from all listeners
192 
193  // add all listener in the configuration
194  for (std::set<ibrcommon::vinterface>::const_iterator iter = global_nets.begin(); iter != global_nets.end(); ++iter)
195  {
197  }
198 
199  // check connection state
200  check_connection_state();
201  }
202 
204  {
205  _storage = storage;
206  }
207 
209  {
210  _seeker = seeker;
211  }
212 
214  {
215  _router = router;
216  }
217 
219  {
220  if (_router == NULL)
221  {
222  throw ibrcommon::Exception("router not set");
223  }
224 
225  return *_router;
226  }
227 
229  {
230  if (_storage == NULL)
231  {
232  throw ibrcommon::Exception("No bundle storage is set! Use BundleCore::setStorage() to set a storage.");
233  }
234  return *_storage;
235  }
236 
238  {
239  if (_seeker == NULL)
240  {
241  throw ibrcommon::Exception("No bundle seeker is set! Use BundleCore::setSeeker() to set a seeker.");
242  }
243  return *_seeker;
244  }
245 
247  {
248  return _clock;
249  }
250 
252  {
253  return _connectionmanager;
254  }
255 
257  {
258  return _disco_agent;
259  }
260 
261  void BundleCore::addRoute(const dtn::data::EID &destination, const dtn::data::EID &nexthop, const dtn::data::Timeout timeout)
262  {
264  }
265 
266  void BundleCore::removeRoute(const dtn::data::EID &destination, const dtn::data::EID &nexthop)
267  {
269  }
270 
272  {
273  return _globally_connected;
274  }
275 
276  void BundleCore::raiseEvent(const dtn::core::Event *evt) throw ()
277  {
278  try {
279  const dtn::routing::QueueBundleEvent &queued = dynamic_cast<const dtn::routing::QueueBundleEvent&>(*evt);
280 
281  // get reference to the meta data of the bundle
282  const dtn::data::MetaBundle &meta = queued.bundle;
283 
284  // ignore fragments
285  if (meta.isFragment()) return;
286 
287  // if the destination is equal this node...
288  if (meta.destination == local)
289  {
290  // if the delivered variable is still false at the end of this block,
291  // we discard the bundle
292  bool delivered = false;
293 
294  // process this bundle locally
295  const dtn::data::Bundle bundle = getStorage().get(meta);
296 
298  try {
299  // check for a custody signal
300  const dtn::data::PayloadBlock &payload = bundle.find<dtn::data::PayloadBlock>();
301 
302  CustodySignalBlock custody;
303  custody.read(payload);
304 
305  getStorage().releaseCustody(bundle.source, custody.bundleid);
306 
307  IBRCOMMON_LOGGER_DEBUG_TAG("BundleCore", 5) << "custody released for " << bundle.toString() << IBRCOMMON_LOGGER_ENDL;
308 
309  delivered = true;
311  // no custody signal available
313  // no payload block available
314  }
315 
316  if (delivered)
317  {
318  // gen a report
320  }
321  else
322  {
323  // gen a report
325  }
326 
328  {
329  // delete the bundle
331  }
332  }
333 
334  return;
335  } catch (const dtn::storage::NoBundleFoundException&) {
336  return;
337  } catch (const std::bad_cast&) {}
338 
339  try {
340  const dtn::net::TransferCompletedEvent &completed = dynamic_cast<const dtn::net::TransferCompletedEvent&>(*evt);
341  const dtn::data::MetaBundle &meta = completed.getBundle();
342  const dtn::data::EID &peer = completed.getPeer();
343 
344  if ((meta.destination.sameHost(peer))
346  {
347  // bundle has been delivered to its destination
348  // delete it from our storage
350 
351  IBRCOMMON_LOGGER_TAG("BundleCore", notice) << "singleton bundle delivered: " << meta.toString() << IBRCOMMON_LOGGER_ENDL;
352 
353  // gen a report
355  }
356 
357  return;
358  } catch (const std::bad_cast&) { }
359 
360  try {
361  const dtn::net::TransferAbortedEvent &aborted = dynamic_cast<const dtn::net::TransferAbortedEvent&>(*evt);
362 
364 
365  const dtn::data::EID &peer = aborted.getPeer();
366  const dtn::data::BundleID &id = aborted.getBundleID();
367 
368  try {
369  // create meta bundle for futher processing
370  const dtn::data::MetaBundle meta = getStorage().info(id);
371 
373 
374  // if the bundle has been sent by this module delete it
375  if (meta.destination.sameHost(peer))
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 
401  {
402  if (dtn::utils::Clock::isExpired(obj)) {
403  // ... bundle is expired
404  IBRCOMMON_LOGGER_DEBUG_TAG("BundleCore", 35) << "bundle rejected: bundle has expired (" << obj.toString() << ")" << IBRCOMMON_LOGGER_ENDL;
405  throw dtn::data::Validator::RejectedException("bundle is expired");
406  }
407 
408  // check if the lifetime of the bundle is too long
409  if (BundleCore::max_lifetime > 0)
410  {
411  if (obj.lifetime > BundleCore::max_lifetime)
412  {
413  // ... we reject bundles with such a long lifetime
414  IBRCOMMON_LOGGER_DEBUG_TAG("BundleCore", 35) << "lifetime of bundle rejected: " << obj.toString() << IBRCOMMON_LOGGER_ENDL;
415  throw dtn::data::Validator::RejectedException("lifetime of the bundle is too long");
416  }
417  }
418 
419  // check if the timestamp is in the future
420  if ((BundleCore::max_timestamp_future > 0) && (obj.timestamp != 0))
421  {
422  // first check if the local clock is reliable
424  // then check the timestamp
426  {
427  // ... we reject bundles with a timestamp so far in the future
428  IBRCOMMON_LOGGER_TAG("BundleCore", warning) << "timestamp of bundle rejected: " << obj.toString() << IBRCOMMON_LOGGER_ENDL;
429  throw dtn::data::Validator::RejectedException("timestamp is too far in the future");
430  }
431  }
432  }
433 
435  {
436  // check if the bundle is expired
437  if (dtn::utils::Clock::isExpired(p.timestamp, p.lifetime))
438  {
439  IBRCOMMON_LOGGER_TAG("BundleCore", warning) << "bundle rejected: bundle has expired (" << p.toString() << ")" << IBRCOMMON_LOGGER_ENDL;
440  throw dtn::data::Validator::RejectedException("bundle is expired");
441  }
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
466  if ((BundleCore::max_timestamp_future > 0) && (p.timestamp != 0))
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.sameHost(dtn::core::BundleCore::local)) {
498  if (!bundle.destination.sameHost(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 bundle expiration again for bundles with age block
528  if ((b.timestamp == 0) && dtn::utils::Clock::isExpired(b))
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 {
538  } catch (const dtn::security::VerificationFailedException &ex) {
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;
585  } catch (const dtn::security::DecryptException &ex) {
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 }