IBR-DTNSuite  0.12
DiscoveryBeacon.cpp
Go to the documentation of this file.
1 /*
2  * DiscoveryBeacon.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 "config.h"
23 #include "net/DiscoveryBeacon.h"
24 #include <ibrdtn/data/Exceptions.h>
25 #include <ibrdtn/data/Number.h>
26 #include <ibrcommon/Logger.h>
27 #include <typeinfo>
28 #include <iostream>
29 #include <vector>
30 
31 #ifdef __WIN32__
32 #include <winsock2.h>
33 #else
34 #include <netinet/in.h>
35 #endif
36 
37 namespace dtn
38 {
39  namespace net
40  {
42  : _version(version), _flags(BEACON_NO_FLAGS), _canonical_eid(eid), _sn(0)
43  {
44  }
45 
47  {
48  }
49 
51  {
52  switch (_version)
53  {
54  case DISCO_VERSION_00:
55  return (_flags & DiscoveryBeacon::BEACON_SHORT);
56 
57  case DISCO_VERSION_01:
58  return !(_flags & DiscoveryBeacon::BEACON_CONTAINS_EID);
59  };
60 
61  return false;
62  }
63 
65  {
66  _canonical_eid = eid;
67  }
68 
70  {
71  return _canonical_eid;
72  }
73 
75  {
76  return _services;
77  }
78 
80  {
81  return _services;
82  }
83 
85  {
86  _services.clear();
87  }
88 
89  const DiscoveryService& DiscoveryBeacon::getService(const std::string &name) const
90  {
91  for (service_list::const_iterator iter = _services.begin(); iter != _services.end(); ++iter)
92  {
93  if ((*iter).getName() == name)
94  {
95  return (*iter);
96  }
97  }
98 
99  throw dtn::MissingObjectException("No service found with tag " + name);
100  }
101 
103  {
104  for (service_list::iterator iter = _services.begin(); iter != _services.end(); ++iter)
105  {
106  if ((*iter).getName() == name)
107  {
108  return (*iter);
109  }
110  }
111 
112  throw dtn::MissingObjectException("No service found with tag " + name);
113  }
114 
116  {
117  _services.push_back(service);
118  }
119 
120  void DiscoveryBeacon::setSequencenumber(uint16_t sequence)
121  {
122  _sn = sequence;
123  }
124 
125  std::ostream &operator<<(std::ostream &stream, const DiscoveryBeacon &announcement)
126  {
127  const dtn::net::DiscoveryBeacon::service_list &services = announcement._services;
128 
129  switch (announcement._version)
130  {
132  {
133  if (services.empty())
134  {
135  const unsigned char flags = DiscoveryBeacon::BEACON_SHORT | announcement._flags;
136  stream << (unsigned char)DiscoveryBeacon::DISCO_VERSION_00 << flags;
137  return stream;
138  }
139 
140  const dtn::data::BundleString eid(announcement._canonical_eid.getString());
141  dtn::data::Number beacon_len;
142 
143  // determine the beacon length
144  beacon_len += eid.getLength();
145 
146  // add service block length
147  for (dtn::net::DiscoveryBeacon::service_list::const_iterator iter = services.begin(); iter != services.end(); ++iter)
148  {
149  beacon_len += (*iter).getLength();
150  }
151 
152  stream << (unsigned char)DiscoveryBeacon::DISCO_VERSION_00 << announcement._flags << beacon_len << eid;
153 
154  for (dtn::net::DiscoveryBeacon::service_list::const_iterator iter = services.begin(); iter != services.end(); ++iter)
155  {
156  stream << (*iter);
157  }
158 
159  break;
160  }
161 
163  {
164  unsigned char flags = 0;
165 
166  stream << (unsigned char)DiscoveryBeacon::DISCO_VERSION_01;
167 
168  if (announcement._canonical_eid != dtn::data::EID())
169  {
170  flags |= DiscoveryBeacon::BEACON_CONTAINS_EID;
171  }
172 
173  if (!services.empty())
174  {
175  flags |= DiscoveryBeacon::BEACON_SERVICE_BLOCK;
176  }
177 
178  stream << flags;
179 
180  // sequencenumber
181  const uint16_t sn = htons(announcement._sn);
182  stream.write( (const char*)&sn, 2 );
183 
184  if ( flags & DiscoveryBeacon::BEACON_CONTAINS_EID )
185  {
186  const dtn::data::BundleString eid(announcement._canonical_eid.getString());
187  stream << eid;
188  }
189 
190  if ( flags & DiscoveryBeacon::BEACON_SERVICE_BLOCK )
191  {
192  stream << dtn::data::Number(services.size());
193 
194  for (dtn::net::DiscoveryBeacon::service_list::const_iterator iter = services.begin(); iter != services.end(); ++iter)
195  {
196  stream << (*iter);
197  }
198  }
199 
200  break;
201  }
202 
204  {
205  uint8_t cl_type = 1;
206  char zero = '\0';
207  uint8_t interval = 10;
208  // uint32_t inet_addr;
209  uint16_t inet_port = htons(4556);
210  std::string eid = announcement._canonical_eid.getString();
211  uint16_t eid_len = htons((uint16_t)eid.length());
212  unsigned int add_zeros = (4 - (eid.length() % 4)) % 4;
213  uint16_t length = htons(static_cast<uint16_t>(12 + eid.length() + add_zeros));
214 
215 
216  stream << (unsigned char)cl_type;
217  stream.write((char*)&interval, 1);
218  stream.write((char*)&length, 2);
219 
220 // std::list<dtn::daemon::Configuration::NetConfig> interfaces = dtn::daemon::Configuration::getInstance().getInterfaces();
221 // dtn::daemon::Configuration::NetConfig &i = interfaces.front();
222 
223 // struct sockaddr_in sock_address;
224 //
225 // // set the local interface address
226 // i.interface.getAddress(&sock_address.sin_addr);
227 //
228 // stream.write((char*)&sock_address.sin_addr, 4);
229  stream.write(&zero, 1);
230  stream.write(&zero, 1);
231  stream.write(&zero, 1);
232  stream.write(&zero, 1);
233 
234  stream.write((char*)&inet_port, 2);
235  stream.write((char*)&eid_len, 2);
236  stream << eid;
237 
238  for (unsigned int i = 0; i < add_zeros; ++i)
239  {
240  stream.write((char*)&zero, 1);
241  }
242 
243  break;
244  }
245  }
246 
247  return stream;
248  }
249 
250  std::istream &operator>>(std::istream &stream, DiscoveryBeacon &announcement)
251  {
252  unsigned char version = 0;
253 
254  // do we running DTN2 compatibility mode?
255  if (announcement._version == DiscoveryBeacon::DTND_IPDISCOVERY)
256  {
257  // set version to IPDiscovery (DTN2)
259  }
260  else
261  {
262  // read IPND version of the frame
263  version = (unsigned char)stream.get();
264  }
265 
266  switch (version)
267  {
269  {
270  IBRCOMMON_LOGGER_DEBUG_TAG("DiscoveryBeacon", 60) << "beacon version 1 received" << IBRCOMMON_LOGGER_ENDL;
271 
272  dtn::data::Number beacon_len;
273  dtn::data::Number eid_len;
274 
275  stream.get((char&)announcement._flags);
276 
277  // catch a short beacon
278  if (DiscoveryBeacon::BEACON_SHORT == announcement._flags)
279  {
280  announcement._canonical_eid = dtn::data::EID();
281  return stream;
282  }
283 
284  stream >> beacon_len;
285  int remain = beacon_len.get<int>();
286 
288  stream >> eid;
289  remain -= static_cast<int>(eid.getLength());
290 
291  announcement._canonical_eid = dtn::data::EID((const std::string&)eid);
292 
293  // get the services
294  dtn::net::DiscoveryBeacon::service_list &services = announcement._services;
295 
296  // clear the services
297  services.clear();
298 
299  while (remain > 0)
300  {
301  // decode the service blocks
302  DiscoveryService service;
303  stream >> service;
304  services.push_back(service);
305  remain -= static_cast<int>(service.getLength());
306  }
307  break;
308  }
309 
311  {
312  IBRCOMMON_LOGGER_DEBUG_TAG("DiscoveryBeacon", 60) << "beacon version 2 received" << IBRCOMMON_LOGGER_ENDL;
313 
314  stream.get((char&)announcement._flags);
315 
316  IBRCOMMON_LOGGER_DEBUG_TAG("DiscoveryBeacon", 85) << "beacon flags: " << hex << (int)announcement._flags << IBRCOMMON_LOGGER_ENDL;
317 
318  uint16_t sn = 0;
319  stream.read((char*)&sn, 2);
320 
321  // convert from network byte order
322  uint16_t sequencenumber = ntohs(sn);
323 
324  IBRCOMMON_LOGGER_DEBUG_TAG("DiscoveryBeacon", 85) << "beacon sequence number: " << sequencenumber << IBRCOMMON_LOGGER_ENDL;
325 
326  if (announcement._flags & DiscoveryBeacon::BEACON_CONTAINS_EID)
327  {
329  stream >> eid;
330 
331  announcement._canonical_eid = dtn::data::EID((const std::string&)eid);
332 
333  IBRCOMMON_LOGGER_DEBUG_TAG("DiscoveryBeacon", 85) << "beacon eid: " << (std::string)eid << IBRCOMMON_LOGGER_ENDL;
334  }
335 
336  if (announcement._flags & DiscoveryBeacon::BEACON_SERVICE_BLOCK)
337  {
338  // get the services
339  dtn::net::DiscoveryBeacon::service_list &services = announcement._services;
340 
341  // read the number of services
342  dtn::data::Number num_services;
343  stream >> num_services;
344 
345  IBRCOMMON_LOGGER_DEBUG_TAG("DiscoveryBeacon", 85) << "beacon services (" << num_services.toString() << "): " << IBRCOMMON_LOGGER_ENDL;
346 
347  // clear the services
348  services.clear();
349 
350  for (unsigned int i = 0; num_services > i; ++i)
351  {
352  // decode the service blocks
353  DiscoveryService service;
354  stream >> service;
355  services.push_back(service);
356 
357  IBRCOMMON_LOGGER_DEBUG_TAG("DiscoveryBeacon", 85) << "\t " << service.getName() << " [" << service.getParameters() << "]" << IBRCOMMON_LOGGER_ENDL;
358  }
359  }
360 
361  if (announcement._flags & DiscoveryBeacon::BEACON_BLOOMFILTER)
362  {
363  // TODO: read the bloomfilter
364  }
365 
366  break;
367  }
368 
370  {
371  uint8_t cl_type;
372  uint8_t interval;
373  uint16_t length;
374  uint32_t inet_addr;
375  uint16_t inet_port;
376  uint16_t eid_len;
377 
378  IBRCOMMON_LOGGER_DEBUG_TAG("DiscoveryBeacon", 60) << "beacon IPDiscovery (DTN2) frame received" << IBRCOMMON_LOGGER_ENDL;
379 
380  stream.read((char*)&cl_type, 1);
381  stream.read((char*)&interval, 1);
382  stream.read((char*)&length, 2);
383  stream.read((char*)&inet_addr, 4);
384  stream.read((char*)&inet_port, 2);
385  stream.read((char*)&eid_len, 2);
386 
387  std::vector<char> eid(eid_len);
388  stream.read(&eid[0], eid.size());
389 
390  announcement._version = DiscoveryBeacon::DTND_IPDISCOVERY;
391  announcement._canonical_eid = dtn::data::EID(std::string(eid.begin(), eid.end()));
392 
393  break;
394  }
395 
396  default:
397  IBRCOMMON_LOGGER_DEBUG_TAG("DiscoveryBeacon", 60) << "unknown beacon received" << IBRCOMMON_LOGGER_ENDL;
398 
399  // Error, throw Exception!
400  throw InvalidProtocolException("The received data does not match the discovery protocol.");
401 
402  break;
403  }
404 
405  return stream;
406  }
407 
408  std::string DiscoveryBeacon::toString() const
409  {
410  stringstream ss;
411  ss << "ANNOUNCE: " << _canonical_eid.getString();
412  return ss.str();
413  }
414  }
415 }