IBR-DTN  1.0.0
UDPDatagramService.cpp
Go to the documentation of this file.
1 /*
2  * UDPDatagramService.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 "net/UDPDatagramService.h"
23 #include <ibrdtn/utils/Utils.h>
24 #include <ibrcommon/Logger.h>
25 #include <ibrcommon/net/socket.h>
26 #include <vector>
27 #include <string.h>
28 
29 #ifdef __WIN32__
30 #define EADDRINUSE WSAEADDRINUSE
31 #endif
32 
33 namespace dtn
34 {
35  namespace net
36  {
37  const ibrcommon::vaddress UDPDatagramService::BROADCAST_ADDR("ff02::1", UDPDatagramService::BROADCAST_PORT, AF_INET6);
38 
39  UDPDatagramService::UDPDatagramService(const ibrcommon::vinterface &iface, int port, size_t mtu)
40  : _msock(NULL), _iface(iface), _bind_port(port)
41  {
42  // set connection parameters
43  _params.max_msg_length = mtu - 2; // minus 2 bytes because we encode seqno and flags into 2 bytes
44  _params.max_seq_numbers = 16; // seqno 0..15
46  _params.initial_timeout = 50; // initial timeout 50ms
47  _params.retry_limit = 5;
48  }
49 
51  {
52  // delete all sockets
53  _vsocket.destroy();
54  }
55 
61  {
62  // delete all sockets
63  _vsocket.destroy();
64 
65  try {
66  // bind socket to the multicast port
67  _msock = new ibrcommon::multicastsocket(BROADCAST_PORT);
68 
69  try {
70  _msock->join(BROADCAST_ADDR, _iface);
71  } catch (const ibrcommon::socket_raw_error &e) {
72  if (e.error() != EADDRINUSE) {
73  IBRCOMMON_LOGGER_TAG("UDPDatagramService", error) << "join failed on " << _iface.toString() << "; " << e.what() << IBRCOMMON_LOGGER_ENDL;
74  }
75  } catch (const ibrcommon::socket_exception &e) {
76  IBRCOMMON_LOGGER_DEBUG_TAG("UDPDatagramService", 10) << "can not join " << BROADCAST_ADDR.toString() << " on " << _iface.toString() << "; " << e.what() << IBRCOMMON_LOGGER_ENDL;
77  }
78 
79  // add multicast socket to receiver sockets
80  _vsocket.add(_msock);
81 
82  if (_iface.isAny()) {
83  // bind socket to interface
84  _vsocket.add(new ibrcommon::udpsocket(_bind_port));
85  } else {
86  // create sockets for all addresses on the interface
87  std::list<ibrcommon::vaddress> addrs = _iface.getAddresses();
88 
89  // convert the port into a string
90  std::stringstream ss; ss << _bind_port;
91 
92  for (std::list<ibrcommon::vaddress>::iterator iter = addrs.begin(); iter != addrs.end(); ++iter) {
93  ibrcommon::vaddress &addr = (*iter);
94 
95  // handle the addresses according to their family
96  switch (addr.family()) {
97  case AF_INET:
98  case AF_INET6:
99  addr.setService(ss.str());
100  _vsocket.add(new ibrcommon::udpsocket(addr), _iface);
101  break;
102  default:
103  break;
104  }
105  }
106  }
107  } catch (const ibrcommon::Exception&) {
108  throw DatagramException("bind failed");
109  }
110 
111  // setup socket operations
112  _vsocket.up();
113  }
114 
119  {
120  // abort socket operations
121  _vsocket.down();
122  }
123 
130  void UDPDatagramService::send(const char &type, const char &flags, const unsigned int &seqno, const std::string &identifier, const char *buf, size_t length) throw (DatagramException)
131  {
132  // decode address identifier
133  ibrcommon::vaddress destination;
134  UDPDatagramService::decode(identifier, destination);
135 
136  // forward to actually send method
137  send(type, flags, seqno, destination, buf, length);
138  }
139 
145  void UDPDatagramService::send(const char &type, const char &flags, const unsigned int &seqno, const char *buf, size_t length) throw (DatagramException)
146  {
147  // forward to actually send method using the broadcast address
148  send(type, flags, seqno, BROADCAST_ADDR, buf, length);
149  }
150 
151  void UDPDatagramService::send(const char &type, const char &flags, const unsigned int &seqno, const ibrcommon::vaddress &destination, const char *buf, size_t length) throw (DatagramException)
152  {
153  try {
154  std::vector<char> tmp(length + 2);
155 
156  // add a 2-byte header - type of frame first
157  tmp[0] = type;
158 
159  // flags (4-bit) + seqno (4-bit)
160  tmp[1] = static_cast<char>((0xf0 & (flags << 4)) | (0x0f & seqno));
161 
162  // copy payload to the new buffer
163  ::memcpy(&tmp[2], buf, length);
164 
165  IBRCOMMON_LOGGER_DEBUG_TAG("UDPDatagramService", 20) << "send() type: " << std::hex << (int)type << "; flags: " << std::hex << (int)flags << "; seqno: " << std::dec << seqno << "; address: " << destination.toString() << IBRCOMMON_LOGGER_ENDL;
166 
167  // create vaddress
168  ibrcommon::socketset sockset = _vsocket.getAll();
169  for (ibrcommon::socketset::iterator iter = sockset.begin(); iter != sockset.end(); ++iter) {
170  if ((*iter) == _msock) continue;
171  try {
172  ibrcommon::udpsocket &sock = dynamic_cast<ibrcommon::udpsocket&>(**iter);
173  sock.sendto(&tmp[0], length + 2, 0, destination);
174  return;
175  } catch (const ibrcommon::Exception&) {
176  } catch (const std::bad_cast&) { }
177  }
178 
179  // throw exception if all sends failed
180  throw DatagramException("send failed");
181  } catch (const ibrcommon::Exception&) {
182  throw DatagramException("send failed");
183  }
184  }
185 
194  size_t UDPDatagramService::recvfrom(char *buf, size_t length, char &type, char &flags, unsigned int &seqno, std::string &address) throw (DatagramException)
195  {
196  try {
197  ibrcommon::socketset readfds;
198  _vsocket.select(&readfds, NULL, NULL, NULL);
199 
200  for (ibrcommon::socketset::iterator iter = readfds.begin(); iter != readfds.end(); ++iter) {
201  try {
202  ibrcommon::udpsocket &sock = dynamic_cast<ibrcommon::udpsocket&>(**iter);
203 
204  std::vector<char> tmp(length + 2);
205  ibrcommon::vaddress peeraddr;
206  size_t ret = sock.recvfrom(&tmp[0], length + 2, 0, peeraddr);
207 
208  // first byte is the type
209  type = tmp[0];
210 
211  // second byte is flags (4-bit) + seqno (4-bit)
212  flags = 0x0f & (tmp[1] >> 4);
213  seqno = 0x0f & tmp[1];
214 
215  // return the encoded format
216  address = UDPDatagramService::encode(peeraddr);
217 
218  // copy payload to the destination buffer
219  ::memcpy(buf, &tmp[2], ret - 2);
220 
221  IBRCOMMON_LOGGER_DEBUG_TAG("UDPDatagramService", 20) << "recvfrom() type: " << std::hex << (int)type << "; flags: " << std::hex << (int)flags << "; seqno: " << seqno << "; address: " << peeraddr.toString() << IBRCOMMON_LOGGER_ENDL;
222 
223  return ret - 2;
224  } catch (const std::bad_cast&) {
225 
226  }
227  }
228  } catch (const ibrcommon::Exception&) {
229  throw DatagramException("receive failed");
230  }
231 
232  return 0;
233  }
234 
241  {
242  // get all addresses
243  std::list<ibrcommon::vaddress> addrs = _iface.getAddresses();
244 
245  for (std::list<ibrcommon::vaddress>::iterator iter = addrs.begin(); iter != addrs.end(); ++iter) {
246  ibrcommon::vaddress &addr = (*iter);
247 
248  try {
249  // handle the addresses according to their family
250  switch (addr.family()) {
251  case AF_INET:
252  case AF_INET6:
253  return UDPDatagramService::encode(addr, _bind_port);
254  break;
255  default:
256  break;
257  }
258  } catch (const ibrcommon::vaddress::address_exception &ex) {
259  IBRCOMMON_LOGGER_DEBUG_TAG("UDPDatagramService", 25) << ex.what() << IBRCOMMON_LOGGER_ENDL;
260  }
261  }
262 
263  // no addresses available, return empty string
264  return "";
265  }
266 
271  const ibrcommon::vinterface& UDPDatagramService::getInterface() const
272  {
273  return _iface;
274  }
275 
281  {
283  }
284 
286  {
287  return _params;
288  }
289 
290  const std::string UDPDatagramService::encode(const ibrcommon::vaddress &address, const int port)
291  {
292  std::stringstream ss;
293  ss << "ip=" << address.address() << ";port=";
294 
295  if (port == 0) ss << address.service();
296  else ss << port;
297 
298  ss << ";";
299  return ss.str();
300  }
301 
302  void UDPDatagramService::decode(const std::string &identifier, ibrcommon::vaddress &address)
303  {
304  std::string addr;
305  std::string port;
306 
307  // parse parameters
308  std::vector<string> parameters = dtn::utils::Utils::tokenize(";", identifier);
309  std::vector<string>::const_iterator param_iter = parameters.begin();
310 
311  while (param_iter != parameters.end())
312  {
313  std::vector<string> p = dtn::utils::Utils::tokenize("=", (*param_iter));
314 
315  if (p[0].compare("ip") == 0)
316  {
317  addr = p[1];
318  }
319 
320  if (p[0].compare("port") == 0)
321  {
322  port = p[1];
323  }
324 
325  ++param_iter;
326  }
327 
328  address = ibrcommon::vaddress(addr, port);
329  }
330  } /* namespace net */
331 } /* namespace dtn */
UDPDatagramService(const ibrcommon::vinterface &iface, int port, size_t mtu=1280)
virtual const ibrcommon::vinterface & getInterface() const
virtual size_t recvfrom(char *buf, size_t length, char &type, char &flags, unsigned int &seqno, std::string &address)
virtual const std::string getServiceDescription() const
virtual void send(const char &type, const char &flags, const unsigned int &seqno, const std::string &address, const char *buf, size_t length)
virtual dtn::core::Node::Protocol getProtocol() const
virtual const DatagramService::Parameter & getParameter() const
static std::vector< std::string > tokenize(const std::string &token, const std::string &data, const std::string::size_type max=std::string::npos)
Definition: Utils.cpp:60