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