IBR-DTN  1.0.0
NeighborRoutingExtension.cpp
Go to the documentation of this file.
1 /*
2  * NeighborRoutingExtension.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"
25 #include "core/BundleCore.h"
28 #include "net/ConnectionEvent.h"
29 #include "core/NodeEvent.h"
30 #include "core/Node.h"
31 #include "net/ConnectionManager.h"
32 #include "ibrcommon/thread/MutexLock.h"
33 #include "storage/BundleStorage.h"
34 #include "core/BundleEvent.h"
35 #include <ibrcommon/Logger.h>
36 
37 #ifdef HAVE_SQLITE
39 #endif
40 
41 #include <functional>
42 #include <list>
43 #include <algorithm>
44 #include <typeinfo>
45 #include <memory>
46 
47 namespace dtn
48 {
49  namespace routing
50  {
51  const std::string NeighborRoutingExtension::TAG = "NeighborRoutingExtension";
52 
54  {
55  }
56 
58  {
59  join();
60  }
61 
63  {
64  _taskqueue.abort();
65  }
66 
68  {
69 #ifdef HAVE_SQLITE
71 #else
73 #endif
74  {
75  public:
77  : _extension(e), _entry(entry), _plist(plist)
78  {};
79 
80  virtual ~BundleFilter() {};
81 
82  virtual dtn::data::Size limit() const throw () { return _entry.getFreeTransferSlots(); };
83 
84  virtual bool addIfSelected(dtn::storage::BundleResult &result, const dtn::data::MetaBundle &meta) const throw (dtn::storage::BundleSelectorException)
85  {
86  // check if the considered bundle should get routed
87  std::pair<bool, dtn::core::Node::Protocol> ret = _extension.shouldRouteTo(meta, _entry, _plist);
88 
89  // put the considered bundle into the result-set if it should get routed
90  if (ret.first) static_cast<RoutingResult&>(result).put(meta, ret.second);
91 
92  // signal that selection to the calling module
93  return ret.first;
94  };
95 
96 #ifdef HAVE_SQLITE
97  const std::string getWhere() const throw ()
98  {
99  return "destination LIKE ?";
100  };
101 
102  int bind(sqlite3_stmt *st, int offset) const throw ()
103  {
104  const std::string d = _entry.eid.getNode().getString() + "%";
105  sqlite3_bind_text(st, offset, d.c_str(), static_cast<int>(d.size()), SQLITE_TRANSIENT);
106  return offset + 1;
107  }
108 #endif
109 
110  private:
111  NeighborRoutingExtension &_extension;
112  const NeighborDatabase::NeighborEntry &_entry;
114  };
115 
116  RoutingResult list;
117 
118  while (true)
119  {
120  NeighborDatabase &db = (**this).getNeighborDB();
121 
122  try {
123  Task *t = _taskqueue.poll();
124  std::auto_ptr<Task> killer(t);
125 
126  IBRCOMMON_LOGGER_DEBUG_TAG(NeighborRoutingExtension::TAG, 5) << "processing task " << t->toString() << IBRCOMMON_LOGGER_ENDL;
127 
133  try {
134  SearchNextBundleTask &task = dynamic_cast<SearchNextBundleTask&>(*t);
135 
136  // clear the result list
137  list.clear();
138 
139  // lock the neighbor database while searching for bundles
140  {
141  // this destination is not handles by any static route
142  ibrcommon::MutexLock l(db);
143  NeighborDatabase::NeighborEntry &entry = db.get(task.eid, true);
144 
145  // check if enough transfer slots available (threshold reached)
146  if (!entry.isTransferThresholdReached())
148 
149  // get a list of protocols supported by both, the local BPA and the remote peer
152 
153  // create a new bundle filter
154  BundleFilter filter(*this, entry, plist);
155 
156  // query an unknown bundle from the storage, the list contains max. 10 items.
157  (**this).getSeeker().get(filter, list);
158  }
159 
160  IBRCOMMON_LOGGER_DEBUG_TAG(NeighborRoutingExtension::TAG, 5) << "got " << list.size() << " items to transfer to " << task.eid.getString() << IBRCOMMON_LOGGER_ENDL;
161 
162  // send the bundles as long as we have resources
163  for (RoutingResult::const_iterator iter = list.begin(); iter != list.end(); ++iter)
164  {
165  try {
166  // transfer the bundle to the neighbor
167  transferTo(task.eid, (*iter).first, (*iter).second);
168  } catch (const NeighborDatabase::AlreadyInTransitException&) { };
169  }
170  } catch (const NeighborDatabase::NoMoreTransfersAvailable &ex) {
171  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "task " << t->toString() << " aborted: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
172  } catch (const NeighborDatabase::EntryNotFoundException &ex) {
173  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "task " << t->toString() << " aborted: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
174  } catch (const NodeNotAvailableException &ex) {
175  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "task " << t->toString() << " aborted: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
176  } catch (const dtn::storage::NoBundleFoundException &ex) {
177  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "task " << t->toString() << " aborted: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
178  } catch (const std::bad_cast&) { };
179 
183  try {
184  const ProcessBundleTask &task = dynamic_cast<ProcessBundleTask&>(*t);
185 
186  // variable to store the result of shouldRouteTo()
187  std::pair<bool, dtn::core::Node::Protocol> ret;
188 
189  // get a list of protocols supported by both, the local BPA and the remote peer
192 
193  // lock the neighbor database while searching for bundles
194  {
195  // this destination is not handles by any static route
196  ibrcommon::MutexLock l(db);
197  NeighborDatabase::NeighborEntry &entry = db.get(task.nexthop, true);
198 
199  ret = shouldRouteTo(task.bundle, entry, plist);
200  if (!ret.first) throw NeighborDatabase::NoRouteKnownException();
201  }
202 
203  // transfer the bundle to the neighbor
204  transferTo(task.nexthop, task.bundle, ret.second);
205  } catch (const NeighborDatabase::AlreadyInTransitException &ex) {
206  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "task " << t->toString() << " aborted: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
207  } catch (const NeighborDatabase::NoMoreTransfersAvailable &ex) {
208  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "task " << t->toString() << " aborted: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
209  } catch (const NeighborDatabase::EntryNotFoundException &ex) {
210  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "task " << t->toString() << " aborted: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
211  } catch (const NodeNotAvailableException &ex) {
212  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "task " << t->toString() << " aborted: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
213  } catch (const NeighborDatabase::NoRouteKnownException &ex) {
214  // nothing to do here.
215  } catch (const std::bad_cast&) { };
216  } catch (const std::exception &ex) {
217  IBRCOMMON_LOGGER_DEBUG_TAG(NeighborRoutingExtension::TAG, 15) << "terminated due to " << ex.what() << IBRCOMMON_LOGGER_ENDL;
218  return;
219  }
220 
221  yield();
222  }
223  }
224 
225  std::pair<bool, dtn::core::Node::Protocol> NeighborRoutingExtension::shouldRouteTo(const dtn::data::MetaBundle &meta, const NeighborDatabase::NeighborEntry &n, const dtn::net::ConnectionManager::protocol_list &plist) const
226  {
227  // check Scope Control Block - do not forward bundles with hop limit == 0
228  if (meta.hopcount == 0)
229  {
230  return make_pair(false, dtn::core::Node::CONN_UNDEFINED);
231  }
232 
234  {
235  // do not forward local bundles
237  {
238  return make_pair(false, dtn::core::Node::CONN_UNDEFINED);
239  }
240 
241  // do not forward bundles for other nodes
242  if (!meta.destination.sameHost(n.eid))
243  {
244  return make_pair(false, dtn::core::Node::CONN_UNDEFINED);
245  }
246  }
247  else
248  {
249  // do not forward non-singleton bundles
250  return make_pair(false, dtn::core::Node::CONN_UNDEFINED);
251  }
252 
253  // do not forward bundles already known by the destination
254  if (n.has(meta))
255  {
256  return make_pair(false, dtn::core::Node::CONN_UNDEFINED);
257  }
258 
259  // update filter context
260  dtn::core::FilterContext context;
261  context.setPeer(n.eid);
262  context.setRouting(*this);
263  context.setMetaBundle(meta);
264 
265  // check bundle filter for each possible path
266  for (dtn::net::ConnectionManager::protocol_list::const_iterator it = plist.begin(); it != plist.end(); ++it)
267  {
268  const dtn::core::Node::Protocol &p = (*it);
269 
270  // update context with current protocol
271  context.setProtocol(p);
272 
273  // execute filtering
275 
277  {
278  // put the selected bundle with targeted interface into the result-set
279  return make_pair(true, p);
280  }
281  }
282 
283  return make_pair(false, dtn::core::Node::CONN_UNDEFINED);
284  }
285 
287  {
288  // transfer the next bundle to this destination
289  _taskqueue.push( new SearchNextBundleTask( peer ) );
290  }
291 
293  {
294  // try to deliver new bundles to all neighbors
295  const std::set<dtn::core::Node> nl = dtn::core::BundleCore::getInstance().getConnectionManager().getNeighbors();
296 
297  for (std::set<dtn::core::Node>::const_iterator iter = nl.begin(); iter != nl.end(); ++iter)
298  {
299  const dtn::core::Node &n = (*iter);
300 
301  if (n.getEID() != peer) {
302  // transfer the next bundle to this destination
303  _taskqueue.push( new ProcessBundleTask(meta, peer, n.getEID()) );
304  }
305  }
306  }
307 
309  {
310  // reset the task queue
311  _taskqueue.reset();
312 
313  // routine checked for throw() on 15.02.2013
314  try {
315  // run the thread
316  start();
317  } catch (const ibrcommon::ThreadException &ex) {
318  IBRCOMMON_LOGGER_TAG(NeighborRoutingExtension::TAG, error) << "componentUp failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
319  }
320  }
321 
323  {
324  // routine checked for throw() on 15.02.2013
325  try {
326  // stop the thread
327  stop();
328  join();
329  } catch (const ibrcommon::ThreadException &ex) {
330  IBRCOMMON_LOGGER_TAG(NeighborRoutingExtension::TAG, error) << "componentDown failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
331  }
332  }
333 
334  const std::string NeighborRoutingExtension::getTag() const throw ()
335  {
336  return "neighbor";
337  }
338 
339  /****************************************/
340 
341  NeighborRoutingExtension::SearchNextBundleTask::SearchNextBundleTask(const dtn::data::EID &e)
342  : eid(e)
343  { }
344 
345  NeighborRoutingExtension::SearchNextBundleTask::~SearchNextBundleTask()
346  { }
347 
348  std::string NeighborRoutingExtension::SearchNextBundleTask::toString()
349  {
350  return "SearchNextBundleTask: " + eid.getString();
351  }
352 
353  /****************************************/
354 
355  NeighborRoutingExtension::ProcessBundleTask::ProcessBundleTask(const dtn::data::MetaBundle &meta, const dtn::data::EID &o, const dtn::data::EID &n)
356  : bundle(meta), origin(o), nexthop(n)
357  { }
358 
359  NeighborRoutingExtension::ProcessBundleTask::~ProcessBundleTask()
360  { }
361 
362  std::string NeighborRoutingExtension::ProcessBundleTask::toString()
363  {
364  return "ProcessBundleTask: " + bundle.toString();
365  }
366  }
367 }
const std::set< dtn::core::Node > getNeighbors()
static dtn::data::EID local
Definition: BundleCore.h:79
bool get(dtn::data::PrimaryBlock::FLAGS flag) const
Definition: MetaBundle.cpp:160
bool sameHost(const std::string &other) const
Definition: EID.cpp:322
std::list< dtn::core::Node::Protocol > protocol_list
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
BundleFilter::ACTION evaluate(BundleFilter::TABLE table, const FilterContext &context) const
Definition: BundleCore.cpp:617
void setProtocol(const dtn::core::Node::Protocol &protocol)
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)
const protocol_set getSupportedProtocols()
virtual const std::string getTag() const
dtn::data::EID destination
Definition: MetaBundle.h:60
size_t Size
Definition: Number.h:34
const dtn::data::EID & getEID() const
Definition: Node.cpp:406
void setRouting(const dtn::routing::RoutingExtension &routing)
virtual void eventBundleQueued(const dtn::data::EID &peer, const dtn::data::MetaBundle &meta)
virtual void eventDataChanged(const dtn::data::EID &peer)
static BundleCore & getInstance()
Definition: BundleCore.cpp:82