IBR-DTNSuite  0.8
daemon/src/net/ConnectionManager.cpp
Go to the documentation of this file.
00001 /*
00002  * ConnectionManager.cpp
00003  *
00004  *  Created on: 24.09.2009
00005  *      Author: morgenro
00006  */
00007 
00008 #include "Configuration.h"
00009 #include "net/ConnectionManager.h"
00010 #include "net/UDPConvergenceLayer.h"
00011 #include "net/TCPConvergenceLayer.h"
00012 #include "net/BundleReceivedEvent.h"
00013 #include "net/ConnectionEvent.h"
00014 #include "core/NodeEvent.h"
00015 #include "core/BundleEvent.h"
00016 #include "core/BundleCore.h"
00017 #include "core/NodeEvent.h"
00018 #include "core/TimeEvent.h"
00019 #include "routing/RequeueBundleEvent.h"
00020 
00021 #include <ibrdtn/utils/Clock.h>
00022 #include <ibrcommon/net/tcpserver.h>
00023 #include <ibrcommon/Logger.h>
00024 
00025 #include <iostream>
00026 #include <iomanip>
00027 #include <algorithm>
00028 #include <functional>
00029 #include <typeinfo>
00030 
00031 using namespace dtn::core;
00032 
00033 namespace dtn
00034 {
00035         namespace net
00036         {
00037                 struct CompareNodeDestination:
00038                 public std::binary_function< dtn::core::Node, dtn::data::EID, bool > {
00039                         bool operator() ( const dtn::core::Node &node, const dtn::data::EID &destination ) const {
00040                                 return node.getEID() == destination;
00041                         }
00042                 };
00043 
00044                 ConnectionManager::ConnectionManager()
00045                  : _shutdown(false), _next_autoconnect(0)
00046                 {
00047                 }
00048 
00049                 ConnectionManager::~ConnectionManager()
00050                 {
00051                 }
00052 
00053                 void ConnectionManager::componentUp()
00054                 {
00055                         bindEvent(TimeEvent::className);
00056                         bindEvent(NodeEvent::className);
00057                         bindEvent(ConnectionEvent::className);
00058 
00059                         // set next auto connect
00060                         const dtn::daemon::Configuration::Network &nc = dtn::daemon::Configuration::getInstance().getNetwork();
00061                         if (nc.getAutoConnect() != 0)
00062                         {
00063                                 _next_autoconnect = dtn::utils::Clock::getTime() + nc.getAutoConnect();
00064                         }
00065                 }
00066 
00067                 void ConnectionManager::componentDown()
00068                 {
00069                         {
00070                                 ibrcommon::MutexLock l(_cl_lock);
00071                                 // clear the list of convergence layers
00072                                 _cl.clear();
00073                         }
00074 
00075                         unbindEvent(NodeEvent::className);
00076                         unbindEvent(TimeEvent::className);
00077                         unbindEvent(ConnectionEvent::className);
00078                 }
00079 
00080                 void ConnectionManager::raiseEvent(const dtn::core::Event *evt)
00081                 {
00082                         try {
00083                                 const NodeEvent &nodeevent = dynamic_cast<const NodeEvent&>(*evt);
00084                                 const Node &n = nodeevent.getNode();
00085 
00086                                 switch (nodeevent.getAction())
00087                                 {
00088                                         case NODE_INFO_UPDATED:
00089                                                 discovered(n);
00090                                                 break;
00091 
00092                                         case NODE_AVAILABLE:
00093                                                 if (n.doConnectImmediately())
00094                                                 {
00095                                                         // open the connection immediately
00096                                                         open(n);
00097                                                 }
00098                                                 break;
00099 
00100                                         default:
00101                                                 break;
00102                                 }
00103                         } catch (const std::bad_cast&) { }
00104 
00105                         try {
00106                                 const TimeEvent &timeevent = dynamic_cast<const TimeEvent&>(*evt);
00107 
00108                                 if (timeevent.getAction() == TIME_SECOND_TICK)
00109                                 {
00110                                         check_unavailable();
00111                                         check_autoconnect();
00112                                 }
00113                         } catch (const std::bad_cast&) { }
00114 
00115                         try {
00116                                 const ConnectionEvent &connection = dynamic_cast<const ConnectionEvent&>(*evt);
00117 
00118                                 switch (connection.state)
00119                                 {
00120                                         case ConnectionEvent::CONNECTION_UP:
00121                                         {
00122                                                 ibrcommon::MutexLock l(_node_lock);
00123 
00124                                                 try {
00125                                                         dtn::core::Node &n = getNode(connection.peer);
00126                                                         n += connection.node;
00127 
00128                                                         IBRCOMMON_LOGGER_DEBUG(56) << "Node attributes added: " << n << IBRCOMMON_LOGGER_ENDL;
00129                                                 } catch (const ibrcommon::Exception&) {
00130                                                         _nodes.push_back(connection.node);
00131 
00132                                                         IBRCOMMON_LOGGER_DEBUG(56) << "New node available: " << connection.node << IBRCOMMON_LOGGER_ENDL;
00133 
00134                                                         // announce the new node
00135                                                         dtn::core::NodeEvent::raise(connection.node, dtn::core::NODE_AVAILABLE);
00136 
00137                                                 }
00138 
00139                                                 break;
00140                                         }
00141 
00142                                         case ConnectionEvent::CONNECTION_DOWN:
00143                                         {
00144                                                 ibrcommon::MutexLock l(_node_lock);
00145 
00146                                                 try {
00147                                                         // remove the node from the connected list
00148                                                         dtn::core::Node &n = getNode(connection.peer);
00149                                                         n -= connection.node;
00150 
00151                                                         IBRCOMMON_LOGGER_DEBUG(56) << "Node attributes removed: " << n << IBRCOMMON_LOGGER_ENDL;
00152                                                 } catch (const ibrcommon::Exception&) { };
00153                                                 break;
00154                                         }
00155 
00156                                         default:
00157                                                 break;
00158                                 }
00159 
00160                         } catch (const std::bad_cast&) {
00161 
00162                         }
00163                 }
00164 
00165                 void ConnectionManager::addConnection(const dtn::core::Node &n)
00166                 {
00167                         ibrcommon::MutexLock l(_node_lock);
00168                         try {
00169                                 dtn::core::Node &db = getNode(n.getEID());
00170 
00171                                 // add all attributes to the node in the database
00172                                 db += n;
00173 
00174                                 IBRCOMMON_LOGGER_DEBUG(56) << "Node attributes added: " << db << IBRCOMMON_LOGGER_ENDL;
00175 
00176                         } catch (const ibrcommon::Exception&) {
00177                                 _nodes.push_back(n);
00178 
00179                                 // announce the new node
00180                                 dtn::core::NodeEvent::raise(n, dtn::core::NODE_AVAILABLE);
00181                                 IBRCOMMON_LOGGER_DEBUG(56) << "New node available: " << n << IBRCOMMON_LOGGER_ENDL;
00182                         }
00183                 }
00184 
00185                 void ConnectionManager::removeConnection(const dtn::core::Node &n)
00186                 {
00187                         ibrcommon::MutexLock l(_node_lock);
00188                         try {
00189                                 dtn::core::Node &db = getNode(n.getEID());
00190 
00191                                 // erase all attributes to the node in the database
00192                                 db -= n;
00193 
00194                                 IBRCOMMON_LOGGER_DEBUG(56) << "Node attributes removed: " << db << IBRCOMMON_LOGGER_ENDL;
00195                         } catch (const ibrcommon::Exception&) { };
00196                 }
00197 
00198                 void ConnectionManager::addConvergenceLayer(ConvergenceLayer *cl)
00199                 {
00200                         ibrcommon::MutexLock l(_cl_lock);
00201                         _cl.insert( cl );
00202                 }
00203 
00204                 void ConnectionManager::discovered(const dtn::core::Node &node)
00205                 {
00206                         // ignore messages of ourself
00207                         if (node.getEID() == dtn::core::BundleCore::local) return;
00208 
00209                         ibrcommon::MutexLock l(_node_lock);
00210 
00211                         try {
00212                                 dtn::core::Node &db = getNode(node.getEID());
00213 
00214                                 // add all attributes to the node in the database
00215                                 db += node;
00216 
00217                                 IBRCOMMON_LOGGER_DEBUG(56) << "Node attributes added: " << db << IBRCOMMON_LOGGER_ENDL;
00218                         } catch (const ibrcommon::Exception&) {
00219                                 _nodes.push_back(node);
00220 
00221                                 // announce the new node
00222                                 dtn::core::NodeEvent::raise(node, dtn::core::NODE_AVAILABLE);
00223                                 IBRCOMMON_LOGGER_DEBUG(56) << "New node available: " << node << IBRCOMMON_LOGGER_ENDL;
00224                         }
00225                 }
00226 
00227                 void ConnectionManager::check_unavailable()
00228                 {
00229                         ibrcommon::MutexLock l(_node_lock);
00230 
00231                         // search for outdated nodes
00232                         std::list<dtn::core::Node>::iterator iter = _nodes.begin();
00233                         while ( iter != _nodes.end() )
00234                         {
00235                                 dtn::core::Node &n = (*iter);
00236 
00237                                 if ( n.expire() )
00238                                 {
00239                                         // announce the unavailable event
00240                                         dtn::core::NodeEvent::raise(n, dtn::core::NODE_UNAVAILABLE);
00241 
00242                                         // remove the element
00243                                         _nodes.erase( iter++ );
00244                                 }
00245                                 else
00246                                 {
00247                                         iter++;
00248                                 }
00249                         }
00250                 }
00251 
00252                 void ConnectionManager::check_autoconnect()
00253                 {
00254                         std::queue<dtn::core::Node> _connect_nodes;
00255 
00256                         size_t interval = dtn::daemon::Configuration::getInstance().getNetwork().getAutoConnect();
00257                         if (interval == 0) return;
00258 
00259                         if (_next_autoconnect < dtn::utils::Clock::getTime())
00260                         {
00261                                 // search for non-connected but available nodes
00262                                 ibrcommon::MutexLock l(_cl_lock);
00263                                 for (std::list<dtn::core::Node>::const_iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
00264                                 {
00265                                         const Node &n = (*iter);
00266                                         std::list<Node::URI> ul = n.get(Node::NODE_CONNECTED, Node::CONN_TCPIP);
00267 
00268                                         if (ul.empty() && n.isAvailable())
00269                                         {
00270                                                 _connect_nodes.push(n);
00271                                         }
00272                                 }
00273 
00274                                 // set the next check time
00275                                 _next_autoconnect = dtn::utils::Clock::getTime() + interval;
00276                         }
00277 
00278                         while (!_connect_nodes.empty())
00279                         {
00280                                 open(_connect_nodes.front());
00281                                 _connect_nodes.pop();
00282                         }
00283                 }
00284 
00285                 void ConnectionManager::open(const dtn::core::Node &node)
00286                 {
00287                         ibrcommon::MutexLock l(_cl_lock);
00288 
00289                         // search for the right cl
00290                         for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); iter++)
00291                         {
00292                                 ConvergenceLayer *cl = (*iter);
00293                                 if (node.has(cl->getDiscoveryProtocol()))
00294                                 {
00295                                         cl->open(node);
00296 
00297                                         // stop here, we queued the bundle already
00298                                         return;
00299                                 }
00300                         }
00301 
00302                         throw ConnectionNotAvailableException();
00303                 }
00304 
00305                 void ConnectionManager::queue(const dtn::core::Node &node, const ConvergenceLayer::Job &job)
00306                 {
00307                         ibrcommon::MutexLock l(_cl_lock);
00308 
00309                         // search for the right cl
00310                         for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); iter++)
00311                         {
00312                                 ConvergenceLayer *cl = (*iter);
00313                                 if (node.has(cl->getDiscoveryProtocol()))
00314                                 {
00315                                         cl->queue(node, job);
00316 
00317                                         // stop here, we queued the bundle already
00318                                         return;
00319                                 }
00320                         }
00321 
00322                         throw ConnectionNotAvailableException();
00323                 }
00324 
00325                 void ConnectionManager::queue(const ConvergenceLayer::Job &job)
00326                 {
00327                         ibrcommon::MutexLock l(_node_lock);
00328 
00329                         if (IBRCOMMON_LOGGER_LEVEL >= 50)
00330                         {
00331                                 IBRCOMMON_LOGGER_DEBUG(50) << "## node list ##" << IBRCOMMON_LOGGER_ENDL;
00332                                 for (std::list<dtn::core::Node>::const_iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
00333                                 {
00334                                         const dtn::core::Node &n = (*iter);
00335                                         IBRCOMMON_LOGGER_DEBUG(2) << n << IBRCOMMON_LOGGER_ENDL;
00336                                 }
00337                         }
00338 
00339                         IBRCOMMON_LOGGER_DEBUG(50) << "search for node " << job._destination.getString() << IBRCOMMON_LOGGER_ENDL;
00340 
00341                         // queue to a node
00342                         for (std::list<dtn::core::Node>::const_iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
00343                         {
00344                                 const Node &n = (*iter);
00345                                 if (n == job._destination)
00346                                 {
00347                                         IBRCOMMON_LOGGER_DEBUG(2) << "next hop: " << n << IBRCOMMON_LOGGER_ENDL;
00348                                         queue(n, job);
00349                                         return;
00350                                 }
00351                         }
00352 
00353                         throw NeighborNotAvailableException("No active connection to this neighbor available!");
00354                 }
00355 
00356                 void ConnectionManager::queue(const dtn::data::EID &eid, const dtn::data::BundleID &b)
00357                 {
00358                         queue( ConvergenceLayer::Job(eid, b) );
00359                 }
00360 
00361                 const std::set<dtn::core::Node> ConnectionManager::getNeighbors()
00362                 {
00363                         ibrcommon::MutexLock l(_node_lock);
00364 
00365                         std::set<dtn::core::Node> ret;
00366 
00367                         for (std::list<dtn::core::Node>::const_iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
00368                         {
00369                                 const Node &n = (*iter);
00370                                 if (n.isAvailable()) ret.insert( *iter );
00371                         }
00372 
00373                         return ret;
00374                 }
00375 
00376                 const dtn::core::Node ConnectionManager::getNeighbor(const dtn::data::EID &eid)
00377                 {
00378                         ibrcommon::MutexLock l(_node_lock);
00379 
00380                         // search for the node in the node list
00381                         for (std::list<dtn::core::Node>::const_iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
00382                         {
00383                                 const Node &n = (*iter);
00384                                 if ((n.getEID() == eid) && (n.isAvailable())) return n;
00385                         }
00386 
00387                         throw dtn::net::NeighborNotAvailableException();
00388                 }
00389 
00390                 bool ConnectionManager::isNeighbor(const dtn::core::Node &node)
00391                 {
00392                         ibrcommon::MutexLock l(_node_lock);
00393 
00394                         // search for the node in the node list
00395                         for (std::list<dtn::core::Node>::const_iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
00396                         {
00397                                 const Node &n = (*iter);
00398                                 if ((n == node) && (n.isAvailable())) return true;
00399                         }
00400 
00401                         return false;
00402                 }
00403 
00404                 const std::string ConnectionManager::getName() const
00405                 {
00406                         return "ConnectionManager";
00407                 }
00408 
00409                 dtn::core::Node& ConnectionManager::getNode(const dtn::data::EID &eid)
00410                 {
00411                         for (std::list<dtn::core::Node>::iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
00412                         {
00413                                 dtn::core::Node &n = (*iter);
00414                                 if (n == eid) return n;
00415                         }
00416 
00417                         throw ibrcommon::Exception("neighbor not found");
00418                 }
00419         }
00420 }