• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

tools/src/dtnping.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/api/Client.h"
00010 #include "ibrdtn/api/StringBundle.h"
00011 #include "ibrcommon/net/tcpclient.h"
00012 #include "ibrcommon/thread/Mutex.h"
00013 #include "ibrcommon/thread/MutexLock.h"
00014 #include "ibrcommon/TimeMeasurement.h"
00015 
00016 #include <iostream>
00017 #include <csignal>
00018 #include <stdint.h>
00019 
00020 #define CREATE_CHUNK_SIZE 2048
00021 
00022 class EchoClient : public dtn::api::Client
00023 {
00024         public:
00025                 EchoClient(dtn::api::Client::COMMUNICATION_MODE mode, string app,  ibrcommon::tcpstream &stream)
00026                  : dtn::api::Client(mode, app, stream), _stream(stream)
00027                 {
00028                         seq=0;
00029                 }
00030 
00031                 virtual ~EchoClient()
00032                 {
00033                 }
00034 
00035                 const dtn::api::Bundle waitForReply(const int timeout)
00036                 {
00037                         double wait=(timeout*1000);
00038                         ibrcommon::TimeMeasurement tm;
00039                         while ( wait > 0)
00040                         {
00041                                 try {
00042                                         tm.start();
00043                                         dtn::api::Bundle b = this->getBundle((int)(wait/1000));
00044                                         tm.stop();
00045                                         checkReply(b);
00046                                         return b;
00047                                 } catch (const ibrcommon::QueueUnblockedException&) {
00048                                         throw ibrcommon::Exception("timeout reached");
00049                                 } catch (const std::string &errmsg) {
00050                                         std::cerr << errmsg << std::endl;
00051                                 }
00052                                 wait=wait-tm.getMilliseconds();
00053                         }
00054                         throw ibrcommon::Exception("timeout is set to zero");
00055                 }
00056 
00057                 void echo(EID destination, int size, int lifetime)
00058                 {
00059                         lastdestination=destination.getString();
00060                         seq++;
00061                         
00062                         // create a bundle
00063                         dtn::api::StringBundle b(destination);
00064 
00065                         // set lifetime
00066                         b.setLifetime(lifetime);
00067                         
00068                         //Add magic seqnr. Hmm, how to to do this without string?
00069                         b.append(string((char *)(&seq),4));
00070                         size-=4;
00071                         
00072                         // create testing pattern, chunkwise to ocnserve memory
00073                         char pattern[CREATE_CHUNK_SIZE];
00074                         for (size_t i = 0; i < sizeof(pattern); i++)
00075                         {
00076                                 pattern[i] = '0';
00077                                 pattern[i] += i % 10;
00078                         }
00079                         string chunk=string(pattern,CREATE_CHUNK_SIZE);
00080 
00081                         while (size > CREATE_CHUNK_SIZE) {
00082                                 b.append(chunk);
00083                                 size-=CREATE_CHUNK_SIZE;
00084                         }
00085                         b.append(chunk.substr(0,size));
00086                         
00087                         
00088 
00089                         // send the bundle
00090                         (*this) << b;
00091 
00092                         // ... flush out
00093                         flush();
00094                         
00095                 }
00096                 
00097                 void checkReply(dtn::api::Bundle &bundle) {
00098                         size_t reply_seq = 0;
00099                         ibrcommon::BLOB::Reference blob = bundle.getData();
00100                         ibrcommon::MutexLock l(blob);
00101                         (*blob).read((char *)(&reply_seq),4 );
00102 
00103                         if (reply_seq != seq) {
00104                                 std::stringstream ss;
00105                                 ss << "sequence number mismatch, awaited " << seq << ", got " << reply_seq;
00106                                 throw ss.str();
00107                         }
00108                         if (bundle.getSource().getString() != lastdestination) {
00109                                 throw std::string("ignoring bundle from source " + bundle.getSource().getString() + " awaited " + lastdestination);
00110                         }
00111                 }
00112 
00113         private:
00114                 ibrcommon::tcpstream &_stream;
00115                 uint32_t seq;
00116                 string lastdestination;
00117 };
00118 
00119 
00120         
00121 void print_help()
00122 {
00123         cout << "-- dtnping (IBR-DTN) --" << endl;
00124         cout << "Syntax: dtnping [options] <dst>"  << endl;
00125         cout << " <dst>    set the destination eid (e.g. dtn://node/echo)" << endl;
00126         cout << "* optional parameters *" << endl;
00127         cout << " -h|--help       display this text" << endl;
00128         cout << " --src <name>    set the source application name (e.g. echo-client)" << endl;
00129         cout << " --nowait        do not wait for a reply" << endl;
00130         cout << " --abortfail     Abort after first packetloss" << endl;
00131         cout << " --size          the size of the payload" << endl;
00132         cout << " --count X       send X echo in a row" << endl;
00133         cout << " --lifetime <seconds> set the lifetime of outgoing bundles; default: 30" << endl;
00134         cout << " -U <socket>     use UNIX domain sockets" << endl;
00135 }
00136 
00137 size_t _received = 0, _transmitted = 0;
00138 float _min = 0.0, _max = 0.0, _avg = 0.0;
00139 ibrcommon::TimeMeasurement _runtime;
00140 
00141 EID _addr;
00142 bool __exit = false;
00143 
00144 void print_summary()
00145 {
00146         _runtime.stop();
00147 
00148         float loss = 0; if (_transmitted > 0) loss = ((_transmitted - _received) / _transmitted) * 100.0;
00149         float avg_value = 0; if (_received > 0) avg_value = (_avg/_received);
00150 
00151         std::cout << std::endl << "--- " << _addr.getString() << " echo statistics --- " << std::endl;
00152         std::cout << _transmitted << " bundles transmitted, " << _received << " received, " << loss << "% bundle loss, time " << _runtime << std::endl;
00153         std::cout << "rtt min/avg/max = " << _min << "/" << avg_value << "/" << _max << " ms" << std::endl;
00154 }
00155 
00156 void term(int signal)
00157 {
00158         if (signal >= 1)
00159         {
00160                 if (!__exit)
00161                 {
00162                         print_summary();
00163                         __exit = true;
00164                 }
00165                 exit(0);
00166         }
00167 }
00168 
00169 int main(int argc, char *argv[])
00170 {
00171         // catch process signals
00172         signal(SIGINT, term);
00173         signal(SIGTERM, term);
00174 
00175         string ping_destination = "dtn://local/echo";
00176         string ping_source = "echo-client";
00177         int ping_size = 64;
00178         unsigned int lifetime = 30;
00179         bool wait_for_reply = true;
00180         bool stop_after_first_fail = false;
00181         bool nonstop = true;
00182         size_t count = 0;
00183         dtn::api::Client::COMMUNICATION_MODE mode = dtn::api::Client::MODE_BIDIRECTIONAL;
00184         ibrcommon::File unixdomain;
00185 
00186         if (argc == 1)
00187         {
00188                 print_help();
00189                 return 0;
00190         }
00191 
00192         for (int i = 1; i < argc; i++)
00193         {
00194                 string arg = argv[i];
00195 
00196                 // print help if requested
00197                 if ((arg == "-h") || (arg == "--help"))
00198                 {
00199                         print_help();
00200                         return 0;
00201                 }
00202 
00203                 else if (arg == "--nowait")
00204                 {
00205                         mode = dtn::api::Client::MODE_SENDONLY;
00206                         wait_for_reply = false;
00207                 }
00208                 
00209                 else if ( arg == "--abortfail") {
00210                         stop_after_first_fail=true;
00211                 }
00212 
00213                 else if (arg == "--src" && argc > i)
00214                 {
00215                         ping_source = argv[i + 1];
00216                         i++;
00217                 }
00218 
00219                 else if (arg == "--size" && argc > i)
00220                 {
00221                         stringstream str_size;
00222                         str_size.str( argv[i + 1] );
00223                         str_size >> ping_size;
00224                         i++;
00225                 }
00226 
00227                 else if (arg == "--count" && argc > i)
00228                 {
00229                         stringstream str_count;
00230                         str_count.str( argv[i + 1] );
00231                         str_count >> count;
00232                         i++;
00233                         nonstop = false;
00234                 }
00235 
00236                 else if (arg == "--lifetime" && argc > i)
00237                 {
00238                         stringstream data; data << argv[i + 1];
00239                         data >> lifetime;
00240                         i++;
00241                 }
00242                 else if (arg == "-U" && argc > i)
00243                 {
00244                         if (++i > argc)
00245                         {
00246                                         std::cout << "argument missing!" << std::endl;
00247                                         return -1;
00248                         }
00249 
00250                         unixdomain = ibrcommon::File(argv[i]);
00251                 }
00252         }
00253 
00254         // the last parameter is always the destination
00255         ping_destination = argv[argc - 1];
00256 
00257         // target address
00258         _addr = EID(ping_destination);
00259 
00260         ibrcommon::TimeMeasurement tm;
00261         
00262         
00263         try {
00264                 // Create a stream to the server using TCP.
00265                 ibrcommon::tcpclient conn;
00266 
00267                 // check if the unixdomain socket exists
00268                 if (unixdomain.exists())
00269                 {
00270                         // connect to the unix domain socket
00271                         conn.open(unixdomain);
00272                 }
00273                 else
00274                 {
00275                         // connect to the standard local api port
00276                         conn.open("127.0.0.1", 4550);
00277 
00278                         // enable nodelay option
00279                         conn.enableNoDelay();
00280                 }
00281 
00282                 // Initiate a derivated client
00283                 EchoClient client(mode, ping_source, conn);
00284 
00285                 // Connect to the server. Actually, this function initiate the
00286                 // stream protocol by starting the thread and sending the contact header.
00287                 client.connect();
00288 
00289                 std::cout << "ECHO " << _addr.getString() << " " << ping_size << " bytes of data." << std::endl;
00290 
00291                 // measure runtime
00292                 _runtime.start();
00293 
00294                 try {
00295                         for (unsigned int i = 0; (i < count) || nonstop; i++)
00296                         {
00297                                 // set sending time
00298                                 tm.start();
00299 
00300                                 // Call out a ECHO
00301                                 client.echo( _addr, ping_size, lifetime );
00302                                 _transmitted++;
00303                         
00304                                 if (wait_for_reply)
00305                                 {
00306                                         try {
00307                                                 dtn::api::Bundle response = client.waitForReply(2*lifetime);
00308 
00309                                                 // print out measurement result
00310                                                 tm.stop();
00311 
00312                                                 size_t reply_seq = 0;
00313                                                 size_t payload_size = 0;
00314 
00315                                                 // check for min/max/avg
00316                                                 _avg += tm.getMilliseconds();
00317                                                 if ((_min > tm.getMilliseconds()) || _min == 0) _min = tm.getMilliseconds();
00318                                                 if ((_max < tm.getMilliseconds()) || _max == 0) _max = tm.getMilliseconds();
00319 
00320                                                 {
00321                                                         ibrcommon::BLOB::Reference blob = response.getData();
00322                                                         ibrcommon::MutexLock l(blob);
00323                                                         (*blob).read((char *)(&reply_seq),4 );
00324                                                         payload_size = blob.getSize();
00325                                                 }
00326 
00327                                                 std::cout << payload_size << " bytes from " << response.getSource().getString() << ": seq=" << reply_seq << " ttl=" << response.getLifetime() << " time=" << tm << std::endl;
00328                                                 _received++;
00329                                         } catch (const ibrcommon::Exception &ex) {
00330                                                 std::cerr << ex.what() << std::endl;
00331 
00332                                                 if (stop_after_first_fail)
00333                                                 {
00334                                                         std::cout << "No response, aborting." << std::endl;
00335                                                         break;
00336                                                 }
00337                                         }
00338                                 }
00339 
00340                                 if (nonstop) ::sleep(1);
00341                         }
00342                 } catch (dtn::api::ConnectionException ex) {
00343                         std::cerr << "Disconnected." << std::endl;
00344                 } catch (ibrcommon::IOException ex) {
00345                         std::cerr << "Error while receiving a bundle." << std::endl;
00346                 }
00347 
00348                 // Shutdown the client connection.
00349                 client.close();
00350                 conn.close();
00351 
00352         } catch (ibrcommon::tcpclient::SocketException ex) {
00353                 std::cerr << "Can not connect to the daemon. Does it run?" << std::endl;
00354                 return -1;
00355         } catch (...) {
00356 
00357         }
00358 
00359         print_summary();
00360 
00361         return 0;
00362 }

Generated on Thu Nov 11 2010 09:49:47 for IBR-DTNSuite by  doxygen 1.7.1