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