IBR-DTNSuite  0.10
ConnectionManager.cpp
Go to the documentation of this file.
1 /*
2  * ConnectionManager.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 "Configuration.h"
23 #include "net/ConnectionManager.h"
26 #include "net/ConnectionEvent.h"
27 #include "core/EventDispatcher.h"
28 #include "core/NodeEvent.h"
29 #include "core/BundleEvent.h"
30 #include "core/BundleCore.h"
31 #include "core/NodeEvent.h"
32 #include "core/TimeEvent.h"
33 #include "core/GlobalEvent.h"
34 
35 #include <ibrdtn/utils/Clock.h>
36 #include <ibrcommon/Logger.h>
37 
38 #include <iostream>
39 #include <iomanip>
40 #include <algorithm>
41 #include <functional>
42 #include <typeinfo>
43 
44 using namespace dtn::core;
45 
46 namespace dtn
47 {
48  namespace net
49  {
50  struct CompareNodeDestination:
51  public std::binary_function< dtn::core::Node, dtn::data::EID, bool > {
52  bool operator() ( const dtn::core::Node &node, const dtn::data::EID &destination ) const {
53  return node.getEID() == destination;
54  }
55  };
56 
57  ConnectionManager::ConnectionManager()
58  : _next_autoconnect(0)
59  {
60  }
61 
63  {
64  }
65 
67  {
68  // routine checked for throw() on 15.02.2013
73 
74  // set next auto connect
76  if (nc.getAutoConnect() != 0)
77  {
78  _next_autoconnect = dtn::utils::Clock::getTime() + nc.getAutoConnect();
79  }
80  }
81 
83  {
84  {
85  ibrcommon::MutexLock l(_cl_lock);
86  // clear the list of convergence layers
87  _cl.clear();
88  }
89 
90  {
91  ibrcommon::MutexLock l(_node_lock);
92  // clear the node list
93  _nodes.clear();
94  }
95 
96  _next_autoconnect = 0;
97 
102  }
103 
105  {
106  try {
107  const NodeEvent &nodeevent = dynamic_cast<const NodeEvent&>(*evt);
108  const Node &n = nodeevent.getNode();
109 
110  switch (nodeevent.getAction())
111  {
112  case NODE_AVAILABLE:
113  if (n.doConnectImmediately())
114  {
115  try {
116  // open the connection immediately
117  open(n);
118  } catch (const ibrcommon::Exception&) {
119  // ignore errors
120  }
121  }
122  break;
123 
124  default:
125  break;
126  }
127  return;
128  } catch (const std::bad_cast&) { }
129 
130  try {
131  const TimeEvent &timeevent = dynamic_cast<const TimeEvent&>(*evt);
132 
133  if (timeevent.getAction() == TIME_SECOND_TICK)
134  {
135  check_unavailable();
136  check_autoconnect();
137  }
138  return;
139  } catch (const std::bad_cast&) { }
140 
141  try {
142  const ConnectionEvent &connection = dynamic_cast<const ConnectionEvent&>(*evt);
143 
144  switch (connection.state)
145  {
147  {
148  add(connection.node);
149  break;
150  }
151 
153  {
154  remove(connection.node);
155  break;
156  }
157 
158  default:
159  break;
160  }
161  return;
162  } catch (const std::bad_cast&) { }
163 
164  try {
165  const dtn::core::GlobalEvent &global = dynamic_cast<const dtn::core::GlobalEvent&>(*evt);
166  switch (global.getAction()) {
167  case GlobalEvent::GLOBAL_INTERNET_AVAILABLE:
168  check_available();
169  break;
170 
171  case GlobalEvent::GLOBAL_INTERNET_UNAVAILABLE:
172  check_unavailable();
173  break;
174 
175  default:
176  break;
177  }
178  } catch (const std::bad_cast&) { };
179  }
180 
182  {
183  ibrcommon::MutexLock l(_node_lock);
184  pair<nodemap::iterator,bool> ret = _nodes.insert( pair<dtn::data::EID, dtn::core::Node>(n.getEID(), n) );
185 
186  dtn::core::Node &db = (*(ret.first)).second;
187 
188  if (!ret.second) {
189  dtn::data::Size old = db.size();
190 
191  // add all attributes to the node in the database
192  db += n;
193 
194  if (old != db.size()) {
195  // announce the new node
197  }
198  } else {
199  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 56) << "New node available: " << db << IBRCOMMON_LOGGER_ENDL;
200  }
201 
202  if (db.isAvailable() && !db.isAnnounced()) {
203  db.setAnnounced(true);
204 
205  // announce the new node
207  }
208  }
209 
211  {
212  ibrcommon::MutexLock l(_node_lock);
213  try {
214  dtn::core::Node &db = getNode(n.getEID());
215 
216  dtn::data::Size old = db.size();
217 
218  // erase all attributes to the node in the database
219  db -= n;
220 
221  if (old != db.size()) {
222  // announce the new node
224  }
225 
226  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 56) << "Node attributes removed: " << db << IBRCOMMON_LOGGER_ENDL;
227  } catch (const NeighborNotAvailableException&) { };
228  }
229 
231  {
232  ibrcommon::MutexLock l(_cl_lock);
233  _cl.insert( cl );
234  }
235 
237  {
238  ibrcommon::MutexLock l(_cl_lock);
239  _cl.erase( cl );
240  }
241 
243  {
244  ibrcommon::MutexLock l(_cl_lock);
245  stats_list stats;
246 
247  for (std::set<ConvergenceLayer*>::const_iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
248  {
249  ConvergenceLayer &cl = (**iter);
250  const ConvergenceLayer::stats_map &cl_stats = cl.getStats();
252 
253  stats_pair entry;
254  entry.first = p;
255  entry.second = cl_stats;
256 
257  stats.push_back(entry);
258  }
259 
260  return stats;
261  }
262 
264  {
265  ibrcommon::MutexLock l(_cl_lock);
266  for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
267  {
268  ConvergenceLayer &cl = (**iter);
269  cl.resetStats();
270  }
271  }
272 
274  {
275  ibrcommon::MutexLock l(_dialup_lock);
276  _dialups.insert(ext);
277  }
278 
280  {
281  ibrcommon::MutexLock l(_dialup_lock);
282  _dialups.erase(ext);
283  }
284 
286  {
287  // ignore messages of ourself
288  if (node.getEID() == dtn::core::BundleCore::local) return;
289 
290  // add node or its attributes to the database
291  add(node);
292  }
293 
294  void ConnectionManager::check_available()
295  {
296  ibrcommon::MutexLock l(_node_lock);
297 
298  // search for outdated nodes
299  for (nodemap::iterator iter = _nodes.begin(); iter != _nodes.end(); ++iter)
300  {
301  dtn::core::Node &n = (*iter).second;
302  if (n.isAnnounced()) continue;
303 
304  if (n.isAvailable()) {
305  n.setAnnounced(true);
306 
307  // announce the unavailable event
309  }
310  }
311  }
312 
313  void ConnectionManager::check_unavailable()
314  {
315  ibrcommon::MutexLock l(_node_lock);
316 
317  // search for outdated nodes
318  nodemap::iterator iter = _nodes.begin();
319  while ( iter != _nodes.end() )
320  {
321  dtn::core::Node &n = (*iter).second;
322  if (!n.isAnnounced()) {
323  ++iter;
324  continue;
325  }
326 
327  if ( !n.isAvailable() ) {
328  n.setAnnounced(false);
329 
330  // announce the unavailable event
332  }
333 
334  if ( n.expire() )
335  {
336  if (n.isAnnounced()) {
337  // announce the unavailable event
339  }
340 
341  // remove the element
342  _nodes.erase( iter++ );
343  }
344  else
345  {
346  ++iter;
347  }
348  }
349  }
350 
351  void ConnectionManager::check_autoconnect()
352  {
353  std::queue<dtn::core::Node> _connect_nodes;
354 
356  if (interval == 0) return;
357 
358  if (_next_autoconnect < dtn::utils::Clock::getTime())
359  {
360  // search for non-connected but available nodes
361  ibrcommon::MutexLock l(_cl_lock);
362  for (nodemap::const_iterator iter = _nodes.begin(); iter != _nodes.end(); ++iter)
363  {
364  const Node &n = (*iter).second;
365  std::list<Node::URI> ul = n.get(Node::NODE_CONNECTED, Node::CONN_TCPIP);
366 
367  if (ul.empty() && n.isAvailable())
368  {
369  _connect_nodes.push(n);
370  }
371  }
372 
373  // set the next check time
374  _next_autoconnect = dtn::utils::Clock::getTime() + interval;
375  }
376 
377  while (!_connect_nodes.empty())
378  {
379  try {
380  open(_connect_nodes.front());
381  } catch (const ibrcommon::Exception&) {
382  // ignore errors
383  }
384  _connect_nodes.pop();
385  }
386  }
387 
389  {
390  ibrcommon::MutexLock l(_cl_lock);
391 
392  // search for the right cl
393  for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
394  {
395  ConvergenceLayer *cl = (*iter);
396  if (node.has(cl->getDiscoveryProtocol()))
397  {
398  cl->open(node);
399 
400  // stop here, we queued the bundle already
401  return;
402  }
403  }
404 
405  // throw dial-up exception if there are P2P dial-up connections available
406  if (node.hasDialup())
407  {
408  // trigger the dial-up connection
409  dialup(node);
410 
412  }
413 
415  }
416 
417  void ConnectionManager::dialup(const dtn::core::Node &n)
418  {
419  // search for p2p_dialup connections
420  ibrcommon::MutexLock l(_cl_lock);
421 
422  // get the list of all available URIs
423  std::list<Node::URI> uri_list = n.get(Node::NODE_P2P_DIALUP);
424 
425  // trigger p2p_dialup connections
426  for (std::list<Node::URI>::const_iterator it = uri_list.begin(); it != uri_list.end(); ++it)
427  {
428  const dtn::core::Node::URI &uri = (*it);
429 
430  ibrcommon::MutexLock l(_dialup_lock);
431  for (std::set<P2PDialupExtension*>::iterator iter = _dialups.begin(); iter != _dialups.end(); ++iter)
432  {
433  P2PDialupExtension &p2pext = (**iter);
434 
435  if (uri.protocol == p2pext.getProtocol()) {
436  // trigger connection set-up
437  p2pext.connect(uri);
438  }
439  }
440  }
441  }
442 
444  {
445  ibrcommon::MutexLock l(_cl_lock);
446 
447  // get the list of all available URIs
448  std::list<Node::URI> uri_list = node.getAll();
449 
450  // search for a match between URI and available convergence layer
451  for (std::list<Node::URI>::const_iterator it = uri_list.begin(); it != uri_list.end(); ++it)
452  {
453  const Node::URI &uri = (*it);
454 
455  // search a matching convergence layer for this URI
456  for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
457  {
458  ConvergenceLayer *cl = (*iter);
459  if (cl->getDiscoveryProtocol() == uri.protocol)
460  {
461  cl->queue(node, job);
462 
463  // stop here, we queued the bundle already
464  return;
465  }
466  }
467  }
468 
469  // throw dial-up exception if there are P2P dial-up connections available
470  if (node.hasDialup()) throw P2PDialupException();
471 
473  }
474 
476  {
477  ibrcommon::MutexLock l(_node_lock);
478 
479  if (IBRCOMMON_LOGGER_LEVEL >= 50)
480  {
481  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 50) << "## node list ##" << IBRCOMMON_LOGGER_ENDL;
482  for (nodemap::const_iterator iter = _nodes.begin(); iter != _nodes.end(); ++iter)
483  {
484  const dtn::core::Node &n = (*iter).second;
485  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 2) << n << IBRCOMMON_LOGGER_ENDL;
486  }
487  }
488 
489  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 50) << "search for node " << job.getNeighbor().getString() << IBRCOMMON_LOGGER_ENDL;
490 
491  // queue to a node
492  const Node &n = getNode(job.getNeighbor());
493  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 2) << "next hop: " << n << IBRCOMMON_LOGGER_ENDL;
494 
495  try {
496  queue(n, job);
497  } catch (const P2PDialupException&) {
498  // trigger the dial-up connection
499  dialup(n);
500 
501  // re-throw P2PDialupException
502  throw;
503  }
504  }
505 
506  const std::set<dtn::core::Node> ConnectionManager::getNeighbors()
507  {
508  ibrcommon::MutexLock l(_node_lock);
509 
510  std::set<dtn::core::Node> ret;
511 
512  for (nodemap::const_iterator iter = _nodes.begin(); iter != _nodes.end(); ++iter)
513  {
514  const Node &n = (*iter).second;
515  if (n.isAvailable()) ret.insert( n );
516  }
517 
518  return ret;
519  }
520 
522  {
523  ibrcommon::MutexLock l(_node_lock);
524  const Node &n = getNode(eid);
525  if (n.isAvailable()) return n;
526 
528  }
529 
531  {
532  try {
533  ibrcommon::MutexLock l(_node_lock);
534  const Node &n = getNode(node.getEID());
535  if (n.isAvailable()) return true;
536  } catch (const NeighborNotAvailableException&) { }
537 
538  return false;
539  }
540 
542  {
543  discovered(n);
544  }
545 
546  const std::string ConnectionManager::getName() const
547  {
548  return "ConnectionManager";
549  }
550 
551  dtn::core::Node& ConnectionManager::getNode(const dtn::data::EID &eid) throw (NeighborNotAvailableException)
552  {
553  nodemap::iterator iter = _nodes.find(eid);
554  if (iter == _nodes.end()) throw NeighborNotAvailableException("neighbor not found");
555  return (*iter).second;
556  }
557  }
558 }