IBR-DTNSuite  0.8
daemon/src/net/IPNDAgent.cpp
Go to the documentation of this file.
00001 /*
00002  * IPNDAgent.cpp
00003  *
00004  *  Created on: 14.09.2009
00005  *      Author: morgenro
00006  */
00007 
00008 #include "net/IPNDAgent.h"
00009 #include "core/BundleCore.h"
00010 #include <ibrdtn/data/Exceptions.h>
00011 #include <sstream>
00012 #include <string.h>
00013 #include <ibrcommon/Logger.h>
00014 #include <ibrcommon/net/MulticastSocket.h>
00015 #include <ibrcommon/TimeMeasurement.h>
00016 #include "Configuration.h"
00017 #include <typeinfo>
00018 #include <time.h>
00019 
00020 namespace dtn
00021 {
00022         namespace net
00023         {
00024                 IPNDAgent::IPNDAgent(int port, const ibrcommon::vaddress &address)
00025                  : DiscoveryAgent(dtn::daemon::Configuration::getInstance().getDiscovery()),
00026                    _version(DiscoveryAnnouncement::DISCO_VERSION_01), _destination(address), _port(port)
00027                 {
00028                         // broadcast addresses should be usable more than once.
00029                         _socket.set(ibrcommon::vsocket::VSOCKET_REUSEADDR);
00030 
00031                         if (_destination.isMulticast())
00032                         {
00033                                 IBRCOMMON_LOGGER(info) << "DiscoveryAgent: multicast mode " << address.toString() << ":" << port << IBRCOMMON_LOGGER_ENDL;
00034                                 _socket.set(ibrcommon::vsocket::VSOCKET_MULTICAST);
00035                         }
00036                         else
00037                         {
00038                                 IBRCOMMON_LOGGER(info) << "DiscoveryAgent: broadcast mode " << address.toString() << ":" << port << IBRCOMMON_LOGGER_ENDL;
00039                                 _socket.set(ibrcommon::vsocket::VSOCKET_BROADCAST);
00040                         }
00041 
00042                         switch (_config.version())
00043                         {
00044                         case 2:
00045                                 _version = DiscoveryAnnouncement::DISCO_VERSION_01;
00046                                 break;
00047 
00048                         case 1:
00049                                 _version = DiscoveryAnnouncement::DISCO_VERSION_00;
00050                                 break;
00051 
00052                         case 0:
00053                                 IBRCOMMON_LOGGER(info) << "DiscoveryAgent: DTN2 compatibility mode" << IBRCOMMON_LOGGER_ENDL;
00054                                 _version = DiscoveryAnnouncement::DTND_IPDISCOVERY;
00055                                 break;
00056                         };
00057                 }
00058 
00059                 IPNDAgent::~IPNDAgent()
00060                 {
00061                 }
00062 
00063                 void IPNDAgent::bind(const ibrcommon::vinterface &net)
00064                 {
00065                         IBRCOMMON_LOGGER(info) << "DiscoveryAgent: bind to interface " << net.toString() << IBRCOMMON_LOGGER_ENDL;
00066                         _interfaces.push_back(net);
00067                 }
00068 
00069                 void IPNDAgent::send(const DiscoveryAnnouncement &a, const ibrcommon::vinterface &iface, const ibrcommon::vaddress &addr, const unsigned int port)
00070                 {
00071                         // serialize announcement
00072                         stringstream ss; ss << a;
00073                         const std::string data = ss.str();
00074 
00075                         std::list<int> fds = _socket.get(iface);
00076                         for (std::list<int>::const_iterator iter = fds.begin(); iter != fds.end(); iter++)
00077                         {
00078                                 try {
00079                                         size_t ret = 0;
00080                                         int flags = 0;
00081 
00082                                         struct addrinfo hints, *ainfo;
00083                                         memset(&hints, 0, sizeof hints);
00084 
00085                                         hints.ai_socktype = SOCK_DGRAM;
00086                                         ainfo = addr.addrinfo(&hints, port);
00087 
00088                                         ret = sendto(*iter, data.c_str(), data.length(), flags, ainfo->ai_addr, ainfo->ai_addrlen);
00089 
00090                                         freeaddrinfo(ainfo);
00091                                 } catch (const ibrcommon::vsocket_exception&) {
00092                                         IBRCOMMON_LOGGER_DEBUG(5) << "can not send message to " << addr.toString() << IBRCOMMON_LOGGER_ENDL;
00093                                 }
00094                         }
00095                 }
00096 
00097                 void IPNDAgent::sendAnnoucement(const u_int16_t &sn, std::list<DiscoveryService> &services)
00098                 {
00099                         DiscoveryAnnouncement announcement(_version, dtn::core::BundleCore::local);
00100 
00101                         // set sequencenumber
00102                         announcement.setSequencenumber(sn);
00103 
00104                         for (std::list<ibrcommon::vinterface>::const_iterator it_iface = _interfaces.begin(); it_iface != _interfaces.end(); it_iface++)
00105                         {
00106                                 const ibrcommon::vinterface &iface = (*it_iface);
00107 
00108                                 // clear all services
00109                                 announcement.clearServices();
00110 
00111                                 if (!_config.shortbeacon())
00112                                 {
00113                                         // add services
00114                                         for (std::list<DiscoveryService>::iterator iter = services.begin(); iter != services.end(); iter++)
00115                                         {
00116                                                 DiscoveryService &service = (*iter);
00117 
00118                                                 try {
00119                                                         // update service information
00120                                                         service.update(iface);
00121 
00122                                                         // add service to discovery message
00123                                                         announcement.addService(service);
00124                                                 } catch (const dtn::net::DiscoveryServiceProvider::NoServiceHereException&) {
00125 
00126                                                 }
00127                                         }
00128                                 }
00129 
00130                                 send(announcement, iface, _destination, _port);
00131                         }
00132                 }
00133 
00134                 void IPNDAgent::eventNotify(const ibrcommon::LinkManagerEvent &evt)
00135                 {
00136                         if (evt.getType() == ibrcommon::LinkManagerEvent::EVENT_ADDRESS_ADDED)
00137                         {
00138                                 if (_destination.isMulticast())
00139                                 {
00140                                         ibrcommon::MulticastSocket ms(_fd);
00141                                         ms.joinGroup(_destination, evt.getInterface());
00142                                 }
00143                         }
00144                 }
00145 
00146                 void IPNDAgent::componentUp()
00147                 {
00148                         // create one socket for each interface
00149                         for (std::list<ibrcommon::vinterface>::const_iterator iter = _interfaces.begin(); iter != _interfaces.end(); iter++)
00150                         {
00151                                 try {
00152                                         const ibrcommon::vinterface &iface = *iter;
00153                                         if (!iface.empty())
00154                                         {
00155                                                 _socket.bind(iface, 0, SOCK_DGRAM);
00156                                         }
00157                                 } catch (const ibrcommon::Exception &ex) {
00158                                         IBRCOMMON_LOGGER(error) << "[IPND] bind failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
00159                                 }
00160                         }
00161 
00162                         try {
00163                                 // bind on ALL interfaces
00164                                 _fd = _socket.bind(_port, SOCK_DGRAM);
00165 
00166                                 // only if the destination is a multicast address
00167                                 if (_destination.isMulticast())
00168                                 {
00169                                         // enable multicasting on the socket
00170                                         ibrcommon::MulticastSocket ms(_fd);
00171 
00172                                         for (std::list<ibrcommon::vinterface>::const_iterator iter = _interfaces.begin(); iter != _interfaces.end(); iter++)
00173                                         {
00174                                                 ms.joinGroup(_destination, *iter);
00175                                         }
00176                                 }
00177                         } catch (const ibrcommon::Exception &ex) {
00178                                 IBRCOMMON_LOGGER(error) << "[IPND] bind on broadcast address failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
00179                         }
00180 
00181                         // set this socket as listener to socket events
00182                         _socket.setEventCallback(this);
00183                 }
00184 
00185                 void IPNDAgent::componentDown()
00186                 {
00187                         // unset this socket as listener to socket events
00188                         _socket.setEventCallback(NULL);
00189 
00190                         // shutdown the sockets
00191                         _socket.shutdown();
00192 
00193                         stop();
00194                         join();
00195                 }
00196 
00197                 void IPNDAgent::componentRun()
00198                 {
00199                         ibrcommon::TimeMeasurement tm;
00200                         tm.start();
00201 
00202                         while (true)
00203                         {
00204                                 std::list<int> fds;
00205 
00206                                 struct timeval tv;
00207 
00208                                 // every second we want to transmit a discovery message, timeout of 1 seconds
00209                                 tv.tv_sec = 0;
00210                                 tv.tv_usec = 100000;
00211 
00212                                 try {
00213                                         // select on all bound sockets
00214                                         _socket.select(fds, &tv);
00215 
00216                                         // receive from all sockets
00217                                         for (std::list<int>::const_iterator iter = fds.begin(); iter != fds.end(); iter++)
00218                                         {
00219                                                 char data[1500];
00220                                                 std::string sender;
00221                                                 DiscoveryAnnouncement announce(_version);
00222 
00223                                                 int len = ibrcommon::recvfrom(*iter, data, 1500, sender);
00224 
00225                                                 if (announce.isShort())
00226                                                 {
00227                                                         // TODO: generate name with the sender address
00228                                                 }
00229 
00230                                                 if (announce.getServices().empty())
00231                                                 {
00232                                                         announce.addService(dtn::net::DiscoveryService("tcpcl", "ip=" + sender + ";port=4556;"));
00233                                                 }
00234 
00235                                                 if (len < 0) return;
00236 
00237                                                 stringstream ss;
00238                                                 ss.write(data, len);
00239 
00240                                                 try {
00241                                                         ss >> announce;
00242                                                         received(announce);
00243                                                 } catch (const dtn::InvalidDataException&) {
00244                                                 } catch (const ibrcommon::IOException&) {
00245                                                 }
00246 
00247                                                 yield();
00248                                         }
00249                                 } catch (const ibrcommon::vsocket_timeout&) { };
00250 
00251                                 // trigger timeout, if one second is elapsed
00252                                 tm.stop(); if (tm.getMilliseconds() > 1000)
00253                                 {
00254                                         tm.start();
00255                                         timeout();
00256                                 }
00257                         }
00258                 }
00259 
00260                 void IPNDAgent::__cancellation()
00261                 {
00262                         // interrupt the receiving thread
00263                         _socket.close();
00264                 }
00265 
00266                 const std::string IPNDAgent::getName() const
00267                 {
00268                         return "IPNDAgent";
00269                 }
00270         }
00271 }