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