IBR-DTNSuite  0.12
dtntracepath.cpp
Go to the documentation of this file.
1 /*
2  * dtnping.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"
25 #include "ibrdtn/api/Client.h"
26 #include <ibrcommon/net/socket.h>
28 #include "ibrcommon/thread/Mutex.h"
31 
32 #include <algorithm>
33 #include <iostream>
34 #include <sstream>
35 #include <unistd.h>
36 
37 class ProbeBundle : public dtn::data::Bundle
38 {
39 public:
40  ProbeBundle(const dtn::data::EID &d, bool tracking, bool group)
41  {
42  destination = d;
43  set(DESTINATION_IS_SINGLETON, !group);
44 
45  if (tracking) {
46  push_back<dtn::data::TrackingBlock>();
47  }
48  }
49 
50  virtual ~ProbeBundle()
51  {
52  }
53 };
54 
55 class TrackingBundle : public dtn::data::Bundle
56 {
57 public:
58  TrackingBundle(const dtn::data::Bundle &apib)
59  : dtn::data::Bundle(apib)
60  {
61  }
62 
63  virtual ~TrackingBundle() {
64  }
65 
66  bool isAdmRecord() {
68  }
69 
70  dtn::data::StatusReportBlock getStatusReport() const {
72  const dtn::data::PayloadBlock &payload = find<dtn::data::PayloadBlock>();
73  srb.read(payload);
74  return srb;
75  }
76 
77  const dtn::data::TrackingBlock& getTrackingBlock() const {
78  return find<dtn::data::TrackingBlock>();
79  }
80 };
81 
82 class Tracer : public dtn::api::Client
83 {
84  public:
86  : dtn::api::Client("", stream, mode), _stream(stream)
87  {
88  }
89 
90  virtual ~Tracer()
91  {
92  }
93 
94  void printReason(char code) {
95  switch (code) {
97  ::printf(" * lifetime expired\n");
98  break;
100  ::printf(" * forwarded over unidirectional link\n");
101  break;
103  ::printf(" * transmission canceled\n");
104  break;
106  ::printf(" * depleted storage\n");
107  break;
109  ::printf(" * destination endpoint ID is unintelligible\n");
110  break;
112  ::printf(" * no known route to destination from here\n");
113  break;
115  ::printf(" * no timely contact with next node on route\n");
116  break;
118  ::printf(" * block unintelligible\n");
119  break;
120  default:
121  break;
122  }
123  }
124 
125  void formattedLog(size_t i, const dtn::data::Bundle &b, const ibrcommon::TimeMeasurement &tm)
126  {
127  TrackingBundle tb(b);
128 
129  const std::string source = b.source.getString();
130 
131  // format time data
132  std::stringstream time;
133  time << tm;
134 
135  if (tb.isAdmRecord()) {
136  dtn::data::StatusReportBlock sr = tb.getStatusReport();
137 
139  std::stringstream type;
140  type << "forwarded";
141  ::printf(" %3d: %-48s %-12s %6s\n", (unsigned int)i, source.c_str(), type.str().c_str(), time.str().c_str());
142  printReason(sr.reasoncode);
143  }
144 
146  std::stringstream type;
147  type << "reception";
148  ::printf(" %3d: %-48s %-12s %6s\n", (unsigned int)i, source.c_str(), type.str().c_str(), time.str().c_str());
149  printReason(sr.reasoncode);
150  }
151 
153  std::stringstream type;
154  type << "delivery";
155  ::printf(" %3d: %-48s %-12s %6s\n", (unsigned int)i, source.c_str(), type.str().c_str(), time.str().c_str());
156  printReason(sr.reasoncode);
157  }
158 
160  std::stringstream type;
161  type << "deletion";
162  ::printf(" %3d: %-48s %-12s %6s\n", (unsigned int)i, source.c_str(), type.str().c_str(), time.str().c_str());
163  printReason(sr.reasoncode);
164  }
165  } else {
166  std::stringstream type;
167  type << "ECHO";
168 
169  ::printf(" %3d: %-48s %-12s %6s\n", (unsigned int)i, source.c_str(), type.str().c_str(), time.str().c_str());
170 
171  try {
172  const dtn::data::TrackingBlock &track_block = tb.getTrackingBlock();
173  const dtn::data::TrackingBlock::tracking_list &list = track_block.getTrack();
174 
175  for (dtn::data::TrackingBlock::tracking_list::const_iterator iter = list.begin(); iter != list.end(); ++iter)
176  {
177  const dtn::data::TrackingBlock::TrackingEntry &entry = (*iter);
178  ::printf(" # %s\n", entry.endpoint.getString().c_str());
179  }
180 
182  }
183 
184  ::fflush(stdout);
185  }
186 
187  void tracepath(const dtn::data::EID &destination, bool group, size_t timeout, unsigned char options, bool tracking)
188  {
189  // create a bundle
190  ProbeBundle b(destination, tracking, group);
191 
192  // set lifetime
193  b.lifetime = timeout;
194 
195  // set some stupid payload
197  b.push_back(ref);
198  (*ref.iostream()) << "follow the white rabbit";
199 
200  // request forward and delivery reports
205 
206  b.reportto = dtn::data::EID("api:me");
207 
209 
210  std::list<dtn::data::Bundle> bundles;
211 
212  try {
213  size_t i = 0;
214 
215  // start the timer
216  tm.start();
217 
218  std::cout << "TRACE TO " << destination.getString() << std::endl;
219 
220  // send the bundle
221  (*this) << b; (*this).flush();
222 
223  try {
224  // now receive all incoming bundles
225  while (true)
226  {
227  dtn::data::Bundle recv = getBundle(timeout);
228  bundles.push_back(recv);
229  tm.stop();
230 
231  // generate formatted output
232  i++;
233  formattedLog(i, recv, tm);
234  }
235  } catch (const std::exception &e) {
236  // error or timeout
237  }
238 
239  std::cout << std::endl;
240  } catch (const dtn::api::ConnectionException&) {
241  cout << "Disconnected." << endl;
242  } catch (const ibrcommon::IOException&) {
243  cout << "Error while receiving a bundle." << endl;
244  }
245  }
246 
247  private:
248  ibrcommon::socketstream &_stream;
249 };
250 
252 {
253  cout << "-- dtntracepath (IBR-DTN) --" << endl;
254  cout << "Syntax: dtntracepath [options] <dst>" << endl;
255  cout << " <dst> set the destination eid (e.g. dtn://node/null)" << endl << endl;
256  cout << "* optional parameters *" << endl;
257  cout << " -h Display this text" << endl;
258  cout << " -t <seconds> Time to wait for reports (default: 10)" << endl;
259  cout << " -d Request deletion report" << endl;
260  cout << " -f Request forward report" << endl;
261  cout << " -r Request reception report" << endl;
262  cout << " -p Add tracking block to record the bundle path" << endl;
263  cout << " -g Destination is a group endpoint" << endl;
264 }
265 
266 int main(int argc, char *argv[])
267 {
268  std::string trace_destination = "dtn://local";
269  // forwarded = 0x01
270  // delivered = 0x02
271  // reception = 0x04
272  // deletion = 0x08
273  unsigned char report_options = 0x02;
274  bool tracking = false;
275  bool group = false;
276 
277  size_t timeout = 10;
278  int opt = 0;
279 
281 
282  if (argc == 1)
283  {
284  print_help();
285  return 0;
286  }
287 
288  while ((opt = getopt(argc, argv, "ht:fdrpg")) != -1)
289  {
290  switch (opt)
291  {
292  case 'h':
293  print_help();
294  return 0;
295 
296  case 't':
297  timeout = atoi(optarg);
298  break;
299 
300  case 'f':
301  report_options |= 0x01;
302  break;
303 
304  case 'd':
305  report_options |= 0x08;
306  break;
307 
308  case 'r':
309  report_options |= 0x04;
310  break;
311 
312  case 'p':
313  tracking = true;
314  break;
315 
316  case 'g':
317  group = true;
318  break;
319  }
320  }
321 
322  // the last parameter is always the destination
323  trace_destination = argv[argc - 1];
324 
325  try {
326  // Create a stream to the server using TCP.
327  ibrcommon::vaddress addr("localhost", 4550);
329 
330  // Initiate a derivated client
331  Tracer tracer(mode, conn);
332 
333  // Connect to the server. Actually, this function initiate the
334  // stream protocol by starting the thread and sending the contact header.
335  tracer.connect();
336 
337  // target address
338  tracer.tracepath(trace_destination, group, timeout, report_options, tracking);
339 
340  // Shutdown the client connection.
341  tracer.close();
342  conn.close();
343 
344  } catch (const ibrcommon::socket_exception&) {
345  std::cerr << "Can not connect to the daemon. Does it run?" << std::endl;
346  return -1;
347  } catch (const std::exception &e) {
348  std::cerr << "Unexcepted error: " << e.what() << std::endl;
349  return -1;
350  }
351 
352  return 0;
353 }