IBR-DTNSuite  0.10
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 namespace dtn
30 {
31  namespace net
32  {
33  const ibrcommon::vaddress UDPDatagramService::BROADCAST_ADDR("ff02::1", UDPDatagramService::BROADCAST_PORT, AF_INET6);
34 
36  : _msock(NULL), _iface(iface), _bind_port(port)
37  {
38  // set connection parameters
39  _params.max_msg_length = mtu - 2; // minus 2 bytes because we encode seqno and flags into 2 bytes
40  _params.max_seq_numbers = 8; // seqno 0..7
42  _params.initial_timeout = 50; // initial timeout 50ms
43  _params.seq_check = true;
44  }
45 
47  {
48  // delete all sockets
49  _vsocket.destroy();
50  }
51 
57  {
58  // delete all sockets
59  _vsocket.destroy();
60 
61  try {
62  // bind socket to the multicast port
63  _msock = new ibrcommon::multicastsocket(BROADCAST_PORT);
64 
65  try {
66  _msock->join(BROADCAST_ADDR, _iface);
67  } catch (const ibrcommon::socket_raw_error &e) {
68  if (e.error() != EADDRINUSE) {
69  IBRCOMMON_LOGGER_TAG("UDPDatagramService", error) << "join failed on " << _iface.toString() << "; " << e.what() << IBRCOMMON_LOGGER_ENDL;
70  }
71  } catch (const ibrcommon::socket_exception &e) {
72  IBRCOMMON_LOGGER_DEBUG_TAG("UDPDatagramService", 10) << "can not join " << BROADCAST_ADDR.toString() << " on " << _iface.toString() << "; " << e.what() << IBRCOMMON_LOGGER_ENDL;
73  }
74 
75  // add multicast socket to receiver sockets
76  _vsocket.add(_msock);
77 
78  if (_iface.empty()) {
79  // bind socket to interface
80  _vsocket.add(new ibrcommon::udpsocket(_bind_port));
81  } else {
82  // create sockets for all addresses on the interface
83  std::list<ibrcommon::vaddress> addrs = _iface.getAddresses();
84 
85  // convert the port into a string
86  std::stringstream ss; ss << _bind_port;
87 
88  for (std::list<ibrcommon::vaddress>::iterator iter = addrs.begin(); iter != addrs.end(); ++iter) {
89  ibrcommon::vaddress &addr = (*iter);
90 
91  // handle the addresses according to their family
92  switch (addr.family()) {
93  case AF_INET:
94  case AF_INET6:
95  addr.setService(ss.str());
96  _vsocket.add(new ibrcommon::udpsocket(addr), _iface);
97  break;
98  default:
99  break;
100  }
101  }
102  }
103  } catch (const ibrcommon::Exception&) {
104  throw DatagramException("bind failed");
105  }
106 
107  // setup socket operations
108  _vsocket.up();
109  }
110 
115  {
116  // abort socket operations
117  _vsocket.down();
118  }
119 
126  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)
127  {
128  // decode address identifier
129  ibrcommon::vaddress destination;
130  UDPDatagramService::decode(identifier, destination);
131 
132  // forward to actually send method
133  send(type, flags, seqno, destination, buf, length);
134  }
135 
141  void UDPDatagramService::send(const char &type, const char &flags, const unsigned int &seqno, const char *buf, size_t length) throw (DatagramException)
142  {
143  // forward to actually send method using the broadcast address
144  send(type, flags, seqno, BROADCAST_ADDR, buf, length);
145  }
146 
147  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)
148  {
149  try {
150  std::vector<char> tmp(length + 2);
151 
152  // add a 2-byte header - type of frame first
153  tmp[0] = type;
154 
155  // flags (4-bit) + seqno (4-bit)
156  tmp[1] = static_cast<char>((0xf0 & (flags << 4)) | (0x0f & seqno));
157 
158  // copy payload to the new buffer
159  ::memcpy(&tmp[2], buf, length);
160 
161  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;
162 
163  // create vaddress
164  ibrcommon::socketset sockset = _vsocket.getAll();
165  for (ibrcommon::socketset::iterator iter = sockset.begin(); iter != sockset.end(); ++iter) {
166  if ((*iter) == _msock) continue;
167  try {
168  ibrcommon::udpsocket &sock = dynamic_cast<ibrcommon::udpsocket&>(**iter);
169  sock.sendto(&tmp[0], length + 2, 0, destination);
170  return;
171  } catch (const ibrcommon::Exception&) {
172  } catch (const std::bad_cast&) { }
173  }
174 
175  // throw exception if all sends failed
176  throw DatagramException("send failed");
177  } catch (const ibrcommon::Exception&) {
178  throw DatagramException("send failed");
179  }
180  }
181 
190  size_t UDPDatagramService::recvfrom(char *buf, size_t length, char &type, char &flags, unsigned int &seqno, std::string &address) throw (DatagramException)
191  {
192  try {
193  ibrcommon::socketset readfds;
194  _vsocket.select(&readfds, NULL, NULL, NULL);
195 
196  for (ibrcommon::socketset::iterator iter = readfds.begin(); iter != readfds.end(); ++iter) {
197  try {
198  ibrcommon::udpsocket &sock = dynamic_cast<ibrcommon::udpsocket&>(**iter);
199 
200  std::vector<char> tmp(length + 2);
201  ibrcommon::vaddress peeraddr;
202  size_t ret = sock.recvfrom(&tmp[0], length + 2, 0, peeraddr);
203 
204  // first byte if the type
205  type = tmp[0];
206 
207  // second byte if flags (4-bit) + seqno (4-bit)
208  flags = 0x0f & (tmp[1] >> 4);
209  seqno = 0x0f & tmp[1];
210 
211  // return the encoded format
212  address = UDPDatagramService::encode(peeraddr);
213 
214  // copy payload to the destination buffer
215  ::memcpy(buf, &tmp[2], ret - 2);
216 
217  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;
218 
219  return ret - 2;
220  } catch (const std::bad_cast&) {
221 
222  }
223  }
224  } catch (const ibrcommon::Exception&) {
225  throw DatagramException("receive failed");
226  }
227 
228  return 0;
229  }
230 
235  const std::string UDPDatagramService::getServiceTag() const
236  {
237  return "dgram:udp";
238  }
239 
246  {
247  // get all addresses
248  std::list<ibrcommon::vaddress> addrs = _iface.getAddresses();
249 
250  for (std::list<ibrcommon::vaddress>::iterator iter = addrs.begin(); iter != addrs.end(); ++iter) {
251  ibrcommon::vaddress &addr = (*iter);
252 
253  try {
254  // handle the addresses according to their family
255  switch (addr.family()) {
256  case AF_INET:
257  case AF_INET6:
258  return UDPDatagramService::encode(addr, _bind_port);
259  break;
260  default:
261  break;
262  }
263  } catch (const ibrcommon::vaddress::address_exception &ex) {
264  IBRCOMMON_LOGGER_DEBUG_TAG("UDPDatagramService", 25) << ex.what() << IBRCOMMON_LOGGER_ENDL;
265  }
266  }
267 
268  // no addresses available, return empty string
269  return "";
270  }
271 
277  {
278  return _iface;
279  }
280 
286  {
288  }
289 
291  {
292  return _params;
293  }
294 
295  const std::string UDPDatagramService::encode(const ibrcommon::vaddress &address, const int port)
296  {
297  std::stringstream ss;
298  ss << "ip=" << address.address() << ";port=";
299 
300  if (port == 0) ss << address.service();
301  else ss << port;
302 
303  ss << ";";
304  return ss.str();
305  }
306 
307  void UDPDatagramService::decode(const std::string &identifier, ibrcommon::vaddress &address)
308  {
309  std::string addr;
310  std::string port;
311 
312  // parse parameters
313  std::vector<string> parameters = dtn::utils::Utils::tokenize(";", identifier);
314  std::vector<string>::const_iterator param_iter = parameters.begin();
315 
316  while (param_iter != parameters.end())
317  {
318  std::vector<string> p = dtn::utils::Utils::tokenize("=", (*param_iter));
319 
320  if (p[0].compare("ip") == 0)
321  {
322  addr = p[1];
323  }
324 
325  if (p[0].compare("port") == 0)
326  {
327  port = p[1];
328  }
329 
330  ++param_iter;
331  }
332 
333  address = ibrcommon::vaddress(addr, port);
334  }
335  } /* namespace net */
336 } /* namespace dtn */