IBR-DTNSuite  0.8
daemon/src/core/BundleCore.cpp
Go to the documentation of this file.
00001 #include "config.h"
00002 #include "core/BundleCore.h"
00003 #include "core/GlobalEvent.h"
00004 #include "core/BundleEvent.h"
00005 #include "core/BundlePurgeEvent.h"
00006 #include "net/TransferAbortedEvent.h"
00007 #include "routing/RequeueBundleEvent.h"
00008 #include "routing/QueueBundleEvent.h"
00009 #include "routing/StaticRouteChangeEvent.h"
00010 
00011 #include <ibrcommon/data/BLOB.h>
00012 #include <ibrdtn/data/MetaBundle.h>
00013 #include <ibrdtn/data/Exceptions.h>
00014 #include <ibrdtn/data/EID.h>
00015 #include <ibrdtn/utils/Clock.h>
00016 #include <ibrcommon/Logger.h>
00017 
00018 #include "limits.h"
00019 #include <iostream>
00020 #include <typeinfo>
00021 #include <stdint.h>
00022 
00023 #ifdef WITH_BUNDLE_SECURITY
00024 #include "security/SecurityManager.h"
00025 #include <ibrdtn/security/PayloadConfidentialBlock.h>
00026 #endif
00027 
00028 #ifdef WITH_COMPRESSION
00029 #include <ibrdtn/data/CompressedPayloadBlock.h>
00030 #endif
00031 
00032 using namespace dtn::data;
00033 using namespace dtn::utils;
00034 using namespace std;
00035 
00036 namespace dtn
00037 {
00038         namespace core
00039         {
00040                 dtn::data::EID BundleCore::local;
00041 
00042                 size_t BundleCore::blocksizelimit = 0;
00043                 size_t BundleCore::max_lifetime = 0;
00044                 size_t BundleCore::max_timestamp_future = 0;
00045 
00046                 bool BundleCore::forwarding = true;
00047 
00048                 BundleCore& BundleCore::getInstance()
00049                 {
00050                         static BundleCore instance;
00051                         return instance;
00052                 }
00053 
00054                 BundleCore::BundleCore()
00055                  : _clock(1), _storage(NULL), _router(NULL)
00056                 {
00060                         if (dtn::utils::Clock::getTime() > 0)
00061                         {
00062                                 dtn::utils::Clock::quality = 1;
00063                         }
00064                         else
00065                         {
00066                                 IBRCOMMON_LOGGER(warning) << "The local clock seems to be wrong. Expiration disabled." << IBRCOMMON_LOGGER_ENDL;
00067                         }
00068 
00069                         bindEvent(dtn::routing::QueueBundleEvent::className);
00070                         bindEvent(dtn::core::BundlePurgeEvent::className);
00071                 }
00072 
00073                 BundleCore::~BundleCore()
00074                 {
00075                         unbindEvent(dtn::routing::QueueBundleEvent::className);
00076                         unbindEvent(dtn::core::BundlePurgeEvent::className);
00077                 }
00078 
00079                 void BundleCore::componentUp()
00080                 {
00081                         _connectionmanager.initialize();
00082                         _clock.initialize();
00083 
00084                         // start a clock
00085                         _clock.startup();
00086                 }
00087 
00088                 void BundleCore::componentDown()
00089                 {
00090                         _connectionmanager.terminate();
00091                         _clock.terminate();
00092                 }
00093 
00094                 void BundleCore::setStorage(dtn::storage::BundleStorage *storage)
00095                 {
00096                         _storage = storage;
00097                 }
00098 
00099                 void BundleCore::setRouter(dtn::routing::BaseRouter *router)
00100                 {
00101                         _router = router;
00102                 }
00103 
00104                 dtn::routing::BaseRouter& BundleCore::getRouter() const
00105                 {
00106                         if (_router == NULL)
00107                         {
00108                                 throw ibrcommon::Exception("router not set");
00109                         }
00110 
00111                         return *_router;
00112                 }
00113 
00114                 dtn::storage::BundleStorage& BundleCore::getStorage()
00115                 {
00116                         if (_storage == NULL)
00117                         {
00118                                 throw ibrcommon::Exception("No bundle storage is set! Use BundleCore::setStorage() to set a storage.");
00119                         }
00120                         return *_storage;
00121                 }
00122 
00123                 WallClock& BundleCore::getClock()
00124                 {
00125                         return _clock;
00126                 }
00127 
00128                 void BundleCore::transferTo(const dtn::data::EID &destination, const dtn::data::BundleID &bundle)
00129                 {
00130                         try {
00131                                 _connectionmanager.queue(destination, bundle);
00132                         } catch (const dtn::net::NeighborNotAvailableException &ex) {
00133                                 // signal interruption of the transfer
00134                                 dtn::net::TransferAbortedEvent::raise(destination, bundle, dtn::net::TransferAbortedEvent::REASON_CONNECTION_DOWN);
00135                         } catch (const dtn::net::ConnectionNotAvailableException &ex) {
00136                                 // signal interruption of the transfer
00137                                 dtn::routing::RequeueBundleEvent::raise(destination, bundle);
00138                         } catch (const ibrcommon::Exception&) {
00139                                 dtn::routing::RequeueBundleEvent::raise(destination, bundle);
00140                         }
00141                 }
00142 
00143                 void BundleCore::addConvergenceLayer(dtn::net::ConvergenceLayer *cl)
00144                 {
00145                         _connectionmanager.addConvergenceLayer(cl);
00146                 }
00147 
00148                 void BundleCore::addConnection(const dtn::core::Node &n)
00149                 {
00150                         _connectionmanager.addConnection(n);
00151                 }
00152 
00153                 void BundleCore::removeConnection(const dtn::core::Node &n)
00154                 {
00155                         _connectionmanager.removeConnection(n);
00156                 }
00157 
00158                 void BundleCore::addRoute(const dtn::data::EID &destination, const dtn::data::EID &nexthop, size_t timeout)
00159                 {
00160                         dtn::routing::StaticRouteChangeEvent::raiseEvent(dtn::routing::StaticRouteChangeEvent::ROUTE_ADD, nexthop, destination, timeout);
00161                 }
00162 
00163                 void BundleCore::removeRoute(const dtn::data::EID &destination, const dtn::data::EID &nexthop)
00164                 {
00165                         dtn::routing::StaticRouteChangeEvent::raiseEvent(dtn::routing::StaticRouteChangeEvent::ROUTE_DEL, nexthop, destination);
00166                 }
00167 
00168                 const std::set<dtn::core::Node> BundleCore::getNeighbors()
00169                 {
00170                         return _connectionmanager.getNeighbors();
00171                 }
00172 
00173                 bool BundleCore::isNeighbor(const dtn::core::Node &node)
00174                 {
00175                         return _connectionmanager.isNeighbor(node);
00176                 }
00177 
00178                 const dtn::core::Node BundleCore::getNeighbor(const dtn::data::EID &eid)
00179                 {
00180                         return _connectionmanager.getNeighbor(eid);
00181                 }
00182 
00183                 void BundleCore::raiseEvent(const dtn::core::Event *evt)
00184                 {
00185                         try {
00186                                 const dtn::routing::QueueBundleEvent &queued = dynamic_cast<const dtn::routing::QueueBundleEvent&>(*evt);
00187 
00188                                 // get reference to the meta data of the bundle
00189                                 const dtn::data::MetaBundle &meta = queued.bundle;
00190 
00191                                 // ignore fragments
00192                                 if (meta.fragment) return;
00193 
00194                                 // if the destination is equal this node...
00195                                 if (meta.destination == local)
00196                                 {
00197                                         // if the delivered variable is still false at the end of this block,
00198                                         // we discard the bundle
00199                                         bool delivered = false;
00200 
00201                                         // process this bundle locally
00202                                         dtn::data::Bundle bundle = getStorage().get(meta);
00203 
00204                                         try {
00205                                                 // check for a custody signal
00206                                                 dtn::data::CustodySignalBlock custody = bundle.getBlock<dtn::data::CustodySignalBlock>();
00207                                                 dtn::data::BundleID id(custody._source, custody._bundle_timestamp.getValue(), custody._bundle_sequence.getValue(), (custody._fragment_length.getValue() > 0), custody._fragment_offset.getValue());
00208                                                 getStorage().releaseCustody(bundle._source, id);
00209 
00210                                                 IBRCOMMON_LOGGER_DEBUG(5) << "custody released for " << bundle.toString() << IBRCOMMON_LOGGER_ENDL;
00211 
00212                                                 delivered = true;
00213                                         } catch (const dtn::data::Bundle::NoSuchBlockFoundException&) {
00214                                                 // no custody signal available
00215                                         }
00216 
00217                                         if (delivered)
00218                                         {
00219                                                 // gen a report
00220                                                 dtn::core::BundleEvent::raise(meta, BUNDLE_DELIVERED);
00221                                         }
00222                                         else
00223                                         {
00224                                                 // gen a report
00225                                                 dtn::core::BundleEvent::raise(meta, BUNDLE_DELETED, StatusReportBlock::DESTINATION_ENDPOINT_ID_UNINTELLIGIBLE);
00226                                         }
00227 
00228                                         // delete the bundle
00229                                         dtn::core::BundlePurgeEvent::raise(meta);
00230                                 }
00231 
00232                                 return;
00233                         } catch (const dtn::storage::BundleStorage::NoBundleFoundException&) {
00234                         } catch (const std::bad_cast&) {}
00235 
00236                         try {
00237                                 const dtn::core::BundlePurgeEvent &purge = dynamic_cast<const dtn::core::BundlePurgeEvent&>(*evt);
00238 
00239                                 // get the global storage
00240                                 dtn::storage::BundleStorage &storage = dtn::core::BundleCore::getInstance().getStorage();
00241 
00242                                 // delete the bundle
00243                                 storage.remove(purge.bundle);
00244 
00245                                 return;
00246                         } catch (const std::bad_cast&) { }
00247                 }
00248 
00249                 void BundleCore::validate(const dtn::data::PrimaryBlock &p) const throw (dtn::data::Validator::RejectedException)
00250                 {
00251                         /*
00252                          *
00253                          * TODO: reject a bundle if...
00254                          * ... it is expired (moved to validate(Bundle) to support AgeBlock for expiration)
00255                          * ... already in the storage
00256                          * ... a fragment of an already received bundle in the storage
00257                          *
00258                          * throw dtn::data::DefaultDeserializer::RejectedException();
00259                          *
00260                          */
00261 
00262                         // if we do not forward bundles
00263                         if (!BundleCore::forwarding)
00264                         {
00265                                 if (!p._destination.sameHost(BundleCore::local))
00266                                 {
00267                                         // ... we reject all non-local bundles.
00268                                         IBRCOMMON_LOGGER(warning) << "non-local bundle rejected: " << p.toString() << IBRCOMMON_LOGGER_ENDL;
00269                                         throw dtn::data::Validator::RejectedException("bundle is not local");
00270                                 }
00271                         }
00272 
00273                         // check if the lifetime of the bundle is too long
00274                         if (BundleCore::max_lifetime > 0)
00275                         {
00276                                 if (p._lifetime > BundleCore::max_lifetime)
00277                                 {
00278                                         // ... we reject bundles with such a long lifetime
00279                                         IBRCOMMON_LOGGER(warning) << "lifetime of bundle rejected: " << p.toString() << IBRCOMMON_LOGGER_ENDL;
00280                                         throw dtn::data::Validator::RejectedException("lifetime of the bundle is too long");
00281                                 }
00282                         }
00283 
00284                         // check if the timestamp is in the future
00285                         if (BundleCore::max_timestamp_future > 0)
00286                         {
00287                                 // first check if the local clock is reliable
00288                                 if (dtn::utils::Clock::quality > 0)
00289                                         // then check the timestamp
00290                                         if ((dtn::utils::Clock::getTime() + BundleCore::max_timestamp_future) < p._timestamp)
00291                                         {
00292                                                 // ... we reject bundles with a timestamp so far in the future
00293                                                 IBRCOMMON_LOGGER(warning) << "timestamp of bundle rejected: " << p.toString() << IBRCOMMON_LOGGER_ENDL;
00294                                                 throw dtn::data::Validator::RejectedException("timestamp is too far in the future");
00295                                         }
00296                         }
00297                 }
00298 
00299                 void BundleCore::validate(const dtn::data::Block&, const size_t size) const throw (dtn::data::Validator::RejectedException)
00300                 {
00301                         /*
00302                          *
00303                          * reject a block if
00304                          * ... it exceeds the payload limit
00305                          *
00306                          * throw dtn::data::DefaultDeserializer::RejectedException();
00307                          *
00308                          */
00309 
00310                         // check for the size of the block
00311                         if ((BundleCore::blocksizelimit > 0) && (size > BundleCore::blocksizelimit))
00312                         {
00313                                 IBRCOMMON_LOGGER(warning) << "bundle rejected: block size of " << size << " is too big" << IBRCOMMON_LOGGER_ENDL;
00314                                 throw dtn::data::Validator::RejectedException("block size is too big");
00315                         }
00316                 }
00317 
00318                 void BundleCore::validate(const dtn::data::Bundle &b) const throw (dtn::data::Validator::RejectedException)
00319                 {
00320                         /*
00321                          *
00322                          * TODO: reject a bundle if
00323                          * ... the security checks (DTNSEC) failed
00324                          * ... a checksum mismatch is detected (CRC)
00325                          *
00326                          * throw dtn::data::DefaultDeserializer::RejectedException();
00327                          *
00328                          */
00329 
00330                         // check if the bundle is expired
00331                         if (dtn::utils::Clock::isExpired(b))
00332                         {
00333                                 IBRCOMMON_LOGGER(warning) << "bundle rejected: bundle has expired (" << b.toString() << ")" << IBRCOMMON_LOGGER_ENDL;
00334                                 throw dtn::data::Validator::RejectedException("bundle is expired");
00335                         }
00336 
00337 #ifdef WITH_BUNDLE_SECURITY
00338                         // do a fast security check
00339                         try {
00340                                 dtn::security::SecurityManager::getInstance().fastverify(b);
00341                         } catch (const dtn::security::SecurityManager::VerificationFailedException &ex) {
00342                                 IBRCOMMON_LOGGER(notice) << "bundle rejected: security checks failed: " << b.toString() << IBRCOMMON_LOGGER_ENDL;
00343                                 throw dtn::data::Validator::RejectedException("security checks failed");
00344                         }
00345 #endif
00346 
00347                         // check for invalid blocks
00348                         const std::list<const dtn::data::Block*> bl = b.getBlocks();
00349                         for (std::list<const dtn::data::Block*>::const_iterator iter = bl.begin(); iter != bl.end(); iter++)
00350                         {
00351                                 try {
00352                                         const dtn::data::ExtensionBlock &e = dynamic_cast<const dtn::data::ExtensionBlock&>(**iter);
00353 
00354                                         if (e.get(dtn::data::Block::DELETE_BUNDLE_IF_NOT_PROCESSED))
00355                                         {
00356                                                 // reject the hole bundle
00357                                                 throw dtn::data::Validator::RejectedException("bundle contains unintelligible blocks");
00358                                         }
00359 
00360                                         if (e.get(dtn::data::Block::TRANSMIT_STATUSREPORT_IF_NOT_PROCESSED))
00361                                         {
00362                                                 // transmit status report, because we can not process this block
00363                                                 dtn::core::BundleEvent::raise(b, BUNDLE_RECEIVED, dtn::data::StatusReportBlock::BLOCK_UNINTELLIGIBLE);
00364                                         }
00365                                 } catch (const std::bad_cast&) { }
00366                         }
00367                 }
00368 
00369                 const std::string BundleCore::getName() const
00370                 {
00371                         return "BundleCore";
00372                 }
00373 
00374                 void BundleCore::processBlocks(dtn::data::Bundle &b)
00375                 {
00376                         // walk through the block and process them when needed
00377                         const std::list<const dtn::data::Block*> blist = b.getBlocks();
00378 
00379                         for (std::list<const dtn::data::Block*>::const_iterator iter = blist.begin(); iter != blist.end(); iter++)
00380                         {
00381                                 const dtn::data::Block &block = (**iter);
00382                                 switch (block.getType())
00383                                 {
00384 #ifdef WITH_BUNDLE_SECURITY
00385                                         case dtn::security::PayloadConfidentialBlock::BLOCK_TYPE:
00386                                         {
00387                                                 // try to decrypt the bundle
00388                                                 try {
00389                                                         dtn::security::SecurityManager::getInstance().decrypt(b);
00390                                                 } catch (const dtn::security::SecurityManager::KeyMissingException&) {
00391                                                         // decrypt needed, but no key is available
00392                                                         IBRCOMMON_LOGGER(warning) << "No key available for decrypt bundle." << IBRCOMMON_LOGGER_ENDL;
00393                                                 } catch (const dtn::security::SecurityManager::DecryptException &ex) {
00394                                                         // decrypt failed
00395                                                         IBRCOMMON_LOGGER(warning) << "Decryption of bundle failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
00396                                                 }
00397                                                 break;
00398                                         }
00399 #endif
00400 
00401 #ifdef WITH_COMPRESSION
00402                                         case dtn::data::CompressedPayloadBlock::BLOCK_TYPE:
00403                                         {
00404                                                 // try to decompress the bundle
00405                                                 try {
00406                                                         dtn::data::CompressedPayloadBlock::extract(b);
00407                                                 } catch (const ibrcommon::Exception&) { };
00408                                                 break;
00409                                         }
00410 #endif
00411                                 }
00412                         }
00413                 }
00414         }
00415 }