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