IBR-DTN  1.0.0
IPNDAgent.cpp
Go to the documentation of this file.
1 /*
2  * IPNDAgent.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "Configuration.h"
23 
24 #include "net/IPNDAgent.h"
25 #include "net/DiscoveryAgent.h"
26 #include "net/P2PDialupEvent.h"
27 #include "core/BundleCore.h"
28 #include "core/EventDispatcher.h"
29 
30 #include <ibrdtn/data/Exceptions.h>
31 
32 #include <ibrcommon/Logger.h>
33 #include <ibrcommon/TimeMeasurement.h>
34 #include <ibrcommon/net/socket.h>
35 #include <ibrcommon/net/vaddress.h>
36 #include <ibrcommon/link/LinkManager.h>
37 
38 #ifdef __WIN32__
39 #define EADDRNOTAVAIL WSAEADDRNOTAVAIL
40 #define EADDRINUSE WSAEADDRINUSE
41 #endif
42 
43 #include <sstream>
44 #include <string.h>
45 #include <typeinfo>
46 #include <time.h>
47 
48 namespace dtn
49 {
50  namespace net
51  {
52  const std::string IPNDAgent::TAG = "IPNDAgent";
53 
55  :
56 #ifndef __WIN32__
57  _virtual_mcast_iface("__virtual_multicast_interface__"),
58 #endif
59  _state(false), _port(port)
60  {
61  }
62 
64  {
65  _socket.destroy();
66  }
67 
68  void IPNDAgent::add(const ibrcommon::vaddress &address) {
69  IBRCOMMON_LOGGER_TAG("DiscoveryAgent", info) << "listen to " << address.toString() << IBRCOMMON_LOGGER_ENDL;
70  _destinations.insert(address);
71  }
72 
73  void IPNDAgent::bind(const ibrcommon::vinterface &net)
74  {
75  IBRCOMMON_LOGGER_TAG("DiscoveryAgent", info) << "add interface " << net.toString() << IBRCOMMON_LOGGER_ENDL;
76 
77  // add the interface to the stored set
78  ibrcommon::MutexLock l(_interface_lock);
79 
80  // only add the interface once
81  if (_interfaces.find(net) != _interfaces.end()) return;
82 
83  // store the new interface in the list of interfaces
84  _interfaces.insert(net);
85  }
86 
87  void IPNDAgent::join(const ibrcommon::vinterface &iface, const ibrcommon::vaddress &addr) throw ()
88  {
89  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "Join on " << iface.toString() << " (" << addr.toString() << ", family: " << addr.family() << ")" << IBRCOMMON_LOGGER_ENDL;
90 
91  // only join IPv6 and IPv4 addresses
92  if ((addr.family() != AF_INET) && (addr.family() != AF_INET6)) return;
93 
94  // do not join on loopback interfaces
95  if (addr.isLocal()) return;
96 
97  // create a multicast socket and bind to given addr
98  ibrcommon::multicastsocket *msock = new ibrcommon::multicastsocket(addr);
99 
100  // if we are in UP state
101  if (_state) {
102  try {
103  // bring up
104  msock->up();
105 
106  // listen to multicast addresses
107  for (std::set<ibrcommon::vaddress>::const_iterator it_addr = _destinations.begin(); it_addr != _destinations.end(); ++it_addr)
108  {
109  try {
110  msock->join(*it_addr, iface);
111  } catch (const ibrcommon::socket_raw_error &e) {
112  if (e.error() == EADDRINUSE) {
113  // silent error
114  } else if (e.error() == 92) {
115  // silent error - protocol not available
116  } else {
117  IBRCOMMON_LOGGER_TAG(IPNDAgent::TAG, warning) << "Join to " << (*it_addr).toString() << " failed on " << iface.toString() << "; " << e.what() << IBRCOMMON_LOGGER_ENDL;
118  }
119  } catch (const ibrcommon::socket_exception &e) {
120  IBRCOMMON_LOGGER_DEBUG_TAG(IPNDAgent::TAG, 10) << "Join to " << (*it_addr).toString() << " failed on " << iface.toString() << "; " << e.what() << IBRCOMMON_LOGGER_ENDL;
121  }
122  }
123  } catch (const ibrcommon::socket_exception &ex) {
124  IBRCOMMON_LOGGER_TAG(IPNDAgent::TAG, error) << "Join failed on " << iface.toString() << " (" << addr.toString() << ", family: " << addr.family() << ")" << "; " << ex.what() << IBRCOMMON_LOGGER_ENDL;
125  delete msock;
126  return;
127  }
128  }
129 
130  // add multicast socket to _socket
131  _socket.add(msock, iface);
132  }
133 
134  void IPNDAgent::leave(const ibrcommon::vinterface &iface, const ibrcommon::vaddress &addr) throw ()
135  {
136  IBRCOMMON_LOGGER_DEBUG_TAG(TAG, 10) << "Leave " << iface.toString() << " (" << addr.toString() << ", family: " << addr.family() << ")" << IBRCOMMON_LOGGER_ENDL;
137 
138  // get all sockets bound to the given interface
139  ibrcommon::socketset ifsocks = _socket.get(iface);
140 
141  for (ibrcommon::socketset::iterator it = ifsocks.begin(); it != ifsocks.end(); ++it)
142  {
143  ibrcommon::multicastsocket *msock = dynamic_cast<ibrcommon::multicastsocket*>(*it);
144  if (msock == NULL) continue;
145 
146  if (msock->get_address() == addr) {
147  // remove the socket
148  _socket.remove(msock);
149 
150  // shutdown the socket
151  try {
152  msock->down();
153  } catch (const ibrcommon::socket_exception &ex) {
154  IBRCOMMON_LOGGER_DEBUG_TAG(IPNDAgent::TAG, 10) << "leave failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
155  }
156 
157  // delete the socket
158  delete msock;
159 
160  return;
161  }
162  }
163  }
164 
165  void IPNDAgent::leave(const ibrcommon::vinterface &iface) throw ()
166  {
167  // get all sockets bound to the given interface
168  ibrcommon::socketset ifsocks = _socket.get(iface);
169 
170  for (ibrcommon::socketset::iterator it = ifsocks.begin(); it != ifsocks.end(); ++it)
171  {
172  ibrcommon::multicastsocket *msock = dynamic_cast<ibrcommon::multicastsocket*>(*it);
173  if (msock == NULL) continue;
174 
175  // remove the socket
176  _socket.remove(msock);
177 
178  // shutdown the socket
179  try {
180  msock->down();
181  } catch (const ibrcommon::socket_exception &ex) {
182  IBRCOMMON_LOGGER_DEBUG_TAG(IPNDAgent::TAG, 10) << "leave failed: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
183  }
184 
185  // delete the socket
186  delete msock;
187  }
188  }
189 
190  void IPNDAgent::join(const ibrcommon::vinterface &iface) throw ()
191  {
192  std::list<ibrcommon::vaddress> addrs = iface.getAddresses();
193 
194  for (std::list<ibrcommon::vaddress>::const_iterator it = addrs.begin(); it != addrs.end(); ++it)
195  {
196  ibrcommon::vaddress addr = (*it);
197  addr.setService(_port);
198  join(iface, addr);
199  }
200  }
201 
202  void IPNDAgent::onAdvertiseBeacon(const ibrcommon::vinterface &iface, const DiscoveryBeacon &beacon) throw ()
203  {
204  // serialize announcement
205  stringstream ss; ss << beacon;
206  const std::string data = ss.str();
207 
208  // get all sockets for the given interface
209  ibrcommon::socketset fds = _socket.get(iface);
210 
211  // send out discovery announcements on all bound sockets
212  // (hopefully only one per interface)
213  for (ibrcommon::socketset::const_iterator iter = fds.begin(); iter != fds.end(); ++iter)
214  {
215  try {
216  ibrcommon::udpsocket &sock = dynamic_cast<ibrcommon::udpsocket&>(**iter);
217 
218  // send beacon to all addresses
219  for (std::set<ibrcommon::vaddress>::const_iterator addr_it = _destinations.begin(); addr_it != _destinations.end(); ++addr_it)
220  {
221  const ibrcommon::vaddress &addr = (*addr_it);
222 
223  try {
224  // prevent broadcasting in the wrong address family
225  if (addr.family() != sock.get_family()) continue;
226 
227  sock.sendto(data.c_str(), data.length(), 0, addr);
228  } catch (const ibrcommon::socket_exception &e) {
229  IBRCOMMON_LOGGER_DEBUG_TAG(IPNDAgent::TAG, 5) << "can not send message to " << addr.toString() << " via " << sock.get_address().toString() << "/" << iface.toString() << "; socket exception: " << e.what() << IBRCOMMON_LOGGER_ENDL;
230  } catch (const ibrcommon::vaddress::address_exception &ex) {
231  IBRCOMMON_LOGGER_TAG(IPNDAgent::TAG, warning) << ex.what() << IBRCOMMON_LOGGER_ENDL;
232  }
233  }
234  } catch (const std::bad_cast&) {
235  IBRCOMMON_LOGGER_TAG(IPNDAgent::TAG, error) << "Socket for sending isn't a udpsocket." << IBRCOMMON_LOGGER_ENDL;
236  }
237  }
238  }
239 
240  void IPNDAgent::raiseEvent(const dtn::net::P2PDialupEvent &dialup) throw ()
241  {
242  switch (dialup.type)
243  {
245  {
246  // add the interface to the stored set
247  {
248  ibrcommon::MutexLock l(_interface_lock);
249 
250  // only add the interface once
251  if (_interfaces.find(dialup.iface) != _interfaces.end()) break;
252 
253  // store the new interface in the list of interfaces
254  _interfaces.insert(dialup.iface);
255  }
256 
257  // subscribe to NetLink events on our interfaces
258  ibrcommon::LinkManager::getInstance().addEventListener(dialup.iface, this);
259 
260  // register as discovery handler for this interface
262 
263  // join to all multicast addresses on this interface
264  join(dialup.iface);
265  break;
266  }
267 
269  {
270  // check if the interface is bound by us
271  {
272  ibrcommon::MutexLock l(_interface_lock);
273 
274  // only remove the interface if it exists
275  if (_interfaces.find(dialup.iface) == _interfaces.end()) break;
276 
277  // remove the interface from the stored set
278  _interfaces.erase(dialup.iface);
279  }
280 
281  // subscribe to NetLink events on our interfaces
282  ibrcommon::LinkManager::getInstance().removeEventListener(dialup.iface, this);
283 
284  // un-register as discovery handler for this interface
286 
287  // leave the multicast groups on the interface
288  leave(dialup.iface);
289  break;
290  }
291  }
292  }
293 
294  void IPNDAgent::eventNotify(const ibrcommon::LinkEvent &evt)
295  {
296  // check first if we are really bound to the interface
297  {
298  ibrcommon::MutexLock l(_interface_lock);
299  if (_interfaces.find(evt.getInterface()) == _interfaces.end()) return;
300  }
301 
302  switch (evt.getAction())
303  {
304  case ibrcommon::LinkEvent::ACTION_ADDRESS_ADDED:
305  {
306  ibrcommon::vaddress addr = evt.getAddress();
307  addr.setService(_port);
308  join(evt.getInterface(), addr);
309  break;
310  }
311 
312  case ibrcommon::LinkEvent::ACTION_ADDRESS_REMOVED:
313  {
314  ibrcommon::vaddress addr = evt.getAddress();
315  addr.setService(_port);
316  leave(evt.getInterface(), addr);
317  break;
318  }
319 
320  case ibrcommon::LinkEvent::ACTION_LINK_DOWN:
321  {
322  // leave the multicast groups on the interface
323  leave(evt.getInterface());
324  break;
325  }
326 
327  default:
328  break;
329  }
330  }
331 
332  void IPNDAgent::componentUp() throw ()
333  {
334  // routine checked for throw() on 15.02.2013
335 
336  try {
337  // setup the sockets
338  _socket.up();
339 
340  // set state to UP
341  _state = true;
342  } catch (const ibrcommon::socket_exception &ex) {
343  IBRCOMMON_LOGGER_TAG(IPNDAgent::TAG, error) << ex.what() << IBRCOMMON_LOGGER_ENDL;
344  }
345 
346 #ifndef __WIN32__
347  std::set<sa_family_t> bound_set;
348 
349  // create a socket for each multicast address and bind explicit
350  // to the multicast addresses
351  for (std::set<ibrcommon::vaddress>::const_iterator it_addr = _destinations.begin(); it_addr != _destinations.end(); ++it_addr)
352  {
353  const ibrcommon::vaddress &addr = (*it_addr);
354 
355  try {
356  sa_family_t fam = addr.family();
357 
358  if (bound_set.find(fam) == bound_set.end()) {
359  const ibrcommon::vaddress any_addr(_port, fam);
360 
361  // create a multicast socket and bind to given addr
362  ibrcommon::multicastsocket *msock = new ibrcommon::multicastsocket(any_addr);
363 
364  try {
365  // bring up
366  msock->up();
367 
368  // add mcast socket to vsocket
369  _socket.add(msock, _virtual_mcast_iface);
370  } catch (const ibrcommon::socket_exception &ex) {
371  IBRCOMMON_LOGGER_TAG(IPNDAgent::TAG, error) << "failed to set-up multicast socket on " << any_addr.toString() << ": " << ex.what() << IBRCOMMON_LOGGER_ENDL;
372  delete msock;
373  }
374 
375  bound_set.insert(fam);
376  }
377  } catch (const ibrcommon::vaddress::address_exception &ex) {
378  IBRCOMMON_LOGGER_TAG(IPNDAgent::TAG, error) << "unsupported multicast address " << addr.toString() << ": " << ex.what() << IBRCOMMON_LOGGER_ENDL;
379  }
380  }
381 #endif
382 
383  // listen to P2P dial-up events
385 
386  // join multicast groups and register as discovery handler
387  ibrcommon::MutexLock l(_interface_lock);
388 
389  for (std::set<ibrcommon::vinterface>::const_iterator it_iface = _interfaces.begin(); it_iface != _interfaces.end(); ++it_iface)
390  {
391  const ibrcommon::vinterface &iface = (*it_iface);
392 
393  // subscribe to NetLink events on our interfaces
394  ibrcommon::LinkManager::getInstance().addEventListener(iface, this);
395 
396  // register as discovery handler for this interface
398 
399  // join to all multicast addresses on this interface
400  join(iface);
401  }
402  }
403 
404  void IPNDAgent::componentDown() throw ()
405  {
406  // un-listen to P2P dial-up events
408 
409  // unsubscribe to NetLink events
410  ibrcommon::LinkManager::getInstance().removeEventListener(this);
411 
412  // un-register as discovery handler for this interface
414 
415  // mark the send socket as down
416  _state = false;
417 
418  // shutdown and destroy all sockets
419  _socket.destroy();
420 
421  ibrcommon::JoinableThread::stop();
422  ibrcommon::JoinableThread::join();
423  }
424 
425  void IPNDAgent::componentRun() throw ()
426  {
427  struct timeval tv;
428 
429  // every second we want to transmit a discovery message, timeout of 1 seconds
430  tv.tv_sec = 1;
431  tv.tv_usec = 0;
432 
433  // get the reference to the discovery agent
435 
436  try {
437  while (true)
438  {
439  ibrcommon::socketset fds;
440 
441  try {
442  // select on all bound sockets
443  _socket.select(&fds, NULL, NULL, &tv);
444 
445  // receive from all sockets
446  for (ibrcommon::socketset::const_iterator iter = fds.begin(); iter != fds.end(); ++iter)
447  {
448  ibrcommon::multicastsocket &sock = dynamic_cast<ibrcommon::multicastsocket&>(**iter);
449 
450  char data[1500];
451  ibrcommon::vaddress sender;
452  DiscoveryBeacon beacon = agent.obtainBeacon();
453 
454  ssize_t len = sock.recvfrom(data, 1500, 0, sender);
455 
456  if (len < 0) return;
457 
458  stringstream ss;
459  ss.write(data, len);
460 
461  try {
462  ss >> beacon;
463 
464  if (beacon.isShort())
465  {
466  // generate name with the sender address
467  beacon.setEID( dtn::data::EID("udp://[" + sender.address() + "]:4556") );
468 
469  // add generated tcpcl service if the services list is empty
470  beacon.addService(dtn::net::DiscoveryService(dtn::core::Node::CONN_TCPIP, "ip=" + sender.address() + ";port=4556;"));
471  }
472 
473  DiscoveryBeacon::service_list &services = beacon.getServices();
474 
475  // add source address if not set
476  for (dtn::net::DiscoveryBeacon::service_list::iterator iter = services.begin(); iter != services.end(); ++iter) {
477  DiscoveryService &service = (*iter);
478 
479  if ( (service.getParameters().find("port=") != std::string::npos) &&
480  (service.getParameters().find("ip=") == std::string::npos) ) {
481 
482  // update service entry
483  service.update("ip=" + sender.address() + ";" + service.getParameters());
484  }
485  }
486 
487  // announce the received beacon
488  agent.onBeaconReceived(beacon);
489  } catch (const dtn::InvalidDataException&) {
490  } catch (const ibrcommon::IOException&) {
491  }
492  }
493 
494  // trigger an artificial timeout if the remaining timeout value is zero or below
495  if ( tv.tv_sec <= 0 && tv.tv_usec <= 0 )
496  throw ibrcommon::vsocket_timeout("timeout");
497 
498  } catch (const ibrcommon::vsocket_timeout&) {
499  // reset timeout to 1 second
500  tv.tv_sec = 1;
501  tv.tv_usec = 0;
502  }
503 
504  yield();
505  }
506  } catch (const ibrcommon::vsocket_interrupt&) {
507  // vsocket has been interrupted - exit now
508  } catch (const ibrcommon::socket_exception &ex) {
509  // unexpected error - exit now
510  IBRCOMMON_LOGGER_TAG(IPNDAgent::TAG, error) << "unexpected error: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
511  }
512  }
513 
515  {
516  // shutdown and interrupt the receiving thread
517  _socket.down();
518  }
519 
520  const std::string IPNDAgent::getName() const
521  {
522  return "IPNDAgent";
523  }
524  }
525 }
std::list< DiscoveryService > service_list
DiscoveryBeacon obtainBeacon() const
virtual ~IPNDAgent()
Definition: IPNDAgent.cpp:63
static void add(EventReceiver< E > *receiver)
void setEID(const dtn::data::EID &eid)
void update(const std::string &parameters)
void add(const ibrcommon::vaddress &address)
Definition: IPNDAgent.cpp:68
virtual const std::string getName() const
Definition: IPNDAgent.cpp:520
static void remove(const EventReceiver< E > *receiver)
IPNDAgent(int port)
Definition: IPNDAgent.cpp:54
void raiseEvent(const dtn::net::P2PDialupEvent &evt)
Definition: IPNDAgent.cpp:240
dtn::net::DiscoveryAgent & getDiscoveryAgent()
Definition: BundleCore.cpp:265
virtual void componentRun()
Definition: IPNDAgent.cpp:425
void unregisterService(const ibrcommon::vinterface &iface, const dtn::net::DiscoveryBeaconHandler *handler)
const std::string & getParameters() const
const std::string TAG
Definition: dtnoutbox.cpp:62
void eventNotify(const ibrcommon::LinkEvent &evt)
Definition: IPNDAgent.cpp:294
virtual void componentUp()
Definition: IPNDAgent.cpp:332
void onBeaconReceived(const DiscoveryBeacon &beacon)
void registerService(const ibrcommon::vinterface &iface, dtn::net::DiscoveryBeaconHandler *handler)
virtual void componentDown()
Definition: IPNDAgent.cpp:404
void bind(const ibrcommon::vinterface &net)
Definition: IPNDAgent.cpp:73
static BundleCore & getInstance()
Definition: BundleCore.cpp:82
void onAdvertiseBeacon(const ibrcommon::vinterface &iface, const DiscoveryBeacon &beacon)
Definition: IPNDAgent.cpp:202