IBR-DTNSuite  0.8
tools/src/dtntracepath.cpp
Go to the documentation of this file.
00001 /*
00002  * dtnping.cpp
00003  *
00004  *  Created on: 24.06.2009
00005  *      Author: morgenro
00006  */
00007 
00008 #include "config.h"
00009 #include <ibrdtn/data/StatusReportBlock.h>
00010 #include "ibrdtn/api/Client.h"
00011 #include "ibrdtn/api/StringBundle.h"
00012 #include "ibrcommon/net/tcpclient.h"
00013 #include "ibrcommon/thread/Mutex.h"
00014 #include "ibrcommon/thread/MutexLock.h"
00015 #include "ibrcommon/TimeMeasurement.h"
00016 
00017 #include <algorithm>
00018 #include <iostream>
00019 #include <sstream>
00020 #include <unistd.h>
00021 
00022 class ReportBundle : public dtn::api::Bundle
00023 {
00024 public:
00025         ReportBundle(const dtn::api::Bundle &apib)
00026          : Bundle(apib) {
00027         }
00028 
00029         virtual ~ReportBundle() {
00030 
00031         }
00032 
00033         const dtn::data::StatusReportBlock& extract()
00034         {
00035                 return _b.getBlock<dtn::data::StatusReportBlock>();
00036         }
00037 };
00038 
00039 class Tracer : public dtn::api::Client
00040 {
00041         public:
00042                 Tracer(dtn::api::Client::COMMUNICATION_MODE mode, ibrcommon::tcpstream &stream)
00043                  : dtn::api::Client("", stream, mode), _stream(stream)
00044                 {
00045                 }
00046 
00047                 virtual ~Tracer()
00048                 {
00049                 }
00050 
00051                 void printReason(char code) {
00052                         switch (code) {
00053                         case dtn::data::StatusReportBlock::LIFETIME_EXPIRED:
00054                                 ::printf("      * lifetime expired\n");
00055                                 break;
00056                         case dtn::data::StatusReportBlock::FORWARDED_OVER_UNIDIRECTIONAL_LINK:
00057                                 ::printf("      * forwarded over unidirectional link\n");
00058                                 break;
00059                         case dtn::data::StatusReportBlock::TRANSMISSION_CANCELED:
00060                                 ::printf("      * transmission canceled\n");
00061                                 break;
00062                         case dtn::data::StatusReportBlock::DEPLETED_STORAGE:
00063                                 ::printf("      * depleted storage\n");
00064                                 break;
00065                         case dtn::data::StatusReportBlock::DESTINATION_ENDPOINT_ID_UNINTELLIGIBLE:
00066                                 ::printf("      * destination endpoint ID is unintelligible\n");
00067                                 break;
00068                         case dtn::data::StatusReportBlock::NO_KNOWN_ROUTE_TO_DESTINATION_FROM_HERE:
00069                                 ::printf("      * no known route to destination from here\n");
00070                                 break;
00071                         case dtn::data::StatusReportBlock::NO_TIMELY_CONTACT_WITH_NEXT_NODE_ON_ROUTE:
00072                                 ::printf("      * no timely contact with next node on route\n");
00073                                 break;
00074                         case dtn::data::StatusReportBlock::BLOCK_UNINTELLIGIBLE:
00075                                 ::printf("      * block unintelligible\n");
00076                                 break;
00077                         default:
00078                                 break;
00079                         }
00080                 }
00081 
00082                 void formattedLog(size_t i, const dtn::api::Bundle &b, const ibrcommon::TimeMeasurement &tm)
00083                 {
00084                         ReportBundle report(b);
00085                         const dtn::data::StatusReportBlock &sr = report.extract();
00086 
00087                         const std::string source = b.getSource().getString();
00088 
00089                         // format time data
00090                         std::stringstream time;
00091                         time << tm;
00092 
00093                         if (sr._status & dtn::data::StatusReportBlock::FORWARDING_OF_BUNDLE) {
00094                                 std::stringstream type;
00095                                 type << "forwarded";
00096                                 ::printf(" %3d: %-48s %-12s %6s\n", (unsigned int)i, source.c_str(), type.str().c_str(), time.str().c_str());
00097                                 printReason(sr._reasoncode);
00098                         }
00099 
00100                         if (sr._status & dtn::data::StatusReportBlock::RECEIPT_OF_BUNDLE) {
00101                                 std::stringstream type;
00102                                 type << "reception";
00103                                 ::printf(" %3d: %-48s %-12s %6s\n", (unsigned int)i, source.c_str(), type.str().c_str(), time.str().c_str());
00104                                 printReason(sr._reasoncode);
00105                         }
00106 
00107                         if (sr._status & dtn::data::StatusReportBlock::DELIVERY_OF_BUNDLE) {
00108                                 std::stringstream type;
00109                                 type << "delivery";
00110                                 ::printf(" %3d: %-48s %-12s %6s\n", (unsigned int)i, source.c_str(), type.str().c_str(), time.str().c_str());
00111                                 printReason(sr._reasoncode);
00112                         }
00113 
00114                         if (sr._status & dtn::data::StatusReportBlock::DELETION_OF_BUNDLE) {
00115                                 std::stringstream type;
00116                                 type << "deletion";
00117                                 ::printf(" %3d: %-48s %-12s %6s\n", (unsigned int)i, source.c_str(), type.str().c_str(), time.str().c_str());
00118                                 printReason(sr._reasoncode);
00119                         }
00120 
00121                         ::fflush(stdout);
00122                 }
00123 
00124                 void tracepath(const dtn::data::EID &destination, size_t timeout, unsigned char options)
00125                 {
00126                         // create a bundle
00127                         dtn::api::StringBundle b(destination);
00128 
00129                         // set lifetime
00130                         b.setLifetime(timeout);
00131 
00132                         // set some stupid payload
00133                         b.append("follow the white rabbit");
00134 
00135                         // request forward and delivery reports
00136                         if (options & 0x01) b.requestForwardedReport();
00137                         if (options & 0x02) b.requestDeliveredReport();
00138                         if (options & 0x04) b.requestReceptionReport();
00139                         if (options & 0x08) b.requestDeletedReport();
00140 
00141                         b.setReportTo( EID("api:me") );
00142 
00143                         ibrcommon::TimeMeasurement tm;
00144 
00145                         std::list<dtn::api::Bundle> bundles;
00146 
00147                         try {
00148                                 size_t i = 0;
00149 
00150                                 // start the timer
00151                                 tm.start();
00152 
00153                                 std::cout << "TRACE TO " << destination.getString() << std::endl;
00154 
00155                                 // send the bundle
00156                                 (*this) << b; (*this).flush();
00157 
00158                                 try {
00159                                         // now receive all incoming bundles
00160                                         while (true)
00161                                         {
00162                                                 dtn::api::Bundle recv = getBundle(timeout);
00163                                                 bundles.push_back(recv);
00164                                                 tm.stop();
00165 
00166                                                 // generate formatted output
00167                                                 i++;
00168                                                 formattedLog(i, recv, tm);
00169                                         }
00170                                 } catch (const std::exception&) {
00171 
00172                                 }
00173 
00174                                 std::cout << std::endl;
00175 
00176 //                              // sort the list
00177 //                              bundles.sort();
00178 //
00179 //                              // print out each hop
00180 //                              for (std::list<dtn::api::Bundle>::iterator iter = bundles.begin(); iter != bundles.end(); iter++)
00181 //                              {
00182 //                                      const dtn::api::Bundle &b = (*iter);
00183 //
00184 //                                      ReportBundle report(b);
00185 //                                      const dtn::data::StatusReportBlock &sr = report.extract();
00186 //
00187 //
00188 //                                      std::cout << "Hop: " << (*iter).getSource().getString() << std::endl;
00189 //
00190 //                                      if (sr._status & dtn::data::StatusReportBlock::FORWARDING_OF_BUNDLE) {
00191 //                                              std::cout << "   bundle forwarded: " << sr._timeof_forwarding.getTimestamp().getValue() << std::endl;
00192 //                                      }
00193 //
00194 //                                      if (sr._status & dtn::data::StatusReportBlock::RECEIPT_OF_BUNDLE) {
00195 //                                              std::cout << "   bundle reception: " << sr._timeof_receipt.getTimestamp().getValue() << std::endl;
00196 //                                      }
00197 //
00198 //                                      if (sr._status & dtn::data::StatusReportBlock::DELIVERY_OF_BUNDLE) {
00199 //                                              std::cout << "   bundle delivery: " << sr._timeof_delivery.getTimestamp().getValue() << std::endl;
00200 //                                      }
00201 //
00202 //                                      if (sr._status & dtn::data::StatusReportBlock::DELETION_OF_BUNDLE) {
00203 //                                              std::cout << "   bundle deletion: " << sr._timeof_deletion.getTimestamp().getValue() << std::endl;
00204 //                                      }
00205 //                              }
00206 
00207                         } catch (const dtn::api::ConnectionException&) {
00208                                 cout << "Disconnected." << endl;
00209                         } catch (const ibrcommon::IOException&) {
00210                                 cout << "Error while receiving a bundle." << endl;
00211                         }
00212                 }
00213 
00214         private:
00215                 ibrcommon::tcpstream &_stream;
00216 };
00217 
00218 void print_help()
00219 {
00220         cout << "-- dtntracepath (IBR-DTN) --" << endl;
00221         cout << "Syntax: dtntracepath [options] <dst>"  << endl;
00222         cout << " <dst>    set the destination eid (e.g. dtn://node/null)" << endl;
00223         cout << "* optional parameters *" << endl;
00224         cout << " -h              display this text" << endl;
00225         cout << " -t <timeout>    time in seconds to wait for reports" << endl;
00226         cout << " -d              request deletion report" << endl;
00227         cout << " -f              request forward report" << endl;
00228         cout << " -r              request reception report" << endl;
00229 }
00230 
00231 int main(int argc, char *argv[])
00232 {
00233         std::string trace_destination = "dtn://local";
00234         // forwarded = 0x01
00235         // delivered = 0x02
00236         // reception = 0x04
00237         // deletion = 0x08
00238         unsigned char report_options = 0x02;
00239 
00240         size_t timeout = 10;
00241         int opt = 0;
00242 
00243         dtn::api::Client::COMMUNICATION_MODE mode = dtn::api::Client::MODE_BIDIRECTIONAL;
00244 
00245         if (argc == 1)
00246         {
00247                 print_help();
00248                 return 0;
00249         }
00250 
00251         while ((opt = getopt(argc, argv, "ht:fdr")) != -1)
00252         {
00253                 switch (opt)
00254                 {
00255                 case 'h':
00256                         print_help();
00257                         return 0;
00258 
00259                 case 't':
00260                         timeout = atoi(optarg);
00261                         break;
00262 
00263                 case 'f':
00264                         report_options |= 0x01;
00265                         break;
00266 
00267                 case 'd':
00268                         report_options |= 0x08;
00269                         break;
00270 
00271                 case 'r':
00272                         report_options |= 0x04;
00273                         break;
00274                 }
00275         }
00276 
00277         // the last parameter is always the destination
00278         trace_destination = argv[argc - 1];
00279 
00280         try {
00281                 // Create a stream to the server using TCP.
00282                 ibrcommon::tcpclient conn("127.0.0.1", 4550);
00283 
00284                 // enable nodelay option
00285                 conn.enableNoDelay();
00286 
00287                 // Initiate a derivated client
00288                 Tracer tracer(mode, conn);
00289 
00290                 // Connect to the server. Actually, this function initiate the
00291                 // stream protocol by starting the thread and sending the contact header.
00292                 tracer.connect();
00293 
00294                 // target address
00295                 tracer.tracepath(trace_destination, timeout, report_options);
00296 
00297                 // Shutdown the client connection.
00298                 tracer.close();
00299                 conn.close();
00300 
00301         } catch (const ibrcommon::tcpclient::SocketException&) {
00302                 std::cerr << "Can not connect to the daemon. Does it run?" << std::endl;
00303                 return -1;
00304         } catch (const std::exception &e) {
00305                 std::cerr << "Unexcepted error: " << e.what() << std::endl;
00306                 return -1;
00307         }
00308 
00309         return 0;
00310 }