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