IBR-DTNSuite  0.8
daemon/src/routing/StaticRoutingExtension.cpp
Go to the documentation of this file.
00001 /*
00002  * StaticRoutingExtension.cpp
00003  *
00004  *  Created on: 16.02.2010
00005  *      Author: morgenro
00006  */
00007 
00008 #include "Configuration.h"
00009 #include "routing/StaticRoutingExtension.h"
00010 #include "routing/QueueBundleEvent.h"
00011 #include "routing/StaticRouteChangeEvent.h"
00012 #include "net/TransferAbortedEvent.h"
00013 #include "net/TransferCompletedEvent.h"
00014 #include "net/ConnectionEvent.h"
00015 #include "routing/RequeueBundleEvent.h"
00016 #include "core/NodeEvent.h"
00017 #include "storage/SimpleBundleStorage.h"
00018 #include "core/TimeEvent.h"
00019 
00020 #include <ibrdtn/utils/Clock.h>
00021 
00022 #include <ibrcommon/Logger.h>
00023 #include <ibrcommon/thread/MutexLock.h>
00024 
00025 #include <typeinfo>
00026 #include <memory>
00027 
00028 namespace dtn
00029 {
00030         namespace routing
00031         {
00032                 StaticRoutingExtension::StaticRoutingExtension()
00033                  : next_expire(0)
00034                 {
00035                 }
00036 
00037                 StaticRoutingExtension::~StaticRoutingExtension()
00038                 {
00039                         stop();
00040                         join();
00041 
00042                         // delete all static routes
00043                         for (std::list<StaticRoute*>::iterator iter = _routes.begin();
00044                                         iter != _routes.end(); iter++)
00045                         {
00046                                 StaticRoute *route = (*iter);
00047                                 delete route;
00048                         }
00049                 }
00050 
00051                 void StaticRoutingExtension::__cancellation()
00052                 {
00053                         _taskqueue.abort();
00054                 }
00055 
00056                 void StaticRoutingExtension::run()
00057                 {
00058                         class BundleFilter : public dtn::storage::BundleStorage::BundleFilterCallback
00059                         {
00060                         public:
00061                                 BundleFilter(const NeighborDatabase::NeighborEntry &entry, const std::list<const StaticRoute*> &routes)
00062                                  : _entry(entry), _routes(routes)
00063                                 {};
00064 
00065                                 virtual ~BundleFilter() {};
00066 
00067                                 virtual size_t limit() const { return 10; };
00068 
00069                                 virtual bool shouldAdd(const dtn::data::MetaBundle &meta) const
00070                                 {
00071                                         // check Scope Control Block - do not forward bundles with hop limit == 0
00072                                         if (meta.hopcount == 0)
00073                                         {
00074                                                 return false;
00075                                         }
00076 
00077                                         // do not forward any routing control message
00078                                         // this is done by the neighbor routing module
00079                                         if (isRouting(meta.source))
00080                                         {
00081                                                 return false;
00082                                         }
00083 
00084                                         // do not forward local bundles
00085                                         if ((meta.destination.getNode() == dtn::core::BundleCore::local)
00086                                                         && meta.get(dtn::data::PrimaryBlock::DESTINATION_IS_SINGLETON)
00087                                                 )
00088                                         {
00089                                                 return false;
00090                                         }
00091 
00092                                         // check Scope Control Block - do not forward non-group bundles with hop limit <= 1
00093                                         if ((meta.hopcount <= 1) && (meta.get(dtn::data::PrimaryBlock::DESTINATION_IS_SINGLETON)))
00094                                         {
00095                                                 return false;
00096                                         }
00097 
00098                                         // do not forward to any blacklisted destination
00099                                         const dtn::data::EID dest = meta.destination.getNode();
00100                                         if (_blacklist.find(dest) != _blacklist.end())
00101                                         {
00102                                                 return false;
00103                                         }
00104 
00105                                         // do not forward bundles already known by the destination
00106                                         if (_entry.has(meta))
00107                                         {
00108                                                 return false;
00109                                         }
00110 
00111                                         // search for one rule that match
00112                                         for (std::list<const StaticRoute*>::const_iterator iter = _routes.begin();
00113                                                         iter != _routes.end(); iter++)
00114                                         {
00115                                                 const StaticRoute &route = (**iter);
00116 
00117                                                 if (route.match(meta.destination))
00118                                                 {
00119                                                         return true;
00120                                                 }
00121                                         }
00122 
00123                                         return false;
00124                                 };
00125 
00126                                 void blacklist(const dtn::data::EID& id)
00127                                 {
00128                                         _blacklist.insert(id);
00129                                 };
00130 
00131                         private:
00132                                 std::set<dtn::data::EID> _blacklist;
00133                                 const NeighborDatabase::NeighborEntry &_entry;
00134                                 const std::list<const StaticRoute*> _routes;
00135                         };
00136 
00137                         // announce static routes here
00138                         const std::multimap<std::string, std::string> &routes = dtn::daemon::Configuration::getInstance().getNetwork().getStaticRoutes();
00139 
00140                         for (std::multimap<std::string, std::string>::const_iterator iter = routes.begin(); iter != routes.end(); iter++)
00141                         {
00142                                 const dtn::data::EID nexthop((*iter).second);
00143                                 dtn::routing::StaticRouteChangeEvent::raiseEvent(dtn::routing::StaticRouteChangeEvent::ROUTE_ADD, nexthop, (*iter).first);
00144                         }
00145 
00146                         dtn::storage::BundleStorage &storage = (**this).getStorage();
00147 
00148                         while (true)
00149                         {
00150                                 NeighborDatabase &db = (**this).getNeighborDB();
00151 
00152                                 try {
00153                                         Task *t = _taskqueue.getnpop(true);
00154                                         std::auto_ptr<Task> killer(t);
00155 
00156                                         IBRCOMMON_LOGGER_DEBUG(5) << "processing static routing task " << t->toString() << IBRCOMMON_LOGGER_ENDL;
00157 
00158                                         try {
00159                                                 SearchNextBundleTask &task = dynamic_cast<SearchNextBundleTask&>(*t);
00160 
00161                                                 std::list<const StaticRoute*> routes;
00162 
00163                                                 // look for routes to this node
00164                                                 for (std::list<StaticRoute*>::const_iterator iter = _routes.begin();
00165                                                                 iter != _routes.end(); iter++)
00166                                                 {
00167                                                         const StaticRoute *route = (*iter);
00168                                                         if (route->getDestination() == task.eid)
00169                                                         {
00170                                                                 // add to the valid routes
00171                                                                 routes.push_back(route);
00172                                                         }
00173                                                 }
00174 
00175                                                 if (routes.size() > 0)
00176                                                 {
00177                                                         // this destination is not handles by any static route
00178                                                         ibrcommon::MutexLock l(db);
00179                                                         NeighborDatabase::NeighborEntry &entry = db.get(task.eid);
00180 
00181                                                         // get the bundle filter of the neighbor
00182                                                         BundleFilter filter(entry, routes);
00183 
00184                                                         // some debug
00185                                                         IBRCOMMON_LOGGER_DEBUG(40) << "search some bundles not known by " << task.eid.getString() << IBRCOMMON_LOGGER_ENDL;
00186 
00187                                                         // blacklist the neighbor itself, because this is handled by neighbor routing extension
00188                                                         filter.blacklist(task.eid);
00189 
00190                                                         // query all bundles from the storage
00191                                                         const std::list<dtn::data::MetaBundle> list = storage.get(filter);
00192 
00193                                                         // send the bundles as long as we have resources
00194                                                         for (std::list<dtn::data::MetaBundle>::const_iterator iter = list.begin(); iter != list.end(); iter++)
00195                                                         {
00196                                                                 try {
00197                                                                         // transfer the bundle to the neighbor
00198                                                                         transferTo(entry, *iter);
00199                                                                 } catch (const NeighborDatabase::AlreadyInTransitException&) { };
00200                                                         }
00201                                                 }
00202                                         } catch (const NeighborDatabase::NoMoreTransfersAvailable&) {
00203                                         } catch (const NeighborDatabase::NeighborNotAvailableException&) {
00204                                         } catch (const std::bad_cast&) { };
00205 
00206                                         try {
00207                                                 const ProcessBundleTask &task = dynamic_cast<ProcessBundleTask&>(*t);
00208                                                 IBRCOMMON_LOGGER_DEBUG(50) << "search static route for " << task.bundle.toString() << IBRCOMMON_LOGGER_ENDL;
00209 
00210                                                 // look for routes to this node
00211                                                 for (std::list<StaticRoutingExtension::StaticRoute*>::const_iterator iter = _routes.begin();
00212                                                                 iter != _routes.end(); iter++)
00213                                                 {
00214                                                         const StaticRoutingExtension::StaticRoute &route = (**iter);
00215                                                         IBRCOMMON_LOGGER_DEBUG(50) << "check static route: " << route.toString() << IBRCOMMON_LOGGER_ENDL;
00216                                                         try {
00217                                                                 if (route.match(task.bundle.destination))
00218                                                                 {
00219                                                                         ibrcommon::MutexLock l(db);
00220                                                                         NeighborDatabase::NeighborEntry &n = db.get(route.getDestination());
00221 
00222                                                                         // transfer the bundle to the neighbor
00223                                                                         transferTo(n, task.bundle);
00224                                                                 }
00225                                                         } catch (const NeighborDatabase::NeighborNotAvailableException&) {
00226                                                                 // neighbor is not available, can not forward this bundle
00227                                                         } catch (const NeighborDatabase::NoMoreTransfersAvailable&) {
00228                                                         } catch (const NeighborDatabase::AlreadyInTransitException&) { };
00229                                                 }
00230                                         } catch (const std::bad_cast&) { };
00231 
00232                                         try {
00233                                                 const RouteChangeTask &task = dynamic_cast<RouteChangeTask&>(*t);
00234 
00235                                                 // delete all similar routes
00236                                                 for (std::list<StaticRoute*>::iterator iter = _routes.begin();
00237                                                                 iter != _routes.end();)
00238                                                 {
00239                                                         StaticRoute *route = (*iter);
00240                                                         if (route->toString() == task.route->toString())
00241                                                         {
00242                                                                 delete route;
00243                                                                 _routes.erase(iter++);
00244                                                         }
00245                                                         else
00246                                                         {
00247                                                                 iter++;
00248                                                         }
00249                                                 }
00250 
00251                                                 if (task.type == RouteChangeTask::ROUTE_ADD)
00252                                                 {
00253                                                         _routes.push_back(task.route);
00254                                                         _taskqueue.push( new SearchNextBundleTask(task.route->getDestination()) );
00255 
00256                                                         ibrcommon::MutexLock l(_expire_lock);
00257                                                         if (next_expire > task.route->getExpiration())
00258                                                         {
00259                                                                 next_expire = task.route->getExpiration();
00260                                                         }
00261                                                 }
00262                                                 else
00263                                                 {
00264                                                         delete task.route;
00265 
00266                                                         // force a expiration process
00267                                                         ibrcommon::MutexLock l(_expire_lock);
00268                                                         next_expire = 1;
00269                                                 }
00270                                         } catch (const bad_cast&) { };
00271 
00272                                         try {
00273                                                 dynamic_cast<ClearRoutesTask&>(*t);
00274 
00275                                                 // delete all static routes
00276                                                 for (std::list<StaticRoute*>::iterator iter = _routes.begin();
00277                                                                 iter != _routes.end(); iter++)
00278                                                 {
00279                                                         StaticRoute *route = (*iter);
00280                                                         delete route;
00281                                                 }
00282                                                 _routes.clear();
00283 
00284                                                 ibrcommon::MutexLock l(_expire_lock);
00285                                                 next_expire = 0;
00286                                         } catch (const bad_cast&) { };
00287 
00288                                         try {
00289                                                 const ExpireTask &task = dynamic_cast<ExpireTask&>(*t);
00290 
00291                                                 ibrcommon::MutexLock l(_expire_lock);
00292                                                 next_expire = 0;
00293 
00294                                                 // search for expired items
00295                                                 for (std::list<StaticRoute*>::iterator iter = _routes.begin();
00296                                                                 iter != _routes.end();)
00297                                                 {
00298                                                         StaticRoute *route = (*iter);
00299 
00300                                                         if (route->getExpiration() < task.timestamp)
00301                                                         {
00302                                                                 delete route;
00303                                                                 _routes.erase(iter++);
00304                                                         }
00305                                                         else
00306                                                         {
00307                                                                 if ((next_expire == 0) || (next_expire > route->getExpiration()))
00308                                                                 {
00309                                                                         next_expire = route->getExpiration();
00310                                                                 }
00311 
00312                                                                 iter++;
00313                                                         }
00314                                                 }
00315                                         } catch (const bad_cast&) { };
00316 
00317                                 } catch (const std::exception &ex) {
00318                                         IBRCOMMON_LOGGER_DEBUG(20) << "static routing failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
00319                                         return;
00320                                 }
00321 
00322                                 yield();
00323                         }
00324                 }
00325 
00326                 void StaticRoutingExtension::notify(const dtn::core::Event *evt)
00327                 {
00328                         try {
00329                                 const QueueBundleEvent &queued = dynamic_cast<const QueueBundleEvent&>(*evt);
00330                                 _taskqueue.push( new ProcessBundleTask(queued.bundle, queued.origin) );
00331                                 return;
00332                         } catch (const std::bad_cast&) { };
00333 
00334                         try {
00335                                 const dtn::core::NodeEvent &nodeevent = dynamic_cast<const dtn::core::NodeEvent&>(*evt);
00336                                 const dtn::core::Node &n = nodeevent.getNode();
00337 
00338                                 if (nodeevent.getAction() == NODE_AVAILABLE)
00339                                 {
00340                                         _taskqueue.push( new SearchNextBundleTask(n.getEID()) );
00341                                 }
00342                                 return;
00343                         } catch (const std::bad_cast&) { };
00344 
00345                         try {
00346                                 const dtn::net::ConnectionEvent &ce = dynamic_cast<const dtn::net::ConnectionEvent&>(*evt);
00347 
00348                                 if (ce.state == dtn::net::ConnectionEvent::CONNECTION_UP)
00349                                 {
00350                                         // send all (multi-hop) bundles in the storage to the neighbor
00351                                         _taskqueue.push( new SearchNextBundleTask(ce.peer) );
00352                                 }
00353                                 return;
00354                         } catch (const std::bad_cast&) { };
00355 
00356                         // The bundle transfer has been aborted
00357                         try {
00358                                 const dtn::net::TransferAbortedEvent &aborted = dynamic_cast<const dtn::net::TransferAbortedEvent&>(*evt);
00359                                 _taskqueue.push( new SearchNextBundleTask(aborted.getPeer()) );
00360                                 return;
00361                         } catch (const std::bad_cast&) { };
00362 
00363                         // A bundle transfer was successful
00364                         try {
00365                                 const dtn::net::TransferCompletedEvent &completed = dynamic_cast<const dtn::net::TransferCompletedEvent&>(*evt);
00366                                 _taskqueue.push( new SearchNextBundleTask(completed.getPeer()) );
00367                                 return;
00368                         } catch (const std::bad_cast&) { };
00369 
00370                         // each second, look for expired routes
00371                         try {
00372                                 const dtn::core::TimeEvent &time = dynamic_cast<const dtn::core::TimeEvent&>(*evt);
00373 
00374                                 ibrcommon::MutexLock l(_expire_lock);
00375                                 if ((next_expire != 0) && (next_expire < time.getUnixTimestamp()))
00376                                 {
00377                                         _taskqueue.push( new ExpireTask( time.getUnixTimestamp() ) );
00378                                 }
00379                                 return;
00380                         } catch (const bad_cast&) { };
00381 
00382                         // on route change, generate a task
00383                         try {
00384                                 const dtn::routing::StaticRouteChangeEvent &route = dynamic_cast<const dtn::routing::StaticRouteChangeEvent&>(*evt);
00385 
00386                                 if (route.type == dtn::routing::StaticRouteChangeEvent::ROUTE_CLEAR)
00387                                 {
00388                                         _taskqueue.push( new ClearRoutesTask() );
00389                                         return;
00390                                 }
00391 
00392                                 StaticRoute *r = NULL;
00393 
00394                                 if (route.pattern.length() > 0)
00395                                 {
00396                                         r = new RegexRoute(route.pattern, route.nexthop);
00397                                 }
00398                                 else
00399                                 {
00400                                         size_t et = dtn::utils::Clock::getUnixTimestamp() + route.timeout;
00401                                         r = new EIDRoute(route.destination, route.nexthop, et);
00402                                 }
00403 
00404                                 switch (route.type)
00405                                 {
00406                                 case dtn::routing::StaticRouteChangeEvent::ROUTE_ADD:
00407                                         _taskqueue.push( new RouteChangeTask( RouteChangeTask::ROUTE_ADD, r ) );
00408                                         break;
00409 
00410                                 case dtn::routing::StaticRouteChangeEvent::ROUTE_DEL:
00411                                         _taskqueue.push( new RouteChangeTask( RouteChangeTask::ROUTE_DEL, r ) );
00412                                         break;
00413 
00414                                 default:
00415                                         break;
00416                                 }
00417 
00418                                 return;
00419                         } catch (const bad_cast&) { };
00420                 }
00421 
00422                 // virtual destructor
00423                 StaticRoutingExtension::StaticRoute::~StaticRoute() {};
00424 
00425                 StaticRoutingExtension::RegexRoute::RegexRoute(const std::string &regex, const dtn::data::EID &dest)
00426                         : _dest(dest), _regex_str(regex), _invalid(false)
00427                 {
00428                         if ( regcomp(&_regex, regex.c_str(), 0) )
00429                         {
00430                                 IBRCOMMON_LOGGER(error) << "Could not compile regex: " << regex << IBRCOMMON_LOGGER_ENDL;
00431                                 _invalid = true;
00432                         }
00433                 }
00434 
00435                 StaticRoutingExtension::RegexRoute::~RegexRoute()
00436                 {
00437                         if (!_invalid)
00438                                 regfree(&_regex);
00439                 }
00440 
00441                 StaticRoutingExtension::RegexRoute::RegexRoute(const StaticRoutingExtension::RegexRoute &obj)
00442                         : _dest(obj._dest), _regex_str(obj._regex_str), _invalid(obj._invalid)
00443                 {
00444                         if ( regcomp(&_regex, _regex_str.c_str(), 0) )
00445                         {
00446                                 _invalid = true;
00447                         }
00448                 }
00449 
00450                 StaticRoutingExtension::RegexRoute& StaticRoutingExtension::RegexRoute::operator=(const StaticRoutingExtension::RegexRoute &obj)
00451                 {
00452                         if (!_invalid)
00453                         {
00454                                 regfree(&_regex);
00455                         }
00456 
00457                         _dest = obj._dest;
00458                         _regex_str = obj._regex_str;
00459                         _invalid = obj._invalid;
00460 
00461                         if (!_invalid)
00462                         {
00463                                 if ( regcomp(&_regex, obj._regex_str.c_str(), 0) )
00464                                 {
00465                                         IBRCOMMON_LOGGER(error) << "Could not compile regex: " << _regex_str << IBRCOMMON_LOGGER_ENDL;
00466                                         _invalid = true;
00467                                 }
00468                         }
00469 
00470                         return *this;
00471                 }
00472 
00473                 bool StaticRoutingExtension::RegexRoute::match(const dtn::data::EID &eid) const
00474                 {
00475                         if (_invalid) return false;
00476 
00477                         const std::string dest = eid.getString();
00478 
00479                         // test against the regular expression
00480                         int reti = regexec(&_regex, dest.c_str(), 0, NULL, 0);
00481 
00482                         if( !reti )
00483                         {
00484                                 // the expression match
00485                                 return true;
00486                         }
00487                         else if( reti == REG_NOMATCH )
00488                         {
00489                                 // the expression not match
00490                                 return false;
00491                         }
00492                         else
00493                         {
00494                                 char msgbuf[100];
00495                                 regerror(reti, &_regex, msgbuf, sizeof(msgbuf));
00496                                 IBRCOMMON_LOGGER(error) << "Regex match failed: " << std::string(msgbuf) << IBRCOMMON_LOGGER_ENDL;
00497                                 return false;
00498                         }
00499                 }
00500 
00501                 const dtn::data::EID& StaticRoutingExtension::RegexRoute::getDestination() const
00502                 {
00503                         return _dest;
00504                 }
00505 
00506                 const std::string StaticRoutingExtension::RegexRoute::toString() const
00507                 {
00508                         std::stringstream ss;
00509                         ss << _regex_str << " => " << _dest.getString();
00510                         return ss.str();
00511                 }
00512 
00513                 StaticRoutingExtension::EIDRoute::EIDRoute(const dtn::data::EID &match, const dtn::data::EID &nexthop, size_t et)
00514                  : _nexthop(nexthop), _match(match), expiretime(et)
00515                 {
00516                 }
00517 
00518                 StaticRoutingExtension::EIDRoute::~EIDRoute()
00519                 {
00520                 }
00521 
00522                 bool StaticRoutingExtension::EIDRoute::match(const dtn::data::EID &eid) const
00523                 {
00524                         return (_match == eid.getNode());
00525                 }
00526 
00527                 const dtn::data::EID& StaticRoutingExtension::EIDRoute::getDestination() const
00528                 {
00529                         return _nexthop;
00530                 }
00531 
00536                 const std::string StaticRoutingExtension::EIDRoute::toString() const
00537                 {
00538                         std::stringstream ss;
00539                         ss << _match.getString() << " => " << _nexthop.getString();
00540                         return ss.str();
00541                 }
00542 
00543                 size_t StaticRoutingExtension::EIDRoute::getExpiration() const
00544                 {
00545                         return expiretime;
00546                 }
00547 
00548                 /****************************************/
00549 
00550                 StaticRoutingExtension::SearchNextBundleTask::SearchNextBundleTask(const dtn::data::EID &e)
00551                  : eid(e)
00552                 { }
00553 
00554                 StaticRoutingExtension::SearchNextBundleTask::~SearchNextBundleTask()
00555                 { }
00556 
00557                 std::string StaticRoutingExtension::SearchNextBundleTask::toString()
00558                 {
00559                         return "SearchNextBundleTask: " + eid.getString();
00560                 }
00561 
00562                 /****************************************/
00563 
00564                 StaticRoutingExtension::ProcessBundleTask::ProcessBundleTask(const dtn::data::MetaBundle &meta, const dtn::data::EID &o)
00565                  : bundle(meta), origin(o)
00566                 { }
00567 
00568                 StaticRoutingExtension::ProcessBundleTask::~ProcessBundleTask()
00569                 { }
00570 
00571                 std::string StaticRoutingExtension::ProcessBundleTask::toString()
00572                 {
00573                         return "ProcessBundleTask: " + bundle.toString();
00574                 }
00575 
00576                 /****************************************/
00577 
00578                 StaticRoutingExtension::ClearRoutesTask::ClearRoutesTask()
00579                 {
00580                 }
00581 
00582                 StaticRoutingExtension::ClearRoutesTask::~ClearRoutesTask()
00583                 {
00584                 }
00585 
00586                 std::string StaticRoutingExtension::ClearRoutesTask::toString()
00587                 {
00588                         return "ClearRoutesTask";
00589                 }
00590 
00591                 /****************************************/
00592 
00593                 StaticRoutingExtension::RouteChangeTask::RouteChangeTask(CHANGE_TYPE t, StaticRoute *r)
00594                  : type(t), route(r)
00595                 {
00596 
00597                 }
00598 
00599                 StaticRoutingExtension::RouteChangeTask::~RouteChangeTask()
00600                 {
00601 
00602                 }
00603 
00604                 std::string StaticRoutingExtension::RouteChangeTask::toString()
00605                 {
00606                         return "RouteChangeTask: " + (*route).toString();
00607                 }
00608 
00609                 /****************************************/
00610 
00611                 StaticRoutingExtension::ExpireTask::ExpireTask(size_t t)
00612                  : timestamp(t)
00613                 {
00614 
00615                 }
00616 
00617                 StaticRoutingExtension::ExpireTask::~ExpireTask()
00618                 {
00619 
00620                 }
00621 
00622                 std::string StaticRoutingExtension::ExpireTask::toString()
00623                 {
00624                         std::stringstream ss;
00625                         ss << "ExpireTask: " << timestamp;
00626                         return ss.str();
00627                 }
00628         }
00629 }