Go to the documentation of this file.00001
00002
00003
00004
00005
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
00063 dtn::api::StringBundle b(destination);
00064
00065
00066 b.setLifetime(lifetime);
00067
00068
00069 b.append(string((char *)(&seq),4));
00070 size-=4;
00071
00072
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
00090 (*this) << b;
00091
00092
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
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
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
00255 ping_destination = argv[argc - 1];
00256
00257
00258 _addr = EID(ping_destination);
00259
00260 ibrcommon::TimeMeasurement tm;
00261
00262
00263 try {
00264
00265 ibrcommon::tcpclient conn;
00266
00267
00268 if (unixdomain.exists())
00269 {
00270
00271 conn.open(unixdomain);
00272 }
00273 else
00274 {
00275
00276 conn.open("127.0.0.1", 4550);
00277
00278
00279 conn.enableNoDelay();
00280 }
00281
00282
00283 EchoClient client(mode, ping_source, conn);
00284
00285
00286
00287 client.connect();
00288
00289 std::cout << "ECHO " << _addr.getString() << " " << ping_size << " bytes of data." << std::endl;
00290
00291
00292 _runtime.start();
00293
00294 try {
00295 for (unsigned int i = 0; (i < count) || nonstop; i++)
00296 {
00297
00298 tm.start();
00299
00300
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
00310 tm.stop();
00311
00312 size_t reply_seq = 0;
00313 size_t payload_size = 0;
00314
00315
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
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 }