IBR-DTN  1.0.0
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 "core/EventDispatcher.h"
25 #include "core/BundleEvent.h"
26 #include "core/BundleCore.h"
27 
28 #include <ibrdtn/utils/Clock.h>
29 #include <ibrcommon/Logger.h>
30 
31 #include <iostream>
32 #include <iomanip>
33 #include <algorithm>
34 #include <functional>
35 #include <typeinfo>
36 
37 namespace dtn
38 {
39  namespace net
40  {
41  struct CompareNodeDestination:
42  public std::binary_function< dtn::core::Node, dtn::data::EID, bool > {
43  bool operator() ( const dtn::core::Node &node, const dtn::data::EID &destination ) const {
44  return node.getEID() == destination;
45  }
46  };
47 
49  : _next_autoconnect(0)
50  {
51  }
52 
54  {
55  }
56 
58  {
59  // routine checked for throw() on 15.02.2013
64 
65  // set next auto connect
67  if (nc.getAutoConnect() != 0)
68  {
69  _next_autoconnect = dtn::utils::Clock::getTime() + nc.getAutoConnect();
70  }
71  }
72 
74  {
75  {
76  ibrcommon::MutexLock l(_cl_lock);
77  // clear the list of convergence layers
78  _cl.clear();
79  _cl_protocols.clear();
80  }
81 
82  {
83  ibrcommon::MutexLock l(_node_lock);
84  // clear the node list
85  _nodes.clear();
86  }
87 
88  _next_autoconnect = 0;
89 
94  }
95 
96  void ConnectionManager::raiseEvent(const dtn::core::NodeEvent &nodeevent) throw ()
97  {
98  ibrcommon::MutexLock l(_node_lock);
99  const Node &n = nodeevent.getNode();
100 
101  switch (nodeevent.getAction())
102  {
103  case NODE_AVAILABLE:
104  if (n.doConnectImmediately())
105  {
106  try {
107  // open the connection immediately
108  open(n);
109  } catch (const ibrcommon::Exception&) {
110  // ignore errors
111  }
112  }
113  break;
114 
115  default:
116  break;
117  }
118  }
119 
120  void ConnectionManager::raiseEvent(const dtn::core::TimeEvent &timeevent) throw ()
121  {
122  if (timeevent.getAction() == TIME_SECOND_TICK)
123  {
124  check_unavailable();
125  check_autoconnect();
126  }
127  }
128 
130  {
131  switch (connection.getState())
132  {
134  {
135  add(connection.getNode());
136  break;
137  }
138 
140  {
141  remove(connection.getNode());
142  break;
143  }
144 
145  default:
146  break;
147  }
148  }
149 
151  {
152  switch (global.getAction()) {
153  case GlobalEvent::GLOBAL_INTERNET_AVAILABLE:
154  check_available();
155  break;
156 
157  case GlobalEvent::GLOBAL_INTERNET_UNAVAILABLE:
158  check_unavailable();
159  break;
160 
161  default:
162  break;
163  }
164  }
165 
166  void ConnectionManager::add(const dtn::core::Node &n) throw ()
167  {
168  // If node contains MCL
169  if(n.has(Node::CONN_EMAIL) && !n.getEID().getScheme().compare("mail") == 0)
170  {
171  dtn::core::Node node = n;
172 
173  std::list<Node::URI> uri = node.get(Node::CONN_EMAIL);
174  for(std::list<Node::URI>::iterator iter = uri.begin(); iter != uri.end(); iter++)
175  {
176  std::string address;
177  unsigned int port;
178  (*iter).decode(address, port);
179 
180  dtn::core::Node fakeNode("mail://" + address);
181 
182  fakeNode.add(Node::URI((*iter).type, Node::CONN_EMAIL, "email=" + address + ";", (*iter).expire - dtn::utils::Clock::getTime(), (*iter).priority));
183 
184  // Announce faked node
185  updateNeighbor(fakeNode);
186 
187  // Add route to faked node
189 
190  node.remove((*iter));
191 
192  if(node.getAll().size() == 0)
193  return;
194  }
195 
196  updateNeighbor(node);
197 
198  return;
199  }
200 
201  ibrcommon::MutexLock l(_node_lock);
202  pair<nodemap::iterator,bool> ret = _nodes.insert( pair<dtn::data::EID, dtn::core::Node>(n.getEID(), n) );
203 
204  dtn::core::Node &db = (*(ret.first)).second;
205 
206  if (!ret.second) {
207  dtn::data::Size old = db.size();
208 
209  // add all attributes to the node in the database
210  db += n;
211 
212  if (old != db.size()) {
213  // announce the new node
215  }
216  } else {
217  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 56) << "New node available: " << db << IBRCOMMON_LOGGER_ENDL;
218  }
219 
220  if (db.isAvailable() && !db.isAnnounced() && isReachable(db)) {
221  db.setAnnounced(true);
222 
223  // announce the new node
225  }
226  }
227 
229  {
230  ibrcommon::MutexLock l(_node_lock);
231  try {
232  dtn::core::Node &db = getNode(n.getEID());
233 
234  dtn::data::Size old = db.size();
235 
236  // erase all attributes to the node in the database
237  db -= n;
238 
239  if (old != db.size()) {
240  // announce the new node
242  }
243 
244  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 56) << "Node attributes removed: " << db << IBRCOMMON_LOGGER_ENDL;
245  } catch (const NodeNotAvailableException&) { };
246  }
247 
249  {
250  ibrcommon::MutexLock l(_cl_lock);
251  _cl.insert( cl );
252  _cl_protocols.insert( cl->getDiscoveryProtocol() );
253  }
254 
256  {
257  ibrcommon::MutexLock l(_cl_lock);
258  _cl.erase( cl );
259 
260  // update protocols
261  _cl_protocols.clear();
262  for (std::set<ConvergenceLayer*>::const_iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
263  {
264  ConvergenceLayer &cl = (**iter);
265  _cl_protocols.insert( cl.getDiscoveryProtocol() );
266  }
267  }
268 
270  {
271  ibrcommon::MutexLock l(_cl_lock);
272  for (std::set<ConvergenceLayer*>::const_iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
273  {
274  ConvergenceLayer &cl = (**iter);
275  cl.getStats(data);
276  }
277  }
278 
280  {
281  ibrcommon::MutexLock l(_cl_lock);
282  for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
283  {
284  ConvergenceLayer &cl = (**iter);
285  cl.resetStats();
286  }
287  }
288 
290  {
291  ibrcommon::MutexLock l(_dialup_lock);
292  _dialups.insert(ext);
293  }
294 
296  {
297  ibrcommon::MutexLock l(_dialup_lock);
298  _dialups.erase(ext);
299  }
300 
302  {
303  // ignore messages of ourself
304  if (node.getEID() == dtn::core::BundleCore::local) return;
305 
306  // add node or its attributes to the database
307  add(node);
308  }
309 
310  bool ConnectionManager::isReachable(const dtn::core::Node &node) throw ()
311  {
312  const std::list<Node::URI> urilist = node.getAll();
313 
314  for (std::list<Node::URI>::const_iterator uri_it = urilist.begin(); uri_it != urilist.end(); ++uri_it)
315  {
316  const Node::URI &uri = (*uri_it);
317 
318  if (uri.type == Node::NODE_P2P_DIALUP)
319  {
320  // lock P2P manager while iterating over them
321  ibrcommon::MutexLock l(_dialup_lock);
322 
323  // check if there is a P2P link opportunity
324  for (std::set<P2PDialupExtension*>::iterator iter = _dialups.begin(); iter != _dialups.end(); ++iter)
325  {
326  const P2PDialupExtension &p2pext = (**iter);
327  if (p2pext.getProtocol() == uri.protocol)
328  {
329  // link opportunity found
330  return true;
331  }
332  }
333  }
334  else
335  {
336  // lock convergence layers while iterating over them
337  ibrcommon::MutexLock l(_cl_lock);
338 
339  // check if there is a link opportunity
340  for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
341  {
342  const ConvergenceLayer &cl = (**iter);
343  if (cl.getDiscoveryProtocol() == uri.protocol)
344  {
345  // link opportunity found
346  return true;
347  }
348  }
349  }
350  }
351 
352  return false;
353  }
354 
355  void ConnectionManager::check_available()
356  {
357  ibrcommon::MutexLock l(_node_lock);
358 
359  // search for outdated nodes
360  for (nodemap::iterator iter = _nodes.begin(); iter != _nodes.end(); ++iter)
361  {
362  dtn::core::Node &n = (*iter).second;
363  if (n.isAnnounced()) continue;
364 
365  if (n.isAvailable() && isReachable(n)) {
366  n.setAnnounced(true);
367 
368  // announce the unavailable event
370  }
371  }
372  }
373 
374  void ConnectionManager::check_unavailable()
375  {
376  ibrcommon::MutexLock l(_node_lock);
377 
378  // search for outdated nodes
379  nodemap::iterator iter = _nodes.begin();
380  while ( iter != _nodes.end() )
381  {
382  dtn::core::Node &n = (*iter).second;
383  if (!n.isAnnounced()) {
384  ++iter;
385  continue;
386  }
387 
388  if ( !n.isAvailable() || !isReachable(n) ) {
389  n.setAnnounced(false);
390 
391  // announce the unavailable event
393  }
394 
395  if ( n.expire() )
396  {
397  if (n.isAnnounced()) {
398  // announce the unavailable event
400  }
401 
402  // remove the element
403  _nodes.erase( iter++ );
404  }
405  else
406  {
407  ++iter;
408  }
409  }
410  }
411 
412  void ConnectionManager::check_autoconnect()
413  {
414  std::queue<dtn::core::Node> connect_nodes;
415 
417  if (interval == 0) return;
418 
419  if (_next_autoconnect < dtn::utils::Clock::getTime())
420  {
421  // search for non-connected but available nodes
422  ibrcommon::MutexLock l(_node_lock);
423  for (nodemap::const_iterator iter = _nodes.begin(); iter != _nodes.end(); ++iter)
424  {
425  const Node &n = (*iter).second;
426  std::list<Node::URI> ul = n.get(Node::NODE_CONNECTED, Node::CONN_TCPIP);
427 
428  if (ul.empty() && n.isAvailable() && isReachable(n))
429  {
430  connect_nodes.push(n);
431  }
432  }
433 
434  // set the next check time
435  _next_autoconnect = dtn::utils::Clock::getTime() + interval;
436  }
437 
438  while (!connect_nodes.empty())
439  {
440  try {
441  open(connect_nodes.front());
442  } catch (const ibrcommon::Exception&) {
443  // ignore errors
444  }
445  connect_nodes.pop();
446  }
447  }
448 
449  void ConnectionManager::open(const dtn::core::Node &node) throw (ibrcommon::Exception)
450  {
451  const std::list<Node::URI> urilist = node.getAll();
452 
453  for (std::list<Node::URI>::const_iterator uri_it = urilist.begin(); uri_it != urilist.end(); ++uri_it)
454  {
455  const Node::URI &uri = (*uri_it);
456 
457  if (uri.type == Node::NODE_P2P_DIALUP)
458  {
459  // check if there is a P2P connection to establish
460  ibrcommon::MutexLock l(_dialup_lock);
461  for (std::set<P2PDialupExtension*>::iterator iter = _dialups.begin(); iter != _dialups.end(); ++iter)
462  {
463  P2PDialupExtension &p2pext = (**iter);
464 
465  if (uri.protocol == p2pext.getProtocol()) {
466  // trigger connection set-up
467  p2pext.connect(uri);
468  throw P2PDialupException();
469  }
470  }
471  }
472  else
473  {
474  // lock convergence layers while iterating over them
475  ibrcommon::MutexLock l(_cl_lock);
476 
477  // search for the right cl
478  for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
479  {
480  ConvergenceLayer *cl = (*iter);
481  if (cl->getDiscoveryProtocol() == uri.protocol)
482  {
483  cl->open(node);
484 
485  // stop here, we queued the bundle already
486  return;
487  }
488  }
489  }
490  }
491 
493  }
494 
496  {
497  try {
498  ibrcommon::MutexLock l(_node_lock);
499 
500  // queue to a node
501  const Node &n = getNode(job.getNeighbor());
502 
503  // debug output
504  IBRCOMMON_LOGGER_DEBUG_TAG("ConnectionManager", 2) << "next hop: " << n << IBRCOMMON_LOGGER_ENDL;
505 
506  // lock convergence layers while iterating over them
507  {
508  ibrcommon::MutexLock lcl(_cl_lock);
509 
510  // search a matching convergence layer for the desired path
511  for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); ++iter)
512  {
513  ConvergenceLayer *cl = (*iter);
514  if (cl->getDiscoveryProtocol() == job.getProtocol())
515  {
516  cl->queue(n, job);
517 
518  // stop here, we queued the bundle already
519  return;
520  }
521  }
522  }
523 
524  // check if there is a P2P connection to establish
525  {
526  ibrcommon::MutexLock ldu(_dialup_lock);
527  for (std::set<P2PDialupExtension*>::iterator iter = _dialups.begin(); iter != _dialups.end(); ++iter)
528  {
529  P2PDialupExtension &p2pext = (**iter);
530 
531  if (job.getProtocol() == p2pext.getProtocol()) {
532  // matching P2P extension found
533  // get P2P credentials
534  const std::list<Node::URI> urilist = n.get(job.getProtocol());
535 
536  // check if already connected
537  for (std::list<Node::URI>::const_iterator uri_it = urilist.begin(); uri_it != urilist.end(); ++uri_it)
538  {
539  const Node::URI &p2puri = (*uri_it);
540  if (p2puri.type == Node::NODE_CONNECTED) {
541  throw P2PDialupException();
542  } else {
543  // trigger connection set-up
544  p2pext.connect(*uri_it);
545  return;
546  }
547  }
548  }
549  }
550  }
551 
552  // signal interruption of the transfer
554  } catch (const dtn::net::NodeNotAvailableException &ex) {
555  // signal interruption of the transfer
557  }
558  }
559 
561  {
562  // lock convergence layers
563  ibrcommon::MutexLock l(_cl_lock);
564  return _cl_protocols;
565  }
566 
568  {
569  protocol_list ret;
570 
571  const dtn::core::Node node = getNeighbor(peer);
572  const std::list<Node::URI> protocols = node.getAll();
573 
574  // lock convergence layers while iterating over them
575  ibrcommon::MutexLock l(_cl_lock);
576 
577  for (std::list<Node::URI>::const_iterator iter = protocols.begin(); iter != protocols.end(); ++iter)
578  {
579  const Node::URI &uri = (*iter);
580  if (uri.type == Node::NODE_P2P_DIALUP || _cl_protocols.find(uri.protocol) != _cl_protocols.end())
581  {
582  ret.push_back(uri.protocol);
583  }
584  }
585 
586  return ret;
587  }
588 
589  const std::set<dtn::core::Node> ConnectionManager::getNeighbors()
590  {
591  ibrcommon::MutexLock l(_node_lock);
592 
593  std::set<dtn::core::Node> ret;
594 
595  for (nodemap::const_iterator iter = _nodes.begin(); iter != _nodes.end(); ++iter)
596  {
597  const Node &n = (*iter).second;
598  if (n.isAvailable() && isReachable(n)) ret.insert( n );
599  }
600 
601  return ret;
602  }
603 
605  {
606  ibrcommon::MutexLock l(_node_lock);
607  const Node &n = getNode(eid);
608  if (n.isAvailable() && isReachable(n)) return n;
609 
610  throw dtn::net::NodeNotAvailableException("Node is not reachable or not available.");
611  }
612 
614  {
615  try {
616  ibrcommon::MutexLock l(_node_lock);
617  const Node &n = getNode(node.getEID());
618  if (n.isAvailable() && isReachable(n)) return true;
619  } catch (const NodeNotAvailableException&) { }
620 
621  return false;
622  }
623 
625  {
626  discovered(n);
627  }
628 
629  const std::string ConnectionManager::getName() const
630  {
631  return "ConnectionManager";
632  }
633 
634  dtn::core::Node& ConnectionManager::getNode(const dtn::data::EID &eid) throw (NodeNotAvailableException)
635  {
636  nodemap::iterator iter = _nodes.find(eid);
637  if (iter == _nodes.end()) throw NodeNotAvailableException("node not found");
638  return (*iter).second;
639  }
640  }
641 }
static Configuration & getInstance(bool reset=false)
const std::set< dtn::core::Node > getNeighbors()
static dtn::data::EID local
Definition: BundleCore.h:79
static void add(EventReceiver< E > *receiver)
dtn::data::Size size() const
Definition: Node.cpp:308
virtual void open(const dtn::core::Node &)
bool isNeighbor(const dtn::core::Node &)
void remove(const dtn::core::Node &n)
bool isAvailable() const
Definition: Node.cpp:526
Protocol protocol
Definition: Node.h:88
std::list< dtn::core::Node::Protocol > protocol_list
static void remove(const EventReceiver< E > *receiver)
void setAnnounced(bool val)
Definition: Node.cpp:574
void getStats(dtn::net::ConvergenceLayer::stats_data &data)
void addRoute(const dtn::data::EID &destination, const dtn::data::EID &nexthop, const dtn::data::Timeout timeout=0)
Definition: BundleCore.cpp:270
void remove(const URI &u)
Definition: Node.cpp:292
bool expire()
Definition: Node.cpp:415
bool isAnnounced() const
Definition: Node.cpp:579
const Configuration::Network & getNetwork() const
void add(const dtn::core::Node &n)
void discovered(const dtn::core::Node &node)
std::set< dtn::core::Node::Protocol > protocol_set
const dtn::data::EID & getNeighbor() const
void queue(dtn::net::BundleTransfer &job)
size_t Timeout
Definition: Number.h:35
bool doConnectImmediately() const
Definition: Node.cpp:516
virtual dtn::core::Node::Protocol getProtocol() const =0
virtual void getStats(ConvergenceLayer::stats_data &data) const
std::map< string, string > stats_data
dtn::core::Node::Protocol getProtocol() const
const protocol_set getSupportedProtocols()
virtual const std::string getName() const
static dtn::data::Timestamp getTime()
Definition: Clock.cpp:167
void add(const URI &u)
Definition: Node.cpp:280
virtual void queue(const dtn::core::Node &n, const dtn::net::BundleTransfer &job)=0
std::list< URI > get(Node::Protocol proto) const
Definition: Node.cpp:325
void abort(const TransferAbortedEvent::AbortReason reason)
size_t Size
Definition: Number.h:34
virtual dtn::core::Node::Protocol getDiscoveryProtocol() const =0
static void raise(const Node &n, const EventNodeAction action)
Definition: NodeEvent.cpp:47
virtual void connect(const dtn::core::Node::URI &uri)=0
const dtn::data::EID & getEID() const
Definition: Node.cpp:406
void raiseEvent(const dtn::core::TimeEvent &evt)
void updateNeighbor(const dtn::core::Node &n)
std::list< Node::URI > getAll() const
Definition: Node.cpp:372
const dtn::core::Node getNeighbor(const dtn::data::EID &eid)
void open(const dtn::core::Node &node)
dtn::data::Timeout getAutoConnect() const
static BundleCore & getInstance()
Definition: BundleCore.cpp:82