IBR-DTNSuite 0.6

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                                         __join_multicast_groups__(evt.getInterface());
00141                                 }
00142                         }
00143                 }
00144 
00145                 void IPNDAgent::__join_multicast_groups__(const ibrcommon::vinterface &iface)
00146                 {
00147                         // get all FD of IPv4 sockets matching this interface
00148                         std::list<int> fds = _socket.get(iface, ibrcommon::vaddress::VADDRESS_INET);
00149 
00150                         // iterate through all socket FD
00151                         for (std::list<int>::const_iterator iter = fds.begin();
00152                                         iter != fds.end(); iter++)
00153                         {
00154                                 // enable multicasting on the socket
00155                                 ibrcommon::MulticastSocket ms(*iter);
00156                                 ms.joinGroup(_destination, iface);
00157                         }
00158                 }
00159 
00160                 void IPNDAgent::componentUp()
00161                 {
00162                         // create one socket for each interface
00163                         for (std::list<ibrcommon::vinterface>::const_iterator iter = _interfaces.begin(); iter != _interfaces.end(); iter++)
00164                         {
00165                                 const ibrcommon::vinterface &iface = *iter;
00166                                 if (!iface.empty())
00167                                 {
00168                                         _socket.bind(iface, 0, SOCK_DGRAM);
00169                                 }
00170                         }
00171 
00172                         // only if the destination is a multicast address
00173                         if (_destination.isMulticast())
00174                         {
00175                                 // bind on the multicast address
00176                                 _socket.bind(_destination, _port, SOCK_DGRAM);
00177 
00178                                 for (std::list<ibrcommon::vinterface>::const_iterator i_iter = _interfaces.begin(); i_iter != _interfaces.end(); i_iter++)
00179                                 {
00180                                         // enable multicast
00181                                         __join_multicast_groups__(*i_iter);
00182                                 }
00183                         }
00184                         else
00185                         {
00186                                 // bind on ALL interfaces
00187                                 _socket.bind(_destination, _port, SOCK_DGRAM);
00188                         }
00189 
00190                         // set this socket as listener to socket events
00191                         _socket.setEventCallback(this);
00192                 }
00193 
00194                 void IPNDAgent::componentDown()
00195                 {
00196                         // unset this socket as listener to socket events
00197                         _socket.setEventCallback(NULL);
00198 
00199                         // shutdown the sockets
00200                         _socket.shutdown();
00201 
00202                         stop();
00203                         join();
00204                 }
00205 
00206                 void IPNDAgent::componentRun()
00207                 {
00208                         ibrcommon::TimeMeasurement tm;
00209                         tm.start();
00210 
00211                         while (true)
00212                         {
00213                                 std::list<int> fds;
00214 
00215                                 struct timeval tv;
00216 
00217                                 // every second we want to transmit a discovery message, timeout of 1 seconds
00218                                 tv.tv_sec = 0;
00219                                 tv.tv_usec = 100000;
00220 
00221                                 try {
00222                                         // select on all bound sockets
00223                                         _socket.select(fds, &tv);
00224 
00225                                         // receive from all sockets
00226                                         for (std::list<int>::const_iterator iter = fds.begin(); iter != fds.end(); iter++)
00227                                         {
00228                                                 char data[1500];
00229                                                 std::string sender;
00230                                                 DiscoveryAnnouncement announce(_version);
00231 
00232                                                 int len = ibrcommon::recvfrom(*iter, data, 1500, sender);
00233 
00234                                                 if (announce.isShort())
00235                                                 {
00236                                                         // TODO: generate name with the sender address
00237                                                 }
00238 
00239                                                 if (announce.getServices().empty())
00240                                                 {
00241                                                         announce.addService(dtn::net::DiscoveryService("tcpcl", "ip=" + sender + ";port=4556;"));
00242                                                 }
00243 
00244                                                 if (len < 0) return;
00245 
00246                                                 stringstream ss;
00247                                                 ss.write(data, len);
00248 
00249                                                 try {
00250                                                         ss >> announce;
00251                                                         received(announce);
00252                                                 } catch (const dtn::InvalidDataException&) {
00253                                                 } catch (const ibrcommon::IOException&) {
00254                                                 }
00255 
00256                                                 yield();
00257                                         }
00258                                 } catch (const ibrcommon::vsocket_timeout&) { };
00259 
00260                                 // trigger timeout, if one second is elapsed
00261                                 tm.stop(); if (tm.getMilliseconds() > 1000)
00262                                 {
00263                                         tm.start();
00264                                         timeout();
00265                                 }
00266                         }
00267                 }
00268 
00269                 bool IPNDAgent::__cancellation()
00270                 {
00271                         // interrupt the receiving thread
00272                         _socket.close();
00273 
00274                         // do not cancel the hard-way
00275                         return true;
00276                 }
00277 
00278                 const std::string IPNDAgent::getName() const
00279                 {
00280                         return "IPNDAgent";
00281                 }
00282         }
00283 }