IBR-DTNSuite 0.6

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 "net/TransferAbortedEvent.h"
00006 #include "routing/RequeueBundleEvent.h"
00007 #include "routing/QueueBundleEvent.h"
00008 
00009 #include <ibrcommon/data/BLOB.h>
00010 #include <ibrdtn/data/MetaBundle.h>
00011 #include <ibrdtn/data/Exceptions.h>
00012 #include <ibrdtn/data/EID.h>
00013 #include <ibrdtn/utils/Clock.h>
00014 #include <ibrcommon/Logger.h>
00015 
00016 #include "limits.h"
00017 #include <iostream>
00018 #include <typeinfo>
00019 #include <stdint.h>
00020 
00021 #ifdef WITH_BUNDLE_SECURITY
00022 #include "security/SecurityManager.h"
00023 #include <ibrdtn/security/PayloadConfidentialBlock.h>
00024 #endif
00025 
00026 #ifdef WITH_COMPRESSION
00027 #include <ibrdtn/data/CompressedPayloadBlock.h>
00028 #endif
00029 
00030 using namespace dtn::data;
00031 using namespace dtn::utils;
00032 using namespace std;
00033 
00034 namespace dtn
00035 {
00036         namespace core
00037         {
00038                 dtn::data::EID BundleCore::local;
00039                 size_t BundleCore::blocksizelimit = 0;
00040                 bool BundleCore::forwarding = true;
00041 
00042                 BundleCore& BundleCore::getInstance()
00043                 {
00044                         static BundleCore instance;
00045                         return instance;
00046                 }
00047 
00048                 BundleCore::BundleCore()
00049                  : _clock(1), _storage(NULL)
00050                 {
00054                         if (dtn::utils::Clock::getTime() > 0)
00055                         {
00056                                 dtn::utils::Clock::quality = 1;
00057                         }
00058                         else
00059                         {
00060                                 IBRCOMMON_LOGGER(warning) << "The local clock seems to be wrong. Expiration disabled." << IBRCOMMON_LOGGER_ENDL;
00061                         }
00062 
00063                         bindEvent(dtn::routing::QueueBundleEvent::className);
00064                 }
00065 
00066                 BundleCore::~BundleCore()
00067                 {
00068                         unbindEvent(dtn::routing::QueueBundleEvent::className);
00069                 }
00070 
00071                 void BundleCore::componentUp()
00072                 {
00073                         _connectionmanager.initialize();
00074                         _clock.initialize();
00075 
00076                         // start a clock
00077                         _clock.startup();
00078                 }
00079 
00080                 void BundleCore::componentDown()
00081                 {
00082                         _connectionmanager.terminate();
00083                         _clock.terminate();
00084                 }
00085 
00086                 void BundleCore::setStorage(dtn::core::BundleStorage *storage)
00087                 {
00088                         _storage = storage;
00089                 }
00090 
00091                 dtn::core::BundleStorage& BundleCore::getStorage()
00092                 {
00093                         if (_storage == NULL)
00094                         {
00095                                 throw ibrcommon::Exception("No bundle storage is set! Use BundleCore::setStorage() to set a storage.");
00096                         }
00097                         return *_storage;
00098                 }
00099 
00100                 WallClock& BundleCore::getClock()
00101                 {
00102                         return _clock;
00103                 }
00104 
00105                 void BundleCore::transferTo(const dtn::data::EID &destination, const dtn::data::BundleID &bundle)
00106                 {
00107                         try {
00108                                 _connectionmanager.queue(destination, bundle);
00109                         } catch (const dtn::net::NeighborNotAvailableException &ex) {
00110                                 // signal interruption of the transfer
00111                                 dtn::net::TransferAbortedEvent::raise(destination, bundle, dtn::net::TransferAbortedEvent::REASON_CONNECTION_DOWN);
00112                         } catch (const dtn::net::ConnectionNotAvailableException &ex) {
00113                                 // signal interruption of the transfer
00114                                 dtn::routing::RequeueBundleEvent::raise(destination, bundle);
00115                         } catch (const ibrcommon::Exception&) {
00116                                 dtn::routing::RequeueBundleEvent::raise(destination, bundle);
00117                         }
00118                 }
00119 
00120                 void BundleCore::addConvergenceLayer(dtn::net::ConvergenceLayer *cl)
00121                 {
00122                         _connectionmanager.addConvergenceLayer(cl);
00123                 }
00124 
00125                 void BundleCore::addConnection(const dtn::core::Node &n)
00126                 {
00127                         _connectionmanager.addConnection(n);
00128                 }
00129 
00130                 void BundleCore::removeConnection(const dtn::core::Node &n)
00131                 {
00132                         _connectionmanager.removeConnection(n);
00133                 }
00134 
00135                 const std::set<dtn::core::Node> BundleCore::getNeighbors()
00136                 {
00137                         return _connectionmanager.getNeighbors();
00138                 }
00139 
00140                 void BundleCore::raiseEvent(const dtn::core::Event *evt)
00141                 {
00142                         try {
00143                                 const dtn::routing::QueueBundleEvent &queued = dynamic_cast<const dtn::routing::QueueBundleEvent&>(*evt);
00144                                 const dtn::data::MetaBundle &meta = queued.bundle;
00145 
00146                                 if (meta.destination == local)
00147                                 {
00148                                         // if the delivered variable is still false at the end of this block.
00149                                         // we send a not delivered report.
00150                                         bool delivered = false;
00151 
00152                                         // process this bundle locally
00153                                         dtn::data::Bundle bundle = getStorage().get(meta);
00154 
00155                                         try {
00156                                                 // check for a custody signal
00157                                                 dtn::data::CustodySignalBlock custody = bundle.getBlock<dtn::data::CustodySignalBlock>();
00158                                                 dtn::data::BundleID id(custody._source, custody._bundle_timestamp.getValue(), custody._bundle_sequence.getValue(), (custody._fragment_length.getValue() > 0), custody._fragment_offset.getValue());
00159                                                 getStorage().releaseCustody(bundle._source, id);
00160 
00161                                                 IBRCOMMON_LOGGER_DEBUG(5) << "custody released for " << bundle.toString() << IBRCOMMON_LOGGER_ENDL;
00162 
00163                                                 delivered = true;
00164                                         } catch (const dtn::data::Bundle::NoSuchBlockFoundException&) {
00165                                                 // no custody signal available
00166                                         }
00167 
00168                                         if (delivered)
00169                                         {
00170                                                 // gen a report
00171                                                 dtn::core::BundleEvent::raise(meta, BUNDLE_DELIVERED);
00172                                         }
00173                                         else
00174                                         {
00175                                                 // gen a report
00176                                                 dtn::core::BundleEvent::raise(meta, BUNDLE_DELETED, StatusReportBlock::DESTINATION_ENDPOINT_ID_UNINTELLIGIBLE);
00177                                         }
00178 
00179                                         // delete the bundle
00180                                         getStorage().remove(meta);
00181                                 }
00182                         } catch (const dtn::core::BundleStorage::NoBundleFoundException&) {
00183                         } catch (const std::bad_cast&) {}
00184                 }
00185 
00186                 void BundleCore::validate(const dtn::data::PrimaryBlock &p) const throw (dtn::data::Validator::RejectedException)
00187                 {
00188                         /*
00189                          *
00190                          * TODO: reject a bundle if...
00191                          * ... it is expired (moved to validate(Bundle) to support AgeBlock for expiration)
00192                          * ... already in the storage
00193                          * ... a fragment of an already received bundle in the storage
00194                          *
00195                          * throw dtn::data::DefaultDeserializer::RejectedException();
00196                          *
00197                          */
00198 
00199                         // if we do not forward bundles
00200                         if (!BundleCore::forwarding)
00201                         {
00202                                 if (!p._destination.sameHost(BundleCore::local))
00203                                 {
00204                                         // ... we reject all non-local bundles.
00205                                         IBRCOMMON_LOGGER(warning) << "non-local bundle rejected: " << p.toString() << IBRCOMMON_LOGGER_ENDL;
00206                                         throw dtn::data::Validator::RejectedException("bundle is not local");
00207                                 }
00208                         }
00209                 }
00210 
00211                 void BundleCore::validate(const dtn::data::Block&, const size_t size) const throw (dtn::data::Validator::RejectedException)
00212                 {
00213                         /*
00214                          *
00215                          * reject a block if
00216                          * ... it exceeds the payload limit
00217                          *
00218                          * throw dtn::data::DefaultDeserializer::RejectedException();
00219                          *
00220                          */
00221 
00222                         // check for the size of the block
00223                         if ((BundleCore::blocksizelimit > 0) && (size > BundleCore::blocksizelimit))
00224                         {
00225                                 IBRCOMMON_LOGGER(warning) << "bundle rejected: block size of " << size << " is too big" << IBRCOMMON_LOGGER_ENDL;
00226                                 throw dtn::data::Validator::RejectedException("block size is too big");
00227                         }
00228                 }
00229 
00230                 void BundleCore::validate(const dtn::data::Bundle &b) const throw (dtn::data::Validator::RejectedException)
00231                 {
00232                         /*
00233                          *
00234                          * TODO: reject a bundle if
00235                          * ... the security checks (DTNSEC) failed
00236                          * ... a checksum mismatch is detected (CRC)
00237                          *
00238                          * throw dtn::data::DefaultDeserializer::RejectedException();
00239                          *
00240                          */
00241 
00242                         // check if the bundle is expired
00243                         if (dtn::utils::Clock::isExpired(b))
00244                         {
00245                                 IBRCOMMON_LOGGER(warning) << "bundle rejected: bundle has expired (" << b.toString() << ")" << IBRCOMMON_LOGGER_ENDL;
00246                                 throw dtn::data::Validator::RejectedException("bundle is expired");
00247                         }
00248 
00249 #ifdef WITH_BUNDLE_SECURITY
00250                         // do a fast security check
00251                         try {
00252                                 dtn::security::SecurityManager::getInstance().fastverify(b);
00253                         } catch (const dtn::security::SecurityManager::VerificationFailedException &ex) {
00254                                 IBRCOMMON_LOGGER(notice) << "bundle rejected: security checks failed: " << b.toString() << IBRCOMMON_LOGGER_ENDL;
00255                                 throw dtn::data::Validator::RejectedException("security checks failed");
00256                         }
00257 #endif
00258 
00259                         // check for invalid blocks
00260                         const std::list<const dtn::data::Block*> bl = b.getBlocks();
00261                         for (std::list<const dtn::data::Block*>::const_iterator iter = bl.begin(); iter != bl.end(); iter++)
00262                         {
00263                                 try {
00264                                         const dtn::data::ExtensionBlock &e = dynamic_cast<const dtn::data::ExtensionBlock&>(**iter);
00265 
00266                                         if (e.get(dtn::data::Block::DELETE_BUNDLE_IF_NOT_PROCESSED))
00267                                         {
00268                                                 // reject the hole bundle
00269                                                 throw dtn::data::Validator::RejectedException("bundle contains unintelligible blocks");
00270                                         }
00271 
00272                                         if (e.get(dtn::data::Block::TRANSMIT_STATUSREPORT_IF_NOT_PROCESSED))
00273                                         {
00274                                                 // transmit status report, because we can not process this block
00275                                                 dtn::core::BundleEvent::raise(b, BUNDLE_RECEIVED, dtn::data::StatusReportBlock::BLOCK_UNINTELLIGIBLE);
00276                                         }
00277                                 } catch (const std::bad_cast&) { }
00278                         }
00279                 }
00280 
00281                 const std::string BundleCore::getName() const
00282                 {
00283                         return "BundleCore";
00284                 }
00285 
00286                 void BundleCore::processBlocks(dtn::data::Bundle &b)
00287                 {
00288                         // walk through the block and process them when needed
00289                         const std::list<const dtn::data::Block*> blist = b.getBlocks();
00290 
00291                         for (std::list<const dtn::data::Block*>::const_iterator iter = blist.begin(); iter != blist.end(); iter++)
00292                         {
00293                                 const dtn::data::Block &block = (**iter);
00294                                 switch (block.getType())
00295                                 {
00296 #ifdef WITH_BUNDLE_SECURITY
00297                                         case dtn::security::PayloadConfidentialBlock::BLOCK_TYPE:
00298                                         {
00299                                                 // try to decrypt the bundle
00300                                                 try {
00301                                                         dtn::security::SecurityManager::getInstance().decrypt(b);
00302                                                 } catch (const dtn::security::SecurityManager::KeyMissingException&) {
00303                                                         // decrypt needed, but no key is available
00304                                                         IBRCOMMON_LOGGER(warning) << "No key available for decrypt bundle." << IBRCOMMON_LOGGER_ENDL;
00305                                                 } catch (const dtn::security::SecurityManager::DecryptException &ex) {
00306                                                         // decrypt failed
00307                                                         IBRCOMMON_LOGGER(warning) << "Decryption of bundle failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
00308                                                 }
00309                                         }
00310 #endif
00311 
00312 #ifdef WITH_COMPRESSION
00313                                         case dtn::data::CompressedPayloadBlock::BLOCK_TYPE:
00314                                         {
00315                                                 // try to decompress the bundle
00316                                                 try {
00317                                                         dtn::data::CompressedPayloadBlock::extract(b);
00318                                                 } catch (const ibrcommon::Exception&) { };
00319                                         }
00320 #endif
00321                                 }
00322                         }
00323                 }
00324         }
00325 }