IBR-DTN  1.0.0
StaticRoutingExtension.cpp
Go to the documentation of this file.
1 /*
2  * StaticRoutingExtension.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "config.h"
23 #include "Configuration.h"
26 
29 #include "net/ConnectionEvent.h"
30 #include "core/EventDispatcher.h"
31 #include "core/NodeEvent.h"
33 
34 #ifdef HAVE_REGEX_H
36 #endif
37 
38 #include <ibrdtn/utils/Clock.h>
39 
40 #include <ibrcommon/Logger.h>
41 #include <ibrcommon/thread/MutexLock.h>
42 
43 #include <typeinfo>
44 #include <memory>
45 
46 namespace dtn
47 {
48  namespace routing
49  {
50  const std::string StaticRoutingExtension::TAG = "StaticRoutingExtension";
51 
53  : next_expire(0)
54  {
55  }
56 
58  {
59  join();
60 
61  // delete all static routes
62  for (std::list<StaticRoute*>::iterator iter = _routes.begin();
63  iter != _routes.end(); ++iter)
64  {
65  StaticRoute *route = (*iter);
66  delete route;
67  }
68  }
69 
71  {
72  _taskqueue.abort();
73  }
74 
76  {
78  {
79  public:
80  BundleFilter(const NeighborDatabase::NeighborEntry &entry, const std::list<const StaticRoute*> &routes, const dtn::core::FilterContext &context, const dtn::net::ConnectionManager::protocol_list &plist)
81  : _entry(entry), _routes(routes), _plist(plist), _context(context)
82  {};
83 
84  virtual ~BundleFilter() {};
85 
86  virtual dtn::data::Size limit() const throw () { return _entry.getFreeTransferSlots(); };
87 
88  virtual bool addIfSelected(dtn::storage::BundleResult &result, const dtn::data::MetaBundle &meta) const throw (dtn::storage::BundleSelectorException)
89  {
90  // check Scope Control Block - do not forward bundles with hop limit == 0
91  if (meta.hopcount == 0)
92  {
93  return false;
94  }
95 
96  // do not forward local bundles
99  )
100  {
101  return false;
102  }
103 
104  // check Scope Control Block - do not forward non-group bundles with hop limit <= 1
106  {
107  return false;
108  }
109 
110  // do not forward bundles already known by the destination
111  if (_entry.has(meta))
112  {
113  return false;
114  }
115 
116  // update filter context
117  dtn::core::FilterContext context = _context;
118  context.setMetaBundle(meta);
119 
120  // search for one rule that match
121  for (std::list<const StaticRoute*>::const_iterator iter = _routes.begin(); iter != _routes.end(); ++iter)
122  {
123  const StaticRoute &route = (**iter);
124 
125  if (route.match(meta.destination))
126  {
127  // check bundle filter for each possible path
128  for (dtn::net::ConnectionManager::protocol_list::const_iterator it = _plist.begin(); it != _plist.end(); ++it)
129  {
130  const dtn::core::Node::Protocol &p = (*it);
131 
132  // update context with current protocol
133  context.setProtocol(p);
134 
135  // execute filtering
137 
139  {
140  // put the selected bundle with targeted interface into the result-set
141  static_cast<RoutingResult&>(result).put(meta, p);
142  return true;
143  }
144  }
145  }
146  }
147 
148  return false;
149  };
150 
151  private:
152  const NeighborDatabase::NeighborEntry &_entry;
153  const std::list<const StaticRoute*> &_routes;
155  const dtn::core::FilterContext &_context;
156  };
157 
158  // announce static routes here
159  const std::multimap<std::string, std::string> &routes = dtn::daemon::Configuration::getInstance().getNetwork().getStaticRoutes();
160 
161  for (std::multimap<std::string, std::string>::const_iterator iter = routes.begin(); iter != routes.end(); ++iter)
162  {
163  const dtn::data::EID nexthop((*iter).second);
165  }
166 
167  RoutingResult list;
168 
169  while (true)
170  {
171  NeighborDatabase &db = (**this).getNeighborDB();
172  std::list<const StaticRoute*> routes;
173 
174  try {
175  Task *t = _taskqueue.poll();
176  std::auto_ptr<Task> killer(t);
177 
178  IBRCOMMON_LOGGER_DEBUG_TAG(StaticRoutingExtension::TAG, 5) << "processing task " << t->toString() << IBRCOMMON_LOGGER_ENDL;
179 
180  try {
181  SearchNextBundleTask &task = dynamic_cast<SearchNextBundleTask&>(*t);
182 
183  // remove all routes of the previous round
184  routes.clear();
185 
186  // clear the result list
187  list.clear();
188 
189  // look for routes to this node
190  for (std::list<StaticRoute*>::const_iterator iter = _routes.begin();
191  iter != _routes.end(); ++iter)
192  {
193  const StaticRoute *route = (*iter);
194  if (route->getDestination() == task.eid)
195  {
196  // add to the valid routes
197  routes.push_back(route);
198  }
199  }
200 
201  if (!routes.empty())
202  {
203  // lock the neighbor database while searching for bundles
204  {
205  // this destination is not handles by any static route
206  ibrcommon::MutexLock l(db);
207  NeighborDatabase::NeighborEntry &entry = db.get(task.eid, true);
208 
209  // check if enough transfer slots available (threshold reached)
210  if (!entry.isTransferThresholdReached())
212 
213  // get a list of protocols supported by both, the local BPA and the remote peer
216 
217  // create a filter context
218  dtn::core::FilterContext context;
219  context.setPeer(entry.eid);
220  context.setRouting(*this);
221 
222  // get the bundle filter of the neighbor
223  BundleFilter filter(entry, routes, context, plist);
224 
225  // some debug
226  IBRCOMMON_LOGGER_DEBUG_TAG(StaticRoutingExtension::TAG, 40) << "search some bundles not known by " << task.eid.getString() << IBRCOMMON_LOGGER_ENDL;
227 
228  // query all bundles from the storage
229  (**this).getSeeker().get(filter, list);
230  }
231 
232  // send the bundles as long as we have resources
233  for (RoutingResult::const_iterator iter = list.begin(); iter != list.end(); ++iter)
234  {
235  try {
236  // transfer the bundle to the neighbor
237  transferTo(task.eid, (*iter).first, (*iter).second);
238  } catch (const NeighborDatabase::AlreadyInTransitException&) { };
239  }
240  }
241  } catch (const NeighborDatabase::NoMoreTransfersAvailable &ex) {
242  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "task " << t->toString() << " aborted: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
243  } catch (const NeighborDatabase::EntryNotFoundException &ex) {
244  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "task " << t->toString() << " aborted: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
245  } catch (const NodeNotAvailableException &ex) {
246  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "task " << t->toString() << " aborted: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
247  } catch (const dtn::storage::NoBundleFoundException &ex) {
248  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "task " << t->toString() << " aborted: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
249  } catch (const std::bad_cast&) { };
250 
251  try {
252  const ProcessBundleTask &task = dynamic_cast<ProcessBundleTask&>(*t);
253  IBRCOMMON_LOGGER_DEBUG_TAG(StaticRoutingExtension::TAG, 50) << "search static route for " << task.bundle.toString() << IBRCOMMON_LOGGER_ENDL;
254 
255  // check Scope Control Block - do not forward non-group bundles with hop limit <= 1
256  if ((task.bundle.hopcount <= 1) && (task.bundle.get(dtn::data::PrimaryBlock::DESTINATION_IS_SINGLETON))) continue;
257 
258  // look for routes to this node
259  for (std::list<StaticRoute*>::const_iterator iter = _routes.begin(); iter != _routes.end(); ++iter)
260  {
261  const StaticRoute &route = (**iter);
262 
263  IBRCOMMON_LOGGER_DEBUG_TAG(StaticRoutingExtension::TAG, 50) << "check static route: " << route.toString() << IBRCOMMON_LOGGER_ENDL;
264 
265  try {
266  if (route.match(task.bundle.destination))
267  {
268  // lock the neighbor database while checking if the bundle
269  // is already known by the peer
270  {
271  // get data about the potential next-hop
272  ibrcommon::MutexLock l(db);
273  NeighborDatabase::NeighborEntry &entry = db.get(route.getDestination(), true);
274 
275  // do not forward bundles already known by the destination
276  if (entry.has(task.bundle)) continue;
277  }
278 
279  // get a list of protocols supported by both, the local BPA and the remote peer
282 
283  // create a filter context
284  dtn::core::FilterContext context;
285  context.setPeer(route.getDestination());
286  context.setRouting(*this);
287 
288  // check bundle filter for each possible path
289  for (dtn::net::ConnectionManager::protocol_list::const_iterator it = plist.begin(); it != plist.end(); ++it)
290  {
291  const dtn::core::Node::Protocol &p = (*it);
292 
293  // update context with current protocol
294  context.setProtocol(p);
295 
296  // execute filtering
298 
300  {
301  // transfer the bundle to the neighbor
302  transferTo(route.getDestination(), task.bundle, p);
303  break;
304  }
305  }
306  }
308  // neighbor is not in the database, can not forward this bundle
311  } catch (const NodeNotAvailableException &ex) {
312  // node is not available as neighbor
313  };
314  }
315  } catch (const std::bad_cast&) { };
316 
317  try {
318  const RouteChangeTask &task = dynamic_cast<RouteChangeTask&>(*t);
319 
320  // delete all similar routes
321  for (std::list<StaticRoute*>::iterator iter = _routes.begin();
322  iter != _routes.end();)
323  {
324  StaticRoute *route = (*iter);
325  if (route->equals(*task.route))
326  {
327  delete route;
328  _routes.erase(iter++);
329  }
330  else
331  {
332  ++iter;
333  }
334  }
335 
336  if (task.type == RouteChangeTask::ROUTE_ADD)
337  {
338  _routes.push_back(task.route);
339  _taskqueue.push( new SearchNextBundleTask(task.route->getDestination()) );
340 
341  if (task.route->getExpiration() > 0)
342  {
343  ibrcommon::MutexLock l(_expire_lock);
344  if (next_expire == 0 || next_expire > task.route->getExpiration())
345  {
346  next_expire = task.route->getExpiration();
347  }
348  }
349  }
350  else
351  {
352  delete task.route;
353 
354  // force a expiration process
355  ibrcommon::MutexLock l(_expire_lock);
356  next_expire = 1;
357  }
358  } catch (const bad_cast&) { };
359 
360  try {
361  dynamic_cast<ClearRoutesTask&>(*t);
362 
363  // delete all static routes
364  for (std::list<StaticRoute*>::iterator iter = _routes.begin();
365  iter != _routes.end(); ++iter)
366  {
367  StaticRoute *route = (*iter);
368  delete route;
369  }
370  _routes.clear();
371 
372  ibrcommon::MutexLock l(_expire_lock);
373  next_expire = 0;
374  } catch (const bad_cast&) { };
375 
376  try {
377  const ExpireTask &task = dynamic_cast<ExpireTask&>(*t);
378 
379  ibrcommon::MutexLock l(_expire_lock);
380  next_expire = 0;
381 
382  // search for expired items
383  for (std::list<StaticRoute*>::iterator iter = _routes.begin();
384  iter != _routes.end();)
385  {
386  StaticRoute *route = (*iter);
387 
388  if ((route->getExpiration() > 0) && (route->getExpiration() < task.timestamp))
389  {
390  route->raiseExpired();
391  delete route;
392  _routes.erase(iter++);
393  }
394  else
395  {
396  if ((next_expire == 0) || (next_expire > route->getExpiration()))
397  {
398  next_expire = route->getExpiration();
399  }
400 
401  ++iter;
402  }
403  }
404  } catch (const bad_cast&) { };
405 
406  } catch (const std::exception &ex) {
407  IBRCOMMON_LOGGER_DEBUG_TAG(StaticRoutingExtension::TAG, 15) << "terminated due to " << ex.what() << IBRCOMMON_LOGGER_ENDL;
408  return;
409  }
410 
411  yield();
412  }
413  }
414 
416  {
417  _taskqueue.push( new SearchNextBundleTask(peer) );
418  }
419 
421  {
422  _taskqueue.push( new ProcessBundleTask(meta, peer) );
423  }
424 
426  {
427  // each second, look for expired routes
429 
430  ibrcommon::MutexLock l(_expire_lock);
431  if ((next_expire != 0) && (next_expire < monotonic))
432  {
433  _taskqueue.push( new ExpireTask( monotonic ) );
434  }
435  }
436 
438  {
439  // on route change, generate a task
441  {
442  _taskqueue.push( new ClearRoutesTask() );
443  return;
444  }
445 
446  StaticRoute *r = NULL;
447 
448  if (route.pattern.length() > 0)
449  {
450 #ifdef HAVE_REGEX_H
451  r = new StaticRegexRoute(route.pattern, route.nexthop);
452 #else
454  r = new EIDRoute(route.pattern, route.nexthop, et);
455 #endif
456  }
457  else
458  {
460  r = new EIDRoute(route.destination, route.nexthop, et);
461  }
462 
463  switch (route.type)
464  {
466  _taskqueue.push( new RouteChangeTask( RouteChangeTask::ROUTE_ADD, r ) );
467  break;
468 
470  _taskqueue.push( new RouteChangeTask( RouteChangeTask::ROUTE_DEL, r ) );
471  break;
472 
473  default:
474  break;
475  }
476  }
477 
479  {
482 
483  // reset the task queue
484  _taskqueue.reset();
485 
486  // routine checked for throw() on 15.02.2013
487  try {
488  // run the thread
489  start();
490  } catch (const ibrcommon::ThreadException &ex) {
491  IBRCOMMON_LOGGER_TAG(StaticRoutingExtension::TAG, error) << "componentUp failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
492  }
493  }
494 
496  {
499 
500  // routine checked for throw() on 15.02.2013
501  try {
502  // stop the thread
503  stop();
504  join();
505  } catch (const ibrcommon::ThreadException &ex) {
506  IBRCOMMON_LOGGER_TAG(StaticRoutingExtension::TAG, error) << "componentDown failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
507  }
508  }
509 
510  const std::string StaticRoutingExtension::getTag() const throw ()
511  {
512  return "neighbor";
513  }
514 
515  StaticRoutingExtension::EIDRoute::EIDRoute(const dtn::data::EID &match, const dtn::data::EID &nexthop, const dtn::data::Timestamp &et)
516  : _nexthop(nexthop), _match(match), expiretime(et)
517  {
518  }
519 
520  StaticRoutingExtension::EIDRoute::~EIDRoute()
521  {
522  }
523 
524  bool StaticRoutingExtension::EIDRoute::match(const dtn::data::EID &eid) const
525  {
526  return _match.sameHost(eid);
527  }
528 
529  const dtn::data::EID& StaticRoutingExtension::EIDRoute::getDestination() const
530  {
531  return _nexthop;
532  }
533 
538  const std::string StaticRoutingExtension::EIDRoute::toString() const
539  {
540  std::stringstream ss;
541  ss << _match.getString() << " => " << _nexthop.getString();
542  return ss.str();
543  }
544 
545  const dtn::data::Timestamp& StaticRoutingExtension::EIDRoute::getExpiration() const
546  {
547  return expiretime;
548  }
549 
550  void StaticRoutingExtension::EIDRoute::raiseExpired() const
551  {
553  }
554 
555  bool StaticRoutingExtension::EIDRoute::equals(const StaticRoute &route) const
556  {
557  try {
558  const StaticRoutingExtension::EIDRoute &r = dynamic_cast<const StaticRoutingExtension::EIDRoute&>(route);
559  return (_nexthop == r._nexthop) && (_match == r._match);
560  } catch (const std::bad_cast&) {
561  return false;
562  }
563  }
564 
565  /****************************************/
566 
567  StaticRoutingExtension::SearchNextBundleTask::SearchNextBundleTask(const dtn::data::EID &e)
568  : eid(e)
569  { }
570 
571  StaticRoutingExtension::SearchNextBundleTask::~SearchNextBundleTask()
572  { }
573 
574  std::string StaticRoutingExtension::SearchNextBundleTask::toString()
575  {
576  return "SearchNextBundleTask: " + eid.getString();
577  }
578 
579  /****************************************/
580 
581  StaticRoutingExtension::ProcessBundleTask::ProcessBundleTask(const dtn::data::MetaBundle &meta, const dtn::data::EID &o)
582  : bundle(meta), origin(o)
583  { }
584 
585  StaticRoutingExtension::ProcessBundleTask::~ProcessBundleTask()
586  { }
587 
588  std::string StaticRoutingExtension::ProcessBundleTask::toString()
589  {
590  return "ProcessBundleTask: " + bundle.toString();
591  }
592 
593  /****************************************/
594 
595  StaticRoutingExtension::ClearRoutesTask::ClearRoutesTask()
596  {
597  }
598 
599  StaticRoutingExtension::ClearRoutesTask::~ClearRoutesTask()
600  {
601  }
602 
603  std::string StaticRoutingExtension::ClearRoutesTask::toString()
604  {
605  return "ClearRoutesTask";
606  }
607 
608  /****************************************/
609 
610  StaticRoutingExtension::RouteChangeTask::RouteChangeTask(CHANGE_TYPE t, StaticRoute *r)
611  : type(t), route(r)
612  {
613 
614  }
615 
616  StaticRoutingExtension::RouteChangeTask::~RouteChangeTask()
617  {
618 
619  }
620 
621  std::string StaticRoutingExtension::RouteChangeTask::toString()
622  {
623  return "RouteChangeTask: " + (*route).toString();
624  }
625 
626  /****************************************/
627 
628  StaticRoutingExtension::ExpireTask::ExpireTask(dtn::data::Timestamp t)
629  : timestamp(t)
630  {
631 
632  }
633 
634  StaticRoutingExtension::ExpireTask::~ExpireTask()
635  {
636 
637  }
638 
639  std::string StaticRoutingExtension::ExpireTask::toString()
640  {
641  std::stringstream ss;
642  ss << "ExpireTask: " << timestamp.toString();
643  return ss.str();
644  }
645  }
646 }
static Configuration & getInstance(bool reset=false)
static dtn::data::EID local
Definition: BundleCore.h:79
bool get(dtn::data::PrimaryBlock::FLAGS flag) const
Definition: MetaBundle.cpp:160
static void add(EventReceiver< E > *receiver)
virtual void raiseExpired() const =0
virtual bool match(const dtn::data::EID &eid) const =0
std::list< dtn::core::Node::Protocol > protocol_list
virtual void eventDataChanged(const dtn::data::EID &peer)
static void remove(const EventReceiver< E > *receiver)
bool has(const dtn::data::BundleID &, const bool require_bloomfilter=false) const
NeighborDatabase::NeighborEntry & get(const dtn::data::EID &eid, bool noCached=false)
dtn::net::ConnectionManager & getConnectionManager()
Definition: BundleCore.cpp:260
static void raiseEvent(CHANGE_TYPE type)
virtual void eventBundleQueued(const dtn::data::EID &peer, const dtn::data::MetaBundle &meta)
BundleFilter::ACTION evaluate(BundleFilter::TABLE table, const FilterContext &context) const
Definition: BundleCore.cpp:617
void setProtocol(const dtn::core::Node::Protocol &protocol)
const Configuration::Network & getNetwork() const
virtual bool equals(const StaticRoute &route) const =0
void setPeer(const dtn::data::EID &endpoint)
void transferTo(const dtn::data::EID &destination, const dtn::data::MetaBundle &meta, const dtn::core::Node::Protocol)
void setMetaBundle(const dtn::data::MetaBundle &data)
EID getNode() const
Definition: EID.cpp:528
const protocol_set getSupportedProtocols()
const std::multimap< std::string, std::string > & getStaticRoutes() const
dtn::data::EID destination
Definition: MetaBundle.h:60
void raiseEvent(const dtn::core::TimeEvent &evt)
size_t Size
Definition: Number.h:34
virtual const std::string toString() const =0
std::string getString() const
Definition: EID.cpp:374
virtual const std::string getTag() const
static dtn::data::Timestamp getMonotonicTimestamp()
Definition: Clock.cpp:175
virtual const dtn::data::Timestamp & getExpiration() const =0
void setRouting(const dtn::routing::RoutingExtension &routing)
virtual const dtn::data::EID & getDestination() const =0
static BundleCore & getInstance()
Definition: BundleCore.cpp:82