IBR-DTNSuite 0.6

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                         if (_next_autoconnect < dtn::utils::Clock::getTime())
00257                         {
00258                                 // search for non-connected but available nodes
00259                                 ibrcommon::MutexLock l(_cl_lock);
00260                                 for (std::list<dtn::core::Node>::const_iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
00261                                 {
00262                                         const Node &n = (*iter);
00263                                         std::list<Node::URI> ul = n.get(Node::NODE_CONNECTED, Node::CONN_TCPIP);
00264 
00265                                         if (ul.empty() && n.isAvailable())
00266                                         {
00267                                                 _connect_nodes.push(n);
00268                                         }
00269                                 }
00270 
00271                                 // set the next check time
00272                                 _next_autoconnect = dtn::utils::Clock::getTime() + dtn::daemon::Configuration::getInstance().getNetwork().getAutoConnect();
00273                         }
00274 
00275                         while (!_connect_nodes.empty())
00276                         {
00277                                 open(_connect_nodes.front());
00278                                 _connect_nodes.pop();
00279                         }
00280                 }
00281 
00282                 void ConnectionManager::open(const dtn::core::Node &node)
00283                 {
00284                         ibrcommon::MutexLock l(_cl_lock);
00285 
00286                         // search for the right cl
00287                         for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); iter++)
00288                         {
00289                                 ConvergenceLayer *cl = (*iter);
00290                                 if (node.has(cl->getDiscoveryProtocol()))
00291                                 {
00292                                         cl->open(node);
00293 
00294                                         // stop here, we queued the bundle already
00295                                         return;
00296                                 }
00297                         }
00298 
00299                         throw ConnectionNotAvailableException();
00300                 }
00301 
00302                 void ConnectionManager::queue(const dtn::core::Node &node, const ConvergenceLayer::Job &job)
00303                 {
00304                         ibrcommon::MutexLock l(_cl_lock);
00305 
00306                         // search for the right cl
00307                         for (std::set<ConvergenceLayer*>::iterator iter = _cl.begin(); iter != _cl.end(); iter++)
00308                         {
00309                                 ConvergenceLayer *cl = (*iter);
00310                                 if (node.has(cl->getDiscoveryProtocol()))
00311                                 {
00312                                         cl->queue(node, job);
00313 
00314                                         // stop here, we queued the bundle already
00315                                         return;
00316                                 }
00317                         }
00318 
00319                         throw ConnectionNotAvailableException();
00320                 }
00321 
00322                 void ConnectionManager::queue(const ConvergenceLayer::Job &job)
00323                 {
00324                         ibrcommon::MutexLock l(_node_lock);
00325 
00326                         if (IBRCOMMON_LOGGER_LEVEL >= 50)
00327                         {
00328                                 IBRCOMMON_LOGGER_DEBUG(50) << "## node list ##" << IBRCOMMON_LOGGER_ENDL;
00329                                 for (std::list<dtn::core::Node>::const_iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
00330                                 {
00331                                         const dtn::core::Node &n = (*iter);
00332                                         IBRCOMMON_LOGGER_DEBUG(2) << n << IBRCOMMON_LOGGER_ENDL;
00333                                 }
00334                         }
00335 
00336                         IBRCOMMON_LOGGER_DEBUG(50) << "search for node " << job._destination.getString() << IBRCOMMON_LOGGER_ENDL;
00337 
00338                         // queue to a node
00339                         for (std::list<dtn::core::Node>::const_iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
00340                         {
00341                                 const Node &n = (*iter);
00342                                 if (n == job._destination)
00343                                 {
00344                                         IBRCOMMON_LOGGER_DEBUG(2) << "next hop: " << n << IBRCOMMON_LOGGER_ENDL;
00345                                         queue(n, job);
00346                                         return;
00347                                 }
00348                         }
00349 
00350                         throw NeighborNotAvailableException("No active connection to this neighbor available!");
00351                 }
00352 
00353                 void ConnectionManager::queue(const dtn::data::EID &eid, const dtn::data::BundleID &b)
00354                 {
00355                         queue( ConvergenceLayer::Job(eid, b) );
00356                 }
00357 
00358                 const std::set<dtn::core::Node> ConnectionManager::getNeighbors()
00359                 {
00360                         ibrcommon::MutexLock l(_node_lock);
00361 
00362                         std::set<dtn::core::Node> ret;
00363 
00364                         for (std::list<dtn::core::Node>::const_iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
00365                         {
00366                                 const Node &n = (*iter);
00367                                 if (n.isAvailable()) ret.insert( *iter );
00368                         }
00369 
00370                         return ret;
00371                 }
00372 
00373 
00374                 bool ConnectionManager::isNeighbor(const dtn::core::Node &node) const
00375                 {
00376                         // search for the node in the node list
00377                         for (std::list<dtn::core::Node>::const_iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
00378                         {
00379                                 const Node &n = (*iter);
00380                                 if ((n == node) && (n.isAvailable())) return true;
00381                         }
00382 
00383                         return false;
00384                 }
00385 
00386                 const std::string ConnectionManager::getName() const
00387                 {
00388                         return "ConnectionManager";
00389                 }
00390 
00391                 dtn::core::Node& ConnectionManager::getNode(const dtn::data::EID &eid)
00392                 {
00393                         for (std::list<dtn::core::Node>::iterator iter = _nodes.begin(); iter != _nodes.end(); iter++)
00394                         {
00395                                 dtn::core::Node &n = (*iter);
00396                                 if (n == eid) return n;
00397                         }
00398 
00399                         throw ibrcommon::Exception("neighbor not found");
00400                 }
00401         }
00402 }