IBR-DTNSuite
0.8
|
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 }