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