IBR-DTNSuite  0.10
LOWPANConvergenceLayer.cpp
Go to the documentation of this file.
1 /*
2  * LOWPANConnection.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 "net/LOWPANConnection.h"
24 #include "core/EventDispatcher.h"
25 #include "core/BundleCore.h"
26 #include "core/TimeEvent.h"
29 
30 #include <ibrcommon/Logger.h>
33 
34 #include <sys/socket.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38 
39 #include <iostream>
40 #include <list>
41 
42 #define EXTENDED_MASK 0x08
43 #define SEQ_NUM_MASK 0x07
44 
45 using namespace dtn::data;
46 
47 namespace dtn
48 {
49  namespace net
50  {
51  LOWPANConvergenceLayer::LOWPANConvergenceLayer(const ibrcommon::vinterface &net, uint16_t panid, unsigned int mtu)
52  : DiscoveryAgent(dtn::daemon::Configuration::getInstance().getDiscovery()),
53  _net(net), _panid(panid), _ipnd_buf(BUFF_SIZE), _ipnd_buf_len(0), m_maxmsgsize(mtu), _running(false)
54  {
55  // convert the panid into a string
56  std::stringstream ss;
57  ss << _panid;
58 
59  // assign the broadcast address
60  _addr_broadcast = ibrcommon::vaddress("0xffff", ss.str(), AF_IEEE802154);
61  }
62 
64  {
65  componentDown();
66  }
67 
69  {
71  }
72 
74  {
75  if (iface == _net)
76  {
77  stringstream service;
78 
79  struct sockaddr_ieee802154 address;
81  address.addr.pan_id = _panid;
82 
83  // Get address via netlink
85 
86  //FIXME better naming for address and panid. This will need updates to the service parser.
87  service << "ip=" << address.addr.short_addr << ";port=" << _panid << ";";
88 
89  announcement.addService( DiscoveryService("lowpancl", service.str()));
90  }
91  else
92  {
94  }
95  }
96 
97  void LOWPANConvergenceLayer::send_cb(const char *buf, const size_t len, const ibrcommon::vaddress &addr)
98  {
99  ibrcommon::socketset socks = _vsocket.getAll();
100  if (socks.size() == 0) return;
101  ibrcommon::lowpansocket &sock = dynamic_cast<ibrcommon::lowpansocket&>(**socks.begin());
102 
103  // set write lock
104  ibrcommon::MutexLock l(m_writelock);
105 
106  if (_addr_broadcast == addr) {
107  // disable auto-ack feature for broadcast
108  sock.setAutoAck(false);
109 
110  // send converted line
111  sock.sendto(buf, len, 0, _addr_broadcast);
112 
113  // re-enable auto-ack feature
114  sock.setAutoAck(true);
115  } else {
116  // send converted line
117  sock.sendto(buf, len, 0, addr);
118  }
119  }
120 
122  {
123  const std::list<dtn::core::Node::URI> uri_list = node.get(dtn::core::Node::CONN_LOWPAN);
124  if (uri_list.empty()) return;
125 
126  const dtn::core::Node::URI &uri = uri_list.front();
127 
128  std::string address;
129  unsigned int pan;
130 
131  uri.decode(address, pan);
132 
133  std::stringstream ss_pan; ss_pan << pan;
134 
135  ibrcommon::vaddress addr( address, ss_pan.str(), AF_IEEE802154 );
136 
137  IBRCOMMON_LOGGER_DEBUG_TAG("LOWPANConvergenceLayer", 55) << "LOWPANConvergenceLayer::queue"<< IBRCOMMON_LOGGER_ENDL;
138 
139  ibrcommon::MutexLock lc(_connection_lock);
140  LOWPANConnection *connection = getConnection(addr);
141  connection->_sender.queue(job);
142  }
143 
144  LOWPANConnection* LOWPANConvergenceLayer::getConnection(const ibrcommon::vaddress &addr)
145  {
146  // Test if connection for this address already exist
147  for(std::list<LOWPANConnection*>::iterator i = ConnectionList.begin(); i != ConnectionList.end(); ++i)
148  {
149  LOWPANConnection &conn = dynamic_cast<LOWPANConnection&>(**i);
150 
151  IBRCOMMON_LOGGER_DEBUG_TAG("LOWPANConvergenceLayer", 55) << "Connection address: " << conn._address.toString() << IBRCOMMON_LOGGER_ENDL;
152 
153  if (conn._address == addr)
154  return (*i);
155  }
156 
157  // Connection does not exist, create one and put it into the list
158  LOWPANConnection *connection = new LOWPANConnection(addr, (*this));
159 
160  ConnectionList.push_back(connection);
161  IBRCOMMON_LOGGER_DEBUG_TAG("LOWPANConvergenceLayer", 55) << "LOWPANConvergenceLayer::getConnection "<< connection->_address.toString() << IBRCOMMON_LOGGER_ENDL;
162  connection->start();
163  return connection;
164  }
165 
167  {
168  ibrcommon::MutexLock lc(_connection_lock);
169 
170  std::list<LOWPANConnection*>::iterator i;
171  for(i = ConnectionList.begin(); i != ConnectionList.end(); ++i)
172  {
173  if ((*i) == conn)
174  {
175  ConnectionList.erase(i);
176  return;
177  }
178  }
179  }
180 
182  {
183  // routine checked for throw() on 15.02.2013
185 
186  try {
187  _vsocket.add(new ibrcommon::lowpansocket(_panid, _net));
188  _vsocket.up();
189 
190  addService(this);
191  } catch (const ibrcommon::socket_exception &ex) {
192  IBRCOMMON_LOGGER_TAG("LOWPANConvergenceLayer", error) << "bind to " << _net.toString() << ":" << _panid << " failed (" << ex.what() << ")" << IBRCOMMON_LOGGER_ENDL;
193  }
194 
195  // set component in running mode
196  _running = true;
197  }
198 
200  {
201  _vsocket.destroy();
203  stop();
204  join();
205  }
206 
207  void LOWPANConvergenceLayer::sendAnnoucement(const uint16_t &sn, std::list<dtn::net::DiscoveryServiceProvider*> &providers)
208  {
209  IBRCOMMON_LOGGER_DEBUG_TAG("LOWPANConvergenceLayer", 60) << "LOWPAN IPND beacon send started" << IBRCOMMON_LOGGER_ENDL;
210 
212 
213  // set sequencenumber
214  announcement.setSequencenumber(sn);
215 
216  // clear all services
217  announcement.clearServices();
218 
219  // add services
220  for (std::list<dtn::net::DiscoveryServiceProvider*>::iterator iter = providers.begin(); iter != providers.end(); ++iter)
221  {
222  dtn::net::DiscoveryServiceProvider &provider = (**iter);
223 
224  try {
225  // update service information
226  provider.update(_net, announcement);
228 
229  }
230  }
231  // Set extended header bit. Everything else 0
232  _ipnd_buf[0] = 0x08;
233  // Set discovery bit in extended header
234  _ipnd_buf[1] = (char)0x80;
235 
236  // serialize announcement
237  stringstream ss;
238  ss << announcement;
239 
240  dtn::data::Length len = ss.str().size();
241  if (len > 113)
242  IBRCOMMON_LOGGER_TAG("LOWPANConvergenceLayer", error) << "Discovery announcement to big (" << len << ")" << IBRCOMMON_LOGGER_ENDL;
243 
244  // copy data infront of the 2 byte header
245  memcpy(&_ipnd_buf[2], ss.str().c_str(), len);
246 
247  // send out broadcast frame
248  send_cb(&_ipnd_buf[0], len + 2, _addr_broadcast);
249  }
250 
252  {
253  while (_running)
254  {
255  try {
256  ibrcommon::socketset readfds;
257  _vsocket.select(&readfds, NULL, NULL, NULL);
258 
259  for (ibrcommon::socketset::iterator iter = readfds.begin(); iter != readfds.end(); ++iter) {
260  ibrcommon::lowpansocket &sock = dynamic_cast<ibrcommon::lowpansocket&>(**iter);
261 
262  std::vector<char> data(m_maxmsgsize);
263  char header;
264 
265  // place to store the peer address
266  ibrcommon::vaddress peeraddr;
267 
268  // Receive full frame from socket
269  ssize_t len = sock.recvfrom(&data[0], static_cast<size_t>(m_maxmsgsize), 0, peeraddr);
270 
271  IBRCOMMON_LOGGER_DEBUG_TAG("LOWPANConvergenceLayer", 40) << "Received IEEE 802.15.4 frame from " << peeraddr.toString() << IBRCOMMON_LOGGER_ENDL;
272 
273  // We got nothing from the socket, keep reading
274  if (len <= 0)
275  continue;
276 
277  // Retrieve header of frame
278  header = data[0];
279 
280  // Check for extended header and retrieve if available
281  if ((header & EXTENDED_MASK) && (data[1] & 0x80)) {
282  DiscoveryAnnouncement announce;
283  stringstream ss;
284  ss.write(&data[2], len-2);
285  ss >> announce;
286  DiscoveryAgent::received(announce.getEID(), announce.getServices(), 30);
287  continue;
288  }
289 
290  ibrcommon::MutexLock lc(_connection_lock);
291 
292  // Connection instance for this address
293  LOWPANConnection* connection = getConnection(peeraddr);
294 
295  // Decide in which queue to write based on the src address
296  connection->getStream().queue(&data[0], len);
297  }
298  } catch (const ibrcommon::vsocket_interrupt&) {
299  return;
300  }
301 
302  yield();
303  }
304  }
305 
306  void LOWPANConvergenceLayer::raiseEvent(const Event *evt) throw ()
307  {
308  try {
309  const TimeEvent &time=dynamic_cast<const TimeEvent&>(*evt);
310  if (time.getAction() == TIME_SECOND_TICK)
311  if (time.getTimestamp().get<size_t>() % 5 == 0)
312  timeout();
313  } catch (const std::bad_cast&)
314  {}
315  }
316 
318  {
319  _running = false;
320  _vsocket.down();
321  }
322 
323  const std::string LOWPANConvergenceLayer::getName() const
324  {
325  return "LOWPANConvergenceLayer";
326  }
327  }
328 }