IBR-DTNSuite
0.8
|
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 }