IBR-DTNSuite  0.12
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"
24 #include "net/ConnectionEvent.h"
25 #include "core/EventDispatcher.h"
26 #include "core/NodeEvent.h"
27 #include "core/BundleEvent.h"
28 #include "core/BundleCore.h"
29 #include "core/NodeEvent.h"
30 #include "core/TimeEvent.h"
31 #include "core/GlobalEvent.h"
32 
33 #include <ibrdtn/utils/Clock.h>
34 #include <ibrcommon/Logger.h>
35 
36 #include <iostream>
37 #include <iomanip>
38 #include <algorithm>
39 #include <functional>
40 #include <typeinfo>
41 
42 using namespace dtn::core;
43 
44 namespace dtn
45 {
46  namespace net
47  {
48  struct CompareNodeDestination:
49  public std::binary_function< dtn::core::Node, dtn::data::EID, bool > {
50  bool operator() ( const dtn::core::Node &node, const dtn::data::EID &destination ) const {
51  return node.getEID() == destination;
52  }
53  };
54 
55  ConnectionManager::ConnectionManager()
56  : _next_autoconnect(0)
57  {
58  }
59 
61  {
62  }
63 
65  {
66  // routine checked for throw() on 15.02.2013
71 
72  // set next auto connect
74  if (nc.getAutoConnect() != 0)
75  {
76  _next_autoconnect = dtn::utils::Clock::getTime() + nc.getAutoConnect();
77  }
78  }
79 
81  {
82  {
83  ibrcommon::MutexLock l(_cl_lock);
84  // clear the list of convergence layers
85  _cl.clear();
86  }
87 
88  {
89  ibrcommon::MutexLock l(_node_lock);
90  // clear the node list
91  _nodes.clear();
92  }
93 
94  _next_autoconnect = 0;
95 
100  }
101 
103  {
104  try {
105  const NodeEvent &nodeevent = dynamic_cast<const NodeEvent&>(*evt);
106 
107  ibrcommon::MutexLock l(_node_lock);
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.getState())
145  {
147  {
148  add(connection.getNode());
149  break;
150  }
151 
153  {
154  remove(connection.getNode());
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  // If node contains MCL
184  if(n.has(Node::CONN_EMAIL) && !n.getEID().getScheme().compare("mail") == 0)
185  {
186  dtn::core::Node node = n;
187 
188  std::list<Node::URI> uri = node.get(Node::CONN_EMAIL);
189  for(std::list<Node::URI>::iterator iter = uri.begin(); iter != uri.end(); iter++)
190  {
191  std::string address;
192  unsigned int port;
193  (*iter).decode(address, port);
194 
195  dtn::core::Node fakeNode("mail://" + address);
196 
197  fakeNode.add(Node::URI((*iter).type, Node::CONN_EMAIL, "email=" + address + ";", (*iter).expire - dtn::utils::Clock::getTime(), (*iter).priority));
198 
199  // Announce faked node
200  updateNeighbor(fakeNode);
201 
202  // Add route to faked node
204 
205  node.remove((*iter));
206 
207  if(node.getAll().size() == 0)
208  return;
209  }
210 
211  updateNeighbor(node);
212 
213  return;
214  }
215 
216  ibrcommon::MutexLock l(_node_lock);
217  pair<nodemap::iterator,bool> ret = _nodes.insert( pair<dtn::data::EID, dtn::core::Node>(n.getEID(), n) );
218 
219  dtn::core::Node &db = (*(ret.first)).second;
220 
221  if (!ret.second) {
222  dtn::data::Size old = db.size();
223 
224  // add all attributes to the node in the database
225  db += n;
226 
227  if (old != db.size()) {
228  // announce the new node
230  }
231  } else {
232  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 56) << "New node available: " << db << IBRCOMMON_LOGGER_ENDL;
233  }
234 
235  if (db.isAvailable() && !db.isAnnounced()) {
236  db.setAnnounced(true);
237 
238  // announce the new node
240  }
241  }
242 
244  {
245  ibrcommon::MutexLock l(_node_lock);
246  try {
247  dtn::core::Node &db = getNode(n.getEID());
248 
249  dtn::data::Size old = db.size();
250 
251  // erase all attributes to the node in the database
252  db -= n;
253 
254  if (old != db.size()) {
255  // announce the new node
257  }
258 
259  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 56) << "Node attributes removed: " << db << IBRCOMMON_LOGGER_ENDL;
260  } catch (const NeighborNotAvailableException&) { };
261  }
262 
264  {
265  ibrcommon::MutexLock l(_cl_lock);
266  _cl.insert( cl );
267  }
268 
270  {
271  ibrcommon::MutexLock l(_cl_lock);
272  _cl.erase( cl );
273  }
274 
276  {
277  ibrcommon::MutexLock l(_cl_lock);
278  for (std::set<ConvergenceLayer*>::const_iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
279  {
280  ConvergenceLayer &cl = (**iter);
281  cl.getStats(data);
282  }
283  }
284 
286  {
287  ibrcommon::MutexLock l(_cl_lock);
288  for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
289  {
290  ConvergenceLayer &cl = (**iter);
291  cl.resetStats();
292  }
293  }
294 
296  {
297  ibrcommon::MutexLock l(_dialup_lock);
298  _dialups.insert(ext);
299  }
300 
302  {
303  ibrcommon::MutexLock l(_dialup_lock);
304  _dialups.erase(ext);
305  }
306 
308  {
309  // ignore messages of ourself
310  if (node.getEID() == dtn::core::BundleCore::local) return;
311 
312  // add node or its attributes to the database
313  add(node);
314  }
315 
316  void ConnectionManager::check_available()
317  {
318  ibrcommon::MutexLock l(_node_lock);
319 
320  // search for outdated nodes
321  for (nodemap::iterator iter = _nodes.begin(); iter != _nodes.end(); ++iter)
322  {
323  dtn::core::Node &n = (*iter).second;
324  if (n.isAnnounced()) continue;
325 
326  if (n.isAvailable()) {
327  n.setAnnounced(true);
328 
329  // announce the unavailable event
331  }
332  }
333  }
334 
335  void ConnectionManager::check_unavailable()
336  {
337  ibrcommon::MutexLock l(_node_lock);
338 
339  // search for outdated nodes
340  nodemap::iterator iter = _nodes.begin();
341  while ( iter != _nodes.end() )
342  {
343  dtn::core::Node &n = (*iter).second;
344  if (!n.isAnnounced()) {
345  ++iter;
346  continue;
347  }
348 
349  if ( !n.isAvailable() ) {
350  n.setAnnounced(false);
351 
352  // announce the unavailable event
354  }
355 
356  if ( n.expire() )
357  {
358  if (n.isAnnounced()) {
359  // announce the unavailable event
361  }
362 
363  // remove the element
364  _nodes.erase( iter++ );
365  }
366  else
367  {
368  ++iter;
369  }
370  }
371  }
372 
373  void ConnectionManager::check_autoconnect()
374  {
375  std::queue<dtn::core::Node> connect_nodes;
376 
378  if (interval == 0) return;
379 
380  if (_next_autoconnect < dtn::utils::Clock::getTime())
381  {
382  // search for non-connected but available nodes
383  ibrcommon::MutexLock l(_node_lock);
384  for (nodemap::const_iterator iter = _nodes.begin(); iter != _nodes.end(); ++iter)
385  {
386  const Node &n = (*iter).second;
387  std::list<Node::URI> ul = n.get(Node::NODE_CONNECTED, Node::CONN_TCPIP);
388 
389  if (ul.empty() && n.isAvailable())
390  {
391  connect_nodes.push(n);
392  }
393  }
394 
395  // set the next check time
396  _next_autoconnect = dtn::utils::Clock::getTime() + interval;
397  }
398 
399  while (!connect_nodes.empty())
400  {
401  try {
402  open(connect_nodes.front());
403  } catch (const ibrcommon::Exception&) {
404  // ignore errors
405  }
406  connect_nodes.pop();
407  }
408  }
409 
411  {
412  // lock convergence layers while iterating over them
413  {
414  ibrcommon::MutexLock l(_cl_lock);
415 
416  // search for the right cl
417  for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
418  {
419  ConvergenceLayer *cl = (*iter);
420  if (node.has(cl->getDiscoveryProtocol()))
421  {
422  cl->open(node);
423 
424  // stop here, we queued the bundle already
425  return;
426  }
427  }
428  }
429 
430  // throw dial-up exception if there are P2P dial-up connections available
431  if (node.hasDialup())
432  {
433  // trigger the dial-up connection
434  dialup(node);
435 
437  }
438 
440  }
441 
442  void ConnectionManager::dialup(const dtn::core::Node &n)
443  {
444  // search for p2p_dialup connections
445  // get the list of all available URIs
446  std::list<Node::URI> uri_list = n.get(Node::NODE_P2P_DIALUP);
447 
448  // trigger p2p_dialup connections
449  for (std::list<Node::URI>::const_iterator it = uri_list.begin(); it != uri_list.end(); ++it)
450  {
451  const dtn::core::Node::URI &uri = (*it);
452 
453  ibrcommon::MutexLock l(_dialup_lock);
454  for (std::set<P2PDialupExtension*>::iterator iter = _dialups.begin(); iter != _dialups.end(); ++iter)
455  {
456  P2PDialupExtension &p2pext = (**iter);
457 
458  if (uri.protocol == p2pext.getProtocol()) {
459  // trigger connection set-up
460  p2pext.connect(uri);
461  }
462  }
463  }
464  }
465 
467  {
468  // get the list of all available URIs
469  std::list<Node::URI> uri_list = node.getAll();
470 
471  // search for a match between URI and available convergence layer
472  for (std::list<Node::URI>::const_iterator it = uri_list.begin(); it != uri_list.end(); ++it)
473  {
474  const Node::URI &uri = (*it);
475 
476  // lock convergence layers while iterating over them
477  ibrcommon::MutexLock l(_cl_lock);
478 
479  // search a matching convergence layer for this URI
480  for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
481  {
482  ConvergenceLayer *cl = (*iter);
483  if (cl->getDiscoveryProtocol() == uri.protocol)
484  {
485  cl->queue(node, job);
486 
487  // stop here, we queued the bundle already
488  return;
489  }
490  }
491  }
492 
493  // throw dial-up exception if there are P2P dial-up connections available
494  if (node.hasDialup()) throw P2PDialupException();
495 
497  }
498 
500  {
501  ibrcommon::MutexLock l(_node_lock);
502 
503  if (IBRCOMMON_LOGGER_LEVEL >= 50)
504  {
505  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 50) << "## node list ##" << IBRCOMMON_LOGGER_ENDL;
506  for (nodemap::const_iterator iter = _nodes.begin(); iter != _nodes.end(); ++iter)
507  {
508  const dtn::core::Node &n = (*iter).second;
509  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 2) << n << IBRCOMMON_LOGGER_ENDL;
510  }
511  }
512 
513  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 50) << "search for node " << job.getNeighbor().getString() << IBRCOMMON_LOGGER_ENDL;
514 
515  try {
516  // queue to a node
517  const Node &n = getNode(job.getNeighbor());
518  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 2) << "next hop: " << n << IBRCOMMON_LOGGER_ENDL;
519 
520  try {
521  queue(n, job);
522  } catch (const P2PDialupException&) {
523  // trigger the dial-up connection
524  dialup(n);
525 
526  // re-throw P2PDialupException
527  throw;
528  }
529  } catch (const dtn::net::NeighborNotAvailableException &ex) {
530  // signal interruption of the transfer
532  }
533  }
534 
535  const std::set<dtn::core::Node> ConnectionManager::getNeighbors()
536  {
537  ibrcommon::MutexLock l(_node_lock);
538 
539  std::set<dtn::core::Node> ret;
540 
541  for (nodemap::const_iterator iter = _nodes.begin(); iter != _nodes.end(); ++iter)
542  {
543  const Node &n = (*iter).second;
544  if (n.isAvailable()) ret.insert( n );
545  }
546 
547  return ret;
548  }
549 
551  {
552  ibrcommon::MutexLock l(_node_lock);
553  const Node &n = getNode(eid);
554  if (n.isAvailable()) return n;
555 
557  }
558 
560  {
561  try {
562  ibrcommon::MutexLock l(_node_lock);
563  const Node &n = getNode(node.getEID());
564  if (n.isAvailable()) return true;
565  } catch (const NeighborNotAvailableException&) { }
566 
567  return false;
568  }
569 
571  {
572  discovered(n);
573  }
574 
575  const std::string ConnectionManager::getName() const
576  {
577  return "ConnectionManager";
578  }
579 
580  dtn::core::Node& ConnectionManager::getNode(const dtn::data::EID &eid) throw (NeighborNotAvailableException)
581  {
582  nodemap::iterator iter = _nodes.find(eid);
583  if (iter == _nodes.end()) throw NeighborNotAvailableException("neighbor not found");
584  return (*iter).second;
585  }
586  }
587 }