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