IBR-DTNSuite  0.10
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"
29 #include "net/ConnectionEvent.h"
30 #include "core/NodeEvent.h"
32 #include "core/TimeEvent.h"
33 
34 #ifdef HAVE_REGEX_H
36 #endif
37 
38 #include <ibrdtn/utils/Clock.h>
39 
40 #include <ibrcommon/Logger.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  {
77  class BundleFilter : public dtn::storage::BundleSelector
78  {
79  public:
80  BundleFilter(const NeighborDatabase::NeighborEntry &entry, const std::list<const StaticRoute*> &routes)
81  : _entry(entry), _routes(routes)
82  {};
83 
84  virtual ~BundleFilter() {};
85 
86  virtual dtn::data::Size limit() const throw () { return _entry.getFreeTransferSlots(); };
87 
88  virtual bool shouldAdd(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 any routing control message
97  // this is done by the neighbor routing module
98  if (isRouting(meta.source))
99  {
100  return false;
101  }
102 
103  // do not forward local bundles
106  )
107  {
108  return false;
109  }
110 
111  // check Scope Control Block - do not forward non-group bundles with hop limit <= 1
113  {
114  return false;
115  }
116 
117  // do not forward bundles addressed to this neighbor,
118  // because this is handled by neighbor routing extension
119  if (_entry.eid == meta.destination.getNode())
120  {
121  return false;
122  }
123 
124  // do not forward bundles already known by the destination
125  if (_entry.has(meta))
126  {
127  return false;
128  }
129 
130  // search for one rule that match
131  for (std::list<const StaticRoute*>::const_iterator iter = _routes.begin();
132  iter != _routes.end(); ++iter)
133  {
134  const StaticRoute &route = (**iter);
135 
136  if (route.match(meta.destination))
137  {
138  return true;
139  }
140  }
141 
142  return false;
143  };
144 
145  private:
146  const NeighborDatabase::NeighborEntry &_entry;
147  const std::list<const StaticRoute*> &_routes;
148  };
149 
150  // announce static routes here
151  const std::multimap<std::string, std::string> &routes = dtn::daemon::Configuration::getInstance().getNetwork().getStaticRoutes();
152 
153  for (std::multimap<std::string, std::string>::const_iterator iter = routes.begin(); iter != routes.end(); ++iter)
154  {
155  const dtn::data::EID nexthop((*iter).second);
157  }
158 
160 
161  while (true)
162  {
163  NeighborDatabase &db = (**this).getNeighborDB();
164  std::list<const StaticRoute*> routes;
165 
166  try {
167  Task *t = _taskqueue.getnpop(true);
168  std::auto_ptr<Task> killer(t);
169 
170  IBRCOMMON_LOGGER_DEBUG_TAG(StaticRoutingExtension::TAG, 5) << "processing task " << t->toString() << IBRCOMMON_LOGGER_ENDL;
171 
172  try {
173  SearchNextBundleTask &task = dynamic_cast<SearchNextBundleTask&>(*t);
174 
175  // remove all routes of the previous round
176  routes.clear();
177 
178  // look for routes to this node
179  for (std::list<StaticRoute*>::const_iterator iter = _routes.begin();
180  iter != _routes.end(); ++iter)
181  {
182  const StaticRoute *route = (*iter);
183  if (route->getDestination() == task.eid)
184  {
185  // add to the valid routes
186  routes.push_back(route);
187  }
188  }
189 
190  if (!routes.empty())
191  {
192  // lock the neighbor database while searching for bundles
193  {
194  // this destination is not handles by any static route
195  ibrcommon::MutexLock l(db);
196  NeighborDatabase::NeighborEntry &entry = db.get(task.eid);
197 
198  // check if enough transfer slots available (threshold reached)
199  if (!entry.isTransferThresholdReached())
201 
202  // get the bundle filter of the neighbor
203  BundleFilter filter(entry, routes);
204 
205  // some debug
206  IBRCOMMON_LOGGER_DEBUG_TAG(StaticRoutingExtension::TAG, 40) << "search some bundles not known by " << task.eid.getString() << IBRCOMMON_LOGGER_ENDL;
207 
208  // query all bundles from the storage
209  list.clear();
210  (**this).getSeeker().get(filter, list);
211  }
212 
213  // send the bundles as long as we have resources
214  for (std::list<dtn::data::MetaBundle>::const_iterator iter = list.begin(); iter != list.end(); ++iter)
215  {
216  try {
217  // transfer the bundle to the neighbor
218  transferTo(task.eid, *iter);
219  } catch (const NeighborDatabase::AlreadyInTransitException&) { };
220  }
221  }
224  } catch (const dtn::storage::NoBundleFoundException&) {
225  } catch (const std::bad_cast&) { };
226 
227  try {
228  const ProcessBundleTask &task = dynamic_cast<ProcessBundleTask&>(*t);
229  IBRCOMMON_LOGGER_DEBUG_TAG(StaticRoutingExtension::TAG, 50) << "search static route for " << task.bundle.toString() << IBRCOMMON_LOGGER_ENDL;
230 
231  // look for routes to this node
232  for (std::list<StaticRoute*>::const_iterator iter = _routes.begin();
233  iter != _routes.end(); ++iter)
234  {
235  const StaticRoute &route = (**iter);
236  IBRCOMMON_LOGGER_DEBUG_TAG(StaticRoutingExtension::TAG, 50) << "check static route: " << route.toString() << IBRCOMMON_LOGGER_ENDL;
237  try {
238  if (route.match(task.bundle.destination))
239  {
240  // transfer the bundle to the neighbor
241  transferTo(route.getDestination(), task.bundle);
242  }
244  // neighbor is not available, can not forward this bundle
246  } catch (const NeighborDatabase::AlreadyInTransitException&) { };
247  }
248  } catch (const std::bad_cast&) { };
249 
250  try {
251  const RouteChangeTask &task = dynamic_cast<RouteChangeTask&>(*t);
252 
253  // delete all similar routes
254  for (std::list<StaticRoute*>::iterator iter = _routes.begin();
255  iter != _routes.end();)
256  {
257  StaticRoute *route = (*iter);
258  if (route->toString() == task.route->toString())
259  {
260  delete route;
261  _routes.erase(iter++);
262  }
263  else
264  {
265  ++iter;
266  }
267  }
268 
269  if (task.type == RouteChangeTask::ROUTE_ADD)
270  {
271  _routes.push_back(task.route);
272  _taskqueue.push( new SearchNextBundleTask(task.route->getDestination()) );
273 
274  ibrcommon::MutexLock l(_expire_lock);
275  if (next_expire > task.route->getExpiration())
276  {
277  next_expire = task.route->getExpiration();
278  }
279  }
280  else
281  {
282  delete task.route;
283 
284  // force a expiration process
285  ibrcommon::MutexLock l(_expire_lock);
286  next_expire = 1;
287  }
288  } catch (const bad_cast&) { };
289 
290  try {
291  dynamic_cast<ClearRoutesTask&>(*t);
292 
293  // delete all static routes
294  for (std::list<StaticRoute*>::iterator iter = _routes.begin();
295  iter != _routes.end(); ++iter)
296  {
297  StaticRoute *route = (*iter);
298  delete route;
299  }
300  _routes.clear();
301 
302  ibrcommon::MutexLock l(_expire_lock);
303  next_expire = 0;
304  } catch (const bad_cast&) { };
305 
306  try {
307  const ExpireTask &task = dynamic_cast<ExpireTask&>(*t);
308 
309  ibrcommon::MutexLock l(_expire_lock);
310  next_expire = 0;
311 
312  // search for expired items
313  for (std::list<StaticRoute*>::iterator iter = _routes.begin();
314  iter != _routes.end();)
315  {
316  StaticRoute *route = (*iter);
317 
318  if (route->getExpiration() < task.timestamp)
319  {
320  delete route;
321  _routes.erase(iter++);
322  }
323  else
324  {
325  if ((next_expire == 0) || (next_expire > route->getExpiration()))
326  {
327  next_expire = route->getExpiration();
328  }
329 
330  ++iter;
331  }
332  }
333  } catch (const bad_cast&) { };
334 
335  } catch (const std::exception &ex) {
336  IBRCOMMON_LOGGER_DEBUG_TAG(StaticRoutingExtension::TAG, 15) << "terminated due to " << ex.what() << IBRCOMMON_LOGGER_ENDL;
337  return;
338  }
339 
340  yield();
341  }
342  }
343 
345  {
346  try {
347  const QueueBundleEvent &queued = dynamic_cast<const QueueBundleEvent&>(*evt);
348  _taskqueue.push( new ProcessBundleTask(queued.bundle, queued.origin) );
349  return;
350  } catch (const std::bad_cast&) { };
351 
352  try {
353  const dtn::core::NodeEvent &nodeevent = dynamic_cast<const dtn::core::NodeEvent&>(*evt);
354  const dtn::core::Node &n = nodeevent.getNode();
355 
356  if (nodeevent.getAction() == NODE_AVAILABLE)
357  {
358  _taskqueue.push( new SearchNextBundleTask(n.getEID()) );
359  }
360  else if (nodeevent.getAction() == NODE_DATA_ADDED)
361  {
362  _taskqueue.push( new SearchNextBundleTask( n.getEID() ) );
363  }
364 
365  return;
366  } catch (const std::bad_cast&) { };
367 
368  try {
369  const dtn::net::ConnectionEvent &ce = dynamic_cast<const dtn::net::ConnectionEvent&>(*evt);
370 
372  {
373  // send all (multi-hop) bundles in the storage to the neighbor
374  _taskqueue.push( new SearchNextBundleTask(ce.peer) );
375  }
376  return;
377  } catch (const std::bad_cast&) { };
378 
379  // The bundle transfer has been aborted
380  try {
381  const dtn::net::TransferAbortedEvent &aborted = dynamic_cast<const dtn::net::TransferAbortedEvent&>(*evt);
382  _taskqueue.push( new SearchNextBundleTask(aborted.getPeer()) );
383  return;
384  } catch (const std::bad_cast&) { };
385 
386  // A bundle transfer was successful
387  try {
388  const dtn::net::TransferCompletedEvent &completed = dynamic_cast<const dtn::net::TransferCompletedEvent&>(*evt);
389  _taskqueue.push( new SearchNextBundleTask(completed.getPeer()) );
390  return;
391  } catch (const std::bad_cast&) { };
392 
393  // each second, look for expired routes
394  try {
395  const dtn::core::TimeEvent &time = dynamic_cast<const dtn::core::TimeEvent&>(*evt);
396 
397  ibrcommon::MutexLock l(_expire_lock);
398  if ((next_expire != 0) && (next_expire < time.getUnixTimestamp()))
399  {
400  _taskqueue.push( new ExpireTask( time.getUnixTimestamp() ) );
401  }
402  return;
403  } catch (const bad_cast&) { };
404 
405  // on route change, generate a task
406  try {
407  const dtn::routing::StaticRouteChangeEvent &route = dynamic_cast<const dtn::routing::StaticRouteChangeEvent&>(*evt);
408 
410  {
411  _taskqueue.push( new ClearRoutesTask() );
412  return;
413  }
414 
415  StaticRoute *r = NULL;
416 
417  if (route.pattern.length() > 0)
418  {
419 #ifdef HAVE_REGEX_H
420  r = new StaticRegexRoute(route.pattern, route.nexthop);
421 #else
423  r = new EIDRoute(route.pattern, route.nexthop, et);
424 #endif
425  }
426  else
427  {
429  r = new EIDRoute(route.destination, route.nexthop, et);
430  }
431 
432  switch (route.type)
433  {
435  _taskqueue.push( new RouteChangeTask( RouteChangeTask::ROUTE_ADD, r ) );
436  break;
437 
439  _taskqueue.push( new RouteChangeTask( RouteChangeTask::ROUTE_DEL, r ) );
440  break;
441 
442  default:
443  break;
444  }
445 
446  return;
447  } catch (const bad_cast&) { };
448  }
449 
451  {
452  // reset the task queue
453  _taskqueue.reset();
454 
455  // routine checked for throw() on 15.02.2013
456  try {
457  // run the thread
458  start();
459  } catch (const ibrcommon::ThreadException &ex) {
460  IBRCOMMON_LOGGER_TAG(StaticRoutingExtension::TAG, error) << "componentUp failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
461  }
462  }
463 
465  {
466  // routine checked for throw() on 15.02.2013
467  try {
468  // stop the thread
469  stop();
470  join();
471  } catch (const ibrcommon::ThreadException &ex) {
472  IBRCOMMON_LOGGER_TAG(StaticRoutingExtension::TAG, error) << "componentDown failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
473  }
474  }
475 
476  StaticRoutingExtension::EIDRoute::EIDRoute(const dtn::data::EID &match, const dtn::data::EID &nexthop, const dtn::data::Timestamp &et)
477  : _nexthop(nexthop), _match(match), expiretime(et)
478  {
479  }
480 
481  StaticRoutingExtension::EIDRoute::~EIDRoute()
482  {
483  }
484 
485  bool StaticRoutingExtension::EIDRoute::match(const dtn::data::EID &eid) const
486  {
487  return (_match == eid.getNode());
488  }
489 
490  const dtn::data::EID& StaticRoutingExtension::EIDRoute::getDestination() const
491  {
492  return _nexthop;
493  }
494 
499  const std::string StaticRoutingExtension::EIDRoute::toString() const
500  {
501  std::stringstream ss;
502  ss << _match.getString() << " => " << _nexthop.getString();
503  return ss.str();
504  }
505 
506  const dtn::data::Timestamp& StaticRoutingExtension::EIDRoute::getExpiration() const
507  {
508  return expiretime;
509  }
510 
511  /****************************************/
512 
513  StaticRoutingExtension::SearchNextBundleTask::SearchNextBundleTask(const dtn::data::EID &e)
514  : eid(e)
515  { }
516 
517  StaticRoutingExtension::SearchNextBundleTask::~SearchNextBundleTask()
518  { }
519 
520  std::string StaticRoutingExtension::SearchNextBundleTask::toString()
521  {
522  return "SearchNextBundleTask: " + eid.getString();
523  }
524 
525  /****************************************/
526 
527  StaticRoutingExtension::ProcessBundleTask::ProcessBundleTask(const dtn::data::MetaBundle &meta, const dtn::data::EID &o)
528  : bundle(meta), origin(o)
529  { }
530 
531  StaticRoutingExtension::ProcessBundleTask::~ProcessBundleTask()
532  { }
533 
534  std::string StaticRoutingExtension::ProcessBundleTask::toString()
535  {
536  return "ProcessBundleTask: " + bundle.toString();
537  }
538 
539  /****************************************/
540 
541  StaticRoutingExtension::ClearRoutesTask::ClearRoutesTask()
542  {
543  }
544 
545  StaticRoutingExtension::ClearRoutesTask::~ClearRoutesTask()
546  {
547  }
548 
549  std::string StaticRoutingExtension::ClearRoutesTask::toString()
550  {
551  return "ClearRoutesTask";
552  }
553 
554  /****************************************/
555 
556  StaticRoutingExtension::RouteChangeTask::RouteChangeTask(CHANGE_TYPE t, StaticRoute *r)
557  : type(t), route(r)
558  {
559 
560  }
561 
562  StaticRoutingExtension::RouteChangeTask::~RouteChangeTask()
563  {
564 
565  }
566 
567  std::string StaticRoutingExtension::RouteChangeTask::toString()
568  {
569  return "RouteChangeTask: " + (*route).toString();
570  }
571 
572  /****************************************/
573 
574  StaticRoutingExtension::ExpireTask::ExpireTask(dtn::data::Timestamp t)
575  : timestamp(t)
576  {
577 
578  }
579 
580  StaticRoutingExtension::ExpireTask::~ExpireTask()
581  {
582 
583  }
584 
585  std::string StaticRoutingExtension::ExpireTask::toString()
586  {
587  std::stringstream ss;
588  ss << "ExpireTask: " << timestamp.toString();
589  return ss.str();
590  }
591  }
592 }