IBR-DTNSuite  0.12
LOWPANDatagramService.cpp
Go to the documentation of this file.
1 /*
2  * LOWPANDatagramService.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 
23 #include <ibrdtn/utils/Utils.h>
24 
27 
28 #include <ibrcommon/Logger.h>
29 
30 #include <string.h>
31 #include <vector>
32 
33 namespace dtn
34 {
35  namespace net
36  {
37  const std::string LOWPANDatagramService::TAG = "LOWPANDatagramService";
38 
40  : _panid(panid), _iface(iface)
41  {
42  // set connection parameters
43  _params.max_msg_length = 115;
44  _params.max_seq_numbers = 4;
46  _params.initial_timeout = 2000; // initial timeout 2 seconds
47  _params.seq_check = true; // no sequence number checks
48  _params.retry_limit = 5;
49 
50  // convert the panid into a string
51  std::stringstream ss;
52  ss << _panid;
53 
54  // assign the broadcast address
55  _addr_broadcast = ibrcommon::vaddress("65535", ss.str(), AF_IEEE802154);
56  }
57 
59  {
60  // destroy all socket objects
61  _vsocket.destroy();
62  }
63 
69  {
70  try {
71  _vsocket.destroy();
72  _vsocket.add(new ibrcommon::lowpansocket(_panid, _iface));
73  _vsocket.up();
74  } catch (const std::bad_cast&) {
75  throw DatagramException("bind failed");
76  } catch (const ibrcommon::Exception&) {
77  throw DatagramException("bind failed");
78  }
79  }
80 
85  {
86  // abort socket operations
87  _vsocket.down();
88  }
89 
96  void LOWPANDatagramService::send(const char &type, const char &flags, const unsigned int &seqno, const std::string &identifier, const char *buf, size_t length) throw (DatagramException)
97  {
98  try {
99  if (length > _params.max_msg_length)
100  {
101  IBRCOMMON_LOGGER_TAG(LOWPANDatagramService::TAG, error) << "send buffer to big to be transferred (" << length << ")."<< IBRCOMMON_LOGGER_ENDL;
102  throw DatagramException("send failed - buffer to big to be transferred");
103  }
104 
105  ibrcommon::socketset socks = _vsocket.getAll();
106  if (socks.size() == 0) return;
107  ibrcommon::lowpansocket &sock = dynamic_cast<ibrcommon::lowpansocket&>(**socks.begin());
108 
109  // decode destination address
110  ibrcommon::vaddress destaddr;
111  LOWPANDatagramService::decode(identifier, destaddr);
112 
113  // buffer for the datagram
114  std::vector<char> tmp(length + 1);
115 
116  // encode the header (1 byte)
117  tmp[0] = 0;
118 
119  // compat: 00
120 
121  // type: 01 = DATA, 10 = DISCO, 11 = ACK, 00 = NACK
122  if (type == DatagramConvergenceLayer::HEADER_SEGMENT) tmp[0] |= 0x01 << 4;
123  else if (type == DatagramConvergenceLayer::HEADER_BROADCAST) tmp[0] |= 0x02 << 4;
124  else if (type == DatagramConvergenceLayer::HEADER_ACK) tmp[0] |= 0x03 << 4;
125  else if (type == DatagramConvergenceLayer::HEADER_NACK) tmp[0] |= 0x00 << 4;
126 
127  // seq.no: xx (2 bit)
128  tmp[0] |= static_cast<char>((0x03 & seqno) << 2);
129 
130  // flags: 10 = first, 00 = middle, 01 = last, 11 = both
131  if (flags & DatagramService::SEGMENT_FIRST) tmp[0] |= 0x2;
132  if (flags & DatagramService::SEGMENT_LAST) tmp[0] |= 0x1;
133 
134  if (length > 0) {
135  // copy payload to the new buffer
136  ::memcpy(&tmp[1], buf, length);
137  }
138 
139  IBRCOMMON_LOGGER_DEBUG_TAG(LOWPANDatagramService::TAG, 20) << "sendto() type: " << std::hex << (int)type << "; flags: " << std::hex << (int)flags << "; seqno: " << seqno << "; address: " << identifier << IBRCOMMON_LOGGER_ENDL;
140 
141  // send converted line
142  sock.sendto(&tmp[0], length + 1, 0, destaddr);
143  } catch (const ibrcommon::Exception&) {
144  throw DatagramException("send failed");
145  }
146  }
147 
153  void LOWPANDatagramService::send(const char &type, const char &flags, const unsigned int &seqno, const char *buf, size_t length) throw (DatagramException)
154  {
155  try {
156  if (length > _params.max_msg_length)
157  {
158  IBRCOMMON_LOGGER_TAG(LOWPANDatagramService::TAG, error) << "send buffer to big to be transferred (" << length << ")."<< IBRCOMMON_LOGGER_ENDL;
159  throw DatagramException("send failed - buffer to big to be transferred");
160  }
161 
162  ibrcommon::socketset socks = _vsocket.getAll();
163  if (socks.size() == 0) return;
164  ibrcommon::lowpansocket &sock = dynamic_cast<ibrcommon::lowpansocket&>(**socks.begin());
165 
166  // buffer for the datagram
167  std::vector<char> tmp(length + 1);
168 
169  // encode the header (1 byte)
170  tmp[0] = 0;
171 
172  // compat: 00
173 
174  // type: 01 = DATA, 10 = DISCO, 11 = ACK, 00 = NACK
175  if (type == DatagramConvergenceLayer::HEADER_SEGMENT) tmp[0] |= 0x01 << 4;
176  else if (type == DatagramConvergenceLayer::HEADER_BROADCAST) tmp[0] |= 0x02 << 4;
177  else if (type == DatagramConvergenceLayer::HEADER_ACK) tmp[0] |= 0x03 << 4;
178  else if (type == DatagramConvergenceLayer::HEADER_NACK) tmp[0] |= 0x00 << 4;
179 
180  // seq.no: xx (2 bit)
181  tmp[0] |= static_cast<char>((0x03 & seqno) << 2);
182 
183  // flags: 10 = first, 00 = middle, 01 = last, 11 = both
184  if (flags & DatagramService::SEGMENT_FIRST) tmp[0] |= 0x2;
185  if (flags & DatagramService::SEGMENT_LAST) tmp[0] |= 0x1;
186 
187  if (length > 0) {
188  // copy payload to the new buffer
189  ::memcpy(&tmp[1], buf, length);
190  }
191 
192  // disable auto-ack feature for broadcast
193  sock.setAutoAck(false);
194 
195  IBRCOMMON_LOGGER_DEBUG_TAG(LOWPANDatagramService::TAG, 20) << "sendto() type: " << std::hex << (int)type << "; flags: " << std::hex << (int)flags << "; seqno: " << seqno << "; address: broadcast" << IBRCOMMON_LOGGER_ENDL;
196 
197  // send converted line
198  sock.sendto(&tmp[0], length + 1, 0, _addr_broadcast);
199 
200  // re-enable auto-ack feature
201  sock.setAutoAck(true);
202  } catch (const ibrcommon::Exception&) {
203  throw DatagramException("send failed");
204  }
205  }
206 
215  size_t LOWPANDatagramService::recvfrom(char *buf, size_t length, char &type, char &flags, unsigned int &seqno, std::string &address) throw (DatagramException)
216  {
217  try {
218  ibrcommon::socketset readfds;
219  _vsocket.select(&readfds, NULL, NULL, NULL);
220 
221  for (ibrcommon::socketset::iterator iter = readfds.begin(); iter != readfds.end(); ++iter) {
222  ibrcommon::lowpansocket &sock = dynamic_cast<ibrcommon::lowpansocket&>(**iter);
223 
224  std::vector<char> tmp(length + 1);
225 
226  // from address of the received frame
227  ibrcommon::vaddress fromaddr;
228 
229  // Receive full frame from socket
230  size_t ret = sock.recvfrom(&tmp[0], length + 1, 0, fromaddr);
231 
232  // decode the header (1 byte)
233  // IGNORE: compat: 00
234 
235  // reset flags to zero
236  flags = 0;
237 
238  // type: 01 = DATA, 10 = DISCO, 11 = ACK, 00 = NACK
239  switch (tmp[0] & (0x03 << 4)) {
240  case (0x01 << 4):
242 
243  // flags: 10 = first, 00 = middle, 01 = last, 11 = both
244  if (tmp[0] & 0x02) flags |= DatagramService::SEGMENT_FIRST;
245  if (tmp[0] & 0x01) flags |= DatagramService::SEGMENT_LAST;
246 
247  break;
248  case (0x02 << 4):
250  break;
251  case (0x03 << 4):
253  break;
254  default:
256 
257  // flags: 10 = temporary
258  if (tmp[0] & 0x02) flags |= DatagramService::NACK_TEMPORARY;
259 
260  break;
261  }
262 
263  // seq.no: xx (2 bit)
264  seqno = (tmp[0] & (0x03 << 2)) >> 2;
265 
266  if (ret > 1) {
267  // copy payload into the buffer
268  ::memcpy(buf, &tmp[1], ret);
269  }
270 
271  // encode into the right format
272  address = LOWPANDatagramService::encode(fromaddr);
273 
274  IBRCOMMON_LOGGER_DEBUG_TAG(LOWPANDatagramService::TAG, 20) << "recvfrom() type: " << std::hex << (int)type << "; flags: " << std::hex << (int)flags << "; seqno: " << seqno << "; address: " << address << IBRCOMMON_LOGGER_ENDL;
275 
276  return ret - 1;
277  }
278  } catch (const ibrcommon::Exception&) {
279  throw DatagramException("receive failed");
280  }
281 
282  return 0;
283  }
284 
291  {
292  std::stringstream ss_pan; ss_pan << _panid;
293 
294  // Get address via netlink
295  ibrcommon::vaddress addr;
296  ibrcommon::lowpansocket::getAddress(_iface, ss_pan.str(), addr);
297 
298  return LOWPANDatagramService::encode(addr);
299  }
300 
306  {
307  return _iface;
308  }
309 
315  {
317  }
318 
320  {
321  return _params;
322  }
323 
324  const std::string LOWPANDatagramService::encode(const ibrcommon::vaddress &addr)
325  {
326  std::stringstream ss;
327  ss << "addr=" << addr.address() << ";pan=" << addr.service() << ";";
328  return ss.str();
329  }
330 
331  void LOWPANDatagramService::decode(const std::string &identifier, ibrcommon::vaddress &addr)
332  {
333  std::string address;
334  std::string service;
335 
336  // parse parameters
337  std::vector<string> parameters = dtn::utils::Utils::tokenize(";", identifier);
338  std::vector<string>::const_iterator param_iter = parameters.begin();
339 
340  while (param_iter != parameters.end())
341  {
342  std::vector<string> p = dtn::utils::Utils::tokenize("=", (*param_iter));
343 
344  if (p[0].compare("addr") == 0)
345  {
346  address = p[1];
347  }
348 
349  if (p[0].compare("pan") == 0)
350  {
351  service = p[1];
352  }
353 
354  ++param_iter;
355  }
356 
357  addr = ibrcommon::vaddress(address, service, AF_IEEE802154);
358  }
359  } /* namespace net */
360 } /* namespace dtn */