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(app, stream, mode), _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, bool encryption = false, bool sign = false)
00058 {
00059 lastdestination=destination.getString();
00060 seq++;
00061
00062
00063 dtn::api::StringBundle b(destination);
00064
00065
00066 if (encryption) b.requestEncryption();
00067
00068
00069 if (sign) b.requestSigned();
00070
00071
00072 b.setLifetime(lifetime);
00073
00074
00075 b.append(string((char *)(&seq),4));
00076 size-=4;
00077
00078
00079 char pattern[CREATE_CHUNK_SIZE];
00080 for (size_t i = 0; i < sizeof(pattern); i++)
00081 {
00082 pattern[i] = '0';
00083 pattern[i] += i % 10;
00084 }
00085 string chunk=string(pattern,CREATE_CHUNK_SIZE);
00086
00087 while (size > CREATE_CHUNK_SIZE) {
00088 b.append(chunk);
00089 size-=CREATE_CHUNK_SIZE;
00090 }
00091 b.append(chunk.substr(0,size));
00092
00093
00094
00095
00096 (*this) << b;
00097
00098
00099 flush();
00100
00101 }
00102
00103 void checkReply(dtn::api::Bundle &bundle) {
00104 size_t reply_seq = 0;
00105 ibrcommon::BLOB::Reference blob = bundle.getData();
00106 blob.iostream()->read((char *)(&reply_seq),4 );
00107
00108 if (reply_seq != seq) {
00109 std::stringstream ss;
00110 ss << "sequence number mismatch, awaited " << seq << ", got " << reply_seq;
00111 throw ss.str();
00112 }
00113 if (bundle.getSource().getString() != lastdestination) {
00114 throw std::string("ignoring bundle from source " + bundle.getSource().getString() + " awaited " + lastdestination);
00115 }
00116 }
00117
00118 private:
00119 ibrcommon::tcpstream &_stream;
00120 uint32_t seq;
00121 string lastdestination;
00122 };
00123
00124
00125
00126 void print_help()
00127 {
00128 cout << "-- dtnping (IBR-DTN) --" << endl;
00129 cout << "Syntax: dtnping [options] <dst>" << endl;
00130 cout << " <dst> set the destination eid (e.g. dtn://node/echo)" << endl;
00131 cout << "* optional parameters *" << endl;
00132 cout << " -h|--help display this text" << endl;
00133 cout << " --src <name> set the source application name (e.g. echo-client)" << endl;
00134 cout << " --nowait do not wait for a reply" << endl;
00135 cout << " --abortfail Abort after first packetloss" << endl;
00136 cout << " --size the size of the payload" << endl;
00137 cout << " --count X send X echo in a row" << endl;
00138 cout << " --lifetime <seconds> set the lifetime of outgoing bundles; default: 30" << endl;
00139 cout << " --encrypt request encryption on the bundle layer" << endl;
00140 cout << " --sign request signature on the bundle layer" << endl;
00141 cout << " -U <socket> use UNIX domain sockets" << endl;
00142 }
00143
00144 size_t _received = 0, _transmitted = 0;
00145 float _min = 0.0, _max = 0.0, _avg = 0.0;
00146 ibrcommon::TimeMeasurement _runtime;
00147
00148 EID _addr;
00149 bool __exit = false;
00150
00151 void print_summary()
00152 {
00153 _runtime.stop();
00154
00155 float loss = 0; if (_transmitted > 0) loss = ((_transmitted - _received) / _transmitted) * 100.0;
00156 float avg_value = 0; if (_received > 0) avg_value = (_avg/_received);
00157
00158 std::cout << std::endl << "--- " << _addr.getString() << " echo statistics --- " << std::endl;
00159 std::cout << _transmitted << " bundles transmitted, " << _received << " received, " << loss << "% bundle loss, time " << _runtime << std::endl;
00160 std::cout << "rtt min/avg/max = ";
00161 ibrcommon::TimeMeasurement::format(std::cout, _min) << "/";
00162 ibrcommon::TimeMeasurement::format(std::cout, avg_value) << "/";
00163 ibrcommon::TimeMeasurement::format(std::cout, _max) << " ms" << std::endl;
00164 }
00165
00166 void term(int signal)
00167 {
00168 if (signal >= 1)
00169 {
00170 if (!__exit)
00171 {
00172 print_summary();
00173 __exit = true;
00174 }
00175 exit(0);
00176 }
00177 }
00178
00179 int main(int argc, char *argv[])
00180 {
00181
00182 signal(SIGINT, term);
00183 signal(SIGTERM, term);
00184
00185 string ping_destination = "dtn://local/echo";
00186 string ping_source = "echo-client";
00187 int ping_size = 64;
00188 unsigned int lifetime = 30;
00189 bool wait_for_reply = true;
00190 bool stop_after_first_fail = false;
00191 bool nonstop = true;
00192 size_t count = 0;
00193 dtn::api::Client::COMMUNICATION_MODE mode = dtn::api::Client::MODE_BIDIRECTIONAL;
00194 ibrcommon::File unixdomain;
00195 bool bundle_encryption = false;
00196 bool bundle_signed = false;
00197
00198 if (argc == 1)
00199 {
00200 print_help();
00201 return 0;
00202 }
00203
00204 for (int i = 1; i < argc; i++)
00205 {
00206 string arg = argv[i];
00207
00208
00209 if ((arg == "-h") || (arg == "--help"))
00210 {
00211 print_help();
00212 return 0;
00213 }
00214
00215 else if (arg == "--encrypt")
00216 {
00217 bundle_encryption = true;
00218 }
00219
00220 else if (arg == "--sign")
00221 {
00222 bundle_signed = true;
00223 }
00224
00225 else if (arg == "--nowait")
00226 {
00227 mode = dtn::api::Client::MODE_SENDONLY;
00228 wait_for_reply = false;
00229 }
00230
00231 else if ( arg == "--abortfail") {
00232 stop_after_first_fail=true;
00233 }
00234
00235 else if (arg == "--src" && argc > i)
00236 {
00237 ping_source = argv[i + 1];
00238 i++;
00239 }
00240
00241 else if (arg == "--size" && argc > i)
00242 {
00243 stringstream str_size;
00244 str_size.str( argv[i + 1] );
00245 str_size >> ping_size;
00246 i++;
00247 }
00248
00249 else if (arg == "--count" && argc > i)
00250 {
00251 stringstream str_count;
00252 str_count.str( argv[i + 1] );
00253 str_count >> count;
00254 i++;
00255 nonstop = false;
00256 }
00257
00258 else if (arg == "--lifetime" && argc > i)
00259 {
00260 stringstream data; data << argv[i + 1];
00261 data >> lifetime;
00262 i++;
00263 }
00264 else if (arg == "-U" && argc > i)
00265 {
00266 if (++i > argc)
00267 {
00268 std::cout << "argument missing!" << std::endl;
00269 return -1;
00270 }
00271
00272 unixdomain = ibrcommon::File(argv[i]);
00273 }
00274 }
00275
00276
00277 ping_destination = argv[argc - 1];
00278
00279
00280 _addr = EID(ping_destination);
00281
00282 ibrcommon::TimeMeasurement tm;
00283
00284
00285 try {
00286
00287 ibrcommon::tcpclient conn;
00288
00289
00290 if (unixdomain.exists())
00291 {
00292
00293 conn.open(unixdomain);
00294 }
00295 else
00296 {
00297
00298 conn.open("127.0.0.1", 4550);
00299
00300
00301 conn.enableNoDelay();
00302 }
00303
00304
00305 EchoClient client(mode, ping_source, conn);
00306
00307
00308
00309 client.connect();
00310
00311 std::cout << "ECHO " << _addr.getString() << " " << ping_size << " bytes of data." << std::endl;
00312
00313
00314 _runtime.start();
00315
00316 try {
00317 for (unsigned int i = 0; (i < count) || nonstop; i++)
00318 {
00319
00320 tm.start();
00321
00322
00323 client.echo( _addr, ping_size, lifetime, bundle_encryption, bundle_signed );
00324 _transmitted++;
00325
00326 if (wait_for_reply)
00327 {
00328 try {
00329 dtn::api::Bundle response = client.waitForReply(2*lifetime);
00330
00331
00332 tm.stop();
00333
00334 size_t reply_seq = 0;
00335 size_t payload_size = 0;
00336
00337
00338 _avg += tm.getMilliseconds();
00339 if ((_min > tm.getMilliseconds()) || _min == 0) _min = tm.getMilliseconds();
00340 if ((_max < tm.getMilliseconds()) || _max == 0) _max = tm.getMilliseconds();
00341
00342 {
00343 ibrcommon::BLOB::Reference blob = response.getData();
00344 blob.iostream()->read((char *)(&reply_seq),4 );
00345 payload_size = blob.iostream().size();
00346 }
00347
00348 std::cout << payload_size << " bytes from " << response.getSource().getString() << ": seq=" << reply_seq << " ttl=" << response.getLifetime() << " time=" << tm << std::endl;
00349 _received++;
00350 } catch (const ibrcommon::Exception &ex) {
00351 std::cerr << ex.what() << std::endl;
00352
00353 if (stop_after_first_fail)
00354 {
00355 std::cout << "No response, aborting." << std::endl;
00356 break;
00357 }
00358 }
00359 }
00360
00361 if (nonstop) ::sleep(1);
00362 }
00363 } catch (const dtn::api::ConnectionException&) {
00364 std::cerr << "Disconnected." << std::endl;
00365 } catch (const ibrcommon::IOException&) {
00366 std::cerr << "Error while receiving a bundle." << std::endl;
00367 }
00368
00369
00370 client.close();
00371 conn.close();
00372
00373 } catch (const ibrcommon::tcpclient::SocketException&) {
00374 std::cerr << "Can not connect to the daemon. Does it run?" << std::endl;
00375 return -1;
00376 } catch (...) {
00377
00378 }
00379
00380 print_summary();
00381
00382 return 0;
00383 }