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