IBR-DTNSuite
0.8
|
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 }