00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 # include <dtn-config.h>
00019 #endif
00020
00021 #include <stdio.h>
00022 #include <unistd.h>
00023 #include <errno.h>
00024 #include <strings.h>
00025 #include <string.h>
00026 #include <stdlib.h>
00027 #include <sys/time.h>
00028
00029 #include "dtnping.h"
00030 #include "dtn_api.h"
00031
00032 const char *progname;
00033
00034 void
00035 usage()
00036 {
00037 fprintf(stderr, "usage: %s [-c count] [-i interval] [-e expiration] eid\n",
00038 progname);
00039 exit(1);
00040 }
00041
00042 void doOptions(int argc, const char **argv);
00043
00044 int interval = 1;
00045 int count = 0;
00046 int reply_count = 0;
00047 int expiration = 30;
00048 char dest_eid_str[DTN_MAX_ENDPOINT_ID] = "";
00049 char source_eid_str[DTN_MAX_ENDPOINT_ID] = "";
00050 char replyto_eid_str[DTN_MAX_ENDPOINT_ID] = "";
00051
00052 #define MAX_PINGS_IN_FLIGHT 1024
00053
00054 int
00055 main(int argc, const char** argv)
00056 {
00057 int i;
00058 int ret;
00059 dtn_handle_t handle;
00060 dtn_endpoint_id_t source_eid;
00061 dtn_reg_info_t reginfo;
00062 dtn_reg_id_t regid;
00063 dtn_bundle_spec_t ping_spec;
00064 dtn_bundle_spec_t reply_spec;
00065 dtn_bundle_payload_t ping_payload;
00066 ping_payload_t payload_contents;
00067 ping_payload_t recv_contents;
00068 dtn_bundle_payload_t reply_payload;
00069 dtn_bundle_status_report_t* sr_data;
00070 dtn_bundle_id_t bundle_id;
00071 int debug = 1;
00072 char demux[64];
00073 int dest_len = 0;
00074 struct timeval send_times[MAX_PINGS_IN_FLIGHT];
00075 dtn_timestamp_t creation_times[MAX_PINGS_IN_FLIGHT];
00076 struct timeval now, recv_start, recv_end;
00077 u_int32_t nonce;
00078 u_int32_t seqno = 0;
00079 int timeout;
00080
00081
00082
00083 setvbuf(stdout, (char *)NULL, _IOLBF, 0);
00084
00085 doOptions(argc, argv);
00086
00087 memset(&ping_spec, 0, sizeof(ping_spec));
00088
00089 gettimeofday(&now, 0);
00090 srand(now.tv_sec);
00091 nonce = rand();
00092
00093
00094 int err = dtn_open(&handle);
00095 if (err != DTN_SUCCESS) {
00096 fprintf(stderr, "fatal error opening dtn handle: %s\n",
00097 dtn_strerror(err));
00098 exit(1);
00099 }
00100
00101
00102
00103 if (strcmp(dest_eid_str, "localhost") == 0) {
00104 dtn_build_local_eid(handle, &ping_spec.dest, "ping");
00105
00106 } else {
00107 if (dtn_parse_eid_string(&ping_spec.dest, dest_eid_str)) {
00108 fprintf(stderr, "invalid destination eid string '%s'\n",
00109 dest_eid_str);
00110 exit(1);
00111 }
00112 }
00113
00114 dest_len = strlen(ping_spec.dest.uri);
00115 if ((dest_len < 4) ||
00116 (strcmp(ping_spec.dest.uri + dest_len - 4, "ping") != 0))
00117 {
00118 fprintf(stderr, "\nWARNING: ping destination does not end in \"ping\"\n\n");
00119 }
00120
00121
00122
00123
00124 snprintf(demux, sizeof(demux), "/ping.%d", getpid());
00125 if (source_eid_str[0] != '\0') {
00126 if (dtn_parse_eid_string(&source_eid, source_eid_str)) {
00127 fprintf(stderr, "invalid source eid string '%s'\n",
00128 source_eid_str);
00129 exit(1);
00130 }
00131 } else {
00132 dtn_build_local_eid(handle, &source_eid, demux);
00133 }
00134
00135
00136 if (debug) printf("source_eid [%s]\n", source_eid.uri);
00137 dtn_copy_eid(&ping_spec.source, &source_eid);
00138 dtn_copy_eid(&ping_spec.replyto, &source_eid);
00139
00140
00141 memset(®info, 0, sizeof(reginfo));
00142 dtn_copy_eid(®info.endpoint, &source_eid);
00143 reginfo.flags = DTN_REG_DEFER;
00144 reginfo.regid = DTN_REGID_NONE;
00145 reginfo.expiration = 0;
00146 if ((ret = dtn_register(handle, ®info, ®id)) != 0) {
00147 fprintf(stderr, "error creating registration: %d (%s)\n",
00148 ret, dtn_strerror(dtn_errno(handle)));
00149 exit(1);
00150 }
00151 if (debug) printf("dtn_register succeeded, regid %d\n", regid);
00152
00153
00154 ping_spec.expiration = expiration;
00155 ping_spec.dopts = DOPTS_DELETE_RCPT;
00156
00157 printf("PING [%s] (expiration %u)...\n", ping_spec.dest.uri, expiration);
00158 if (interval == 0) {
00159 printf("WARNING: zero second interval will result in flooding pings!!\n");
00160 }
00161
00162
00163 for (i = 0; count == 0 || i < count; ++i) {
00164 gettimeofday(&send_times[seqno], NULL);
00165
00166
00167
00168
00169 memcpy(&payload_contents.ping, PING_STR, 8);
00170 payload_contents.seqno = seqno;
00171 payload_contents.nonce = nonce;
00172 payload_contents.time = send_times[seqno].tv_sec;
00173
00174 memset(&ping_payload, 0, sizeof(ping_payload));
00175 dtn_set_payload(&ping_payload, DTN_PAYLOAD_MEM,
00176 (char*)&payload_contents, sizeof(payload_contents));
00177
00178 memset(&bundle_id, 0, sizeof(bundle_id));
00179 if ((ret = dtn_send(handle, regid, &ping_spec, &ping_payload,
00180 &bundle_id)) != 0) {
00181 fprintf(stderr, "error sending bundle: %d (%s)\n",
00182 ret, dtn_strerror(dtn_errno(handle)));
00183 exit(1);
00184 }
00185
00186 creation_times[seqno] = bundle_id.creation_ts;
00187
00188 memset(&reply_spec, 0, sizeof(reply_spec));
00189 memset(&reply_payload, 0, sizeof(reply_payload));
00190
00191
00192
00193
00194 timeout = interval * 1000;
00195 if (i == count - 1)
00196 timeout += expiration * 2000;
00197
00198 do {
00199 gettimeofday(&recv_start, 0);
00200 if ((ret = dtn_recv(handle, &reply_spec,
00201 DTN_PAYLOAD_MEM, &reply_payload, timeout)) < 0)
00202 {
00203 if (dtn_errno(handle) == DTN_ETIMEOUT) {
00204 break;
00205 }
00206
00207 fprintf(stderr, "error getting ping reply: %d (%s)\n",
00208 ret, dtn_strerror(dtn_errno(handle)));
00209 exit(1);
00210 }
00211 gettimeofday(&recv_end, 0);
00212
00213 if (reply_payload.status_report != NULL)
00214 {
00215 sr_data = reply_payload.status_report;
00216 if (sr_data->flags != STATUS_DELETED) {
00217 fprintf(stderr, "(bad status report from %s: flags 0x%x)\n",
00218 reply_spec.source.uri, sr_data->flags);
00219 goto next;
00220 }
00221
00222
00223
00224 int j = 0;
00225 for (j = 0; j < MAX_PINGS_IN_FLIGHT; ++j) {
00226 if (creation_times[j].secs ==
00227 sr_data->bundle_id.creation_ts.secs &&
00228 creation_times[j].seqno ==
00229 sr_data->bundle_id.creation_ts.seqno)
00230 {
00231 printf("bundle deleted at [%s] (%s): seqno=%d, time=%ld ms\n",
00232 reply_spec.source.uri,
00233 dtn_status_report_reason_to_str(sr_data->reason),
00234 j, TIMEVAL_DIFF_MSEC(recv_end, send_times[j]));
00235 goto next;
00236 }
00237 }
00238
00239 printf("bundle deleted at [%s] (%s): ERROR: can't find seqno\n",
00240 reply_spec.source.uri,
00241 dtn_status_report_reason_to_str(sr_data->reason));
00242 }
00243 else {
00244 if (reply_payload.buf.buf_len != sizeof(ping_payload_t))
00245 {
00246 printf("%d bytes from [%s]: ERROR: length != %zu\n",
00247 reply_payload.buf.buf_len,
00248 reply_spec.source.uri,
00249 sizeof(ping_payload_t));
00250 goto next;
00251 }
00252
00253 memcpy(&recv_contents, reply_payload.buf.buf_val,
00254 sizeof(recv_contents));
00255
00256 if (recv_contents.seqno > MAX_PINGS_IN_FLIGHT)
00257 {
00258 printf("%d bytes from [%s]: ERROR: invalid seqno %d\n",
00259 reply_payload.buf.buf_len,
00260 reply_spec.source.uri,
00261 recv_contents.seqno);
00262 goto next;
00263 }
00264
00265 if (recv_contents.nonce != nonce)
00266 {
00267 printf("%d bytes from [%s]: ERROR: invalid nonce %u != %u\n",
00268 reply_payload.buf.buf_len,
00269 reply_spec.source.uri,
00270 recv_contents.nonce, nonce);
00271 goto next;
00272 }
00273
00274 if (recv_contents.time != (u_int32_t)send_times[recv_contents.seqno].tv_sec)
00275 {
00276 printf("%d bytes from [%s]: ERROR: time mismatch -- "
00277 "seqno %u reply time %u != send time %lu\n",
00278 reply_payload.buf.buf_len,
00279 reply_spec.source.uri,
00280 recv_contents.seqno,
00281 recv_contents.time,
00282 (long unsigned int)send_times[recv_contents.seqno].tv_sec);
00283 goto next;
00284 }
00285
00286 printf("%d bytes from [%s]: '%.*s' seqno=%d, time=%ld ms\n",
00287 reply_payload.buf.buf_len,
00288 reply_spec.source.uri,
00289 (u_int)strlen(PING_STR),
00290 reply_payload.buf.buf_val,
00291 recv_contents.seqno,
00292 TIMEVAL_DIFF_MSEC(recv_end,
00293 send_times[recv_contents.seqno]));
00294 fflush(stdout);
00295 }
00296 next:
00297 dtn_free_payload(&reply_payload);
00298 timeout -= TIMEVAL_DIFF_MSEC(recv_end, recv_start);
00299
00300
00301
00302 reply_count++;
00303 if (count != 0 && reply_count == count) {
00304 break;
00305 }
00306
00307 } while (timeout > 0);
00308
00309 seqno++;
00310 seqno %= MAX_PINGS_IN_FLIGHT;
00311 }
00312
00313 dtn_close(handle);
00314
00315 return 0;
00316 }
00317
00318 void
00319 doOptions(int argc, const char **argv)
00320 {
00321 int c;
00322
00323 progname = argv[0];
00324
00325 while ( (c=getopt(argc, (char **) argv, "hc:i:e:d:s:r:")) !=EOF ) {
00326 switch (c) {
00327 case 'c':
00328 count = atoi(optarg);
00329 break;
00330 case 'i':
00331 interval = atoi(optarg);
00332 break;
00333 case 'e':
00334 expiration = atoi(optarg);
00335 break;
00336 case 'd':
00337 strcpy(dest_eid_str, optarg);
00338 break;
00339 case 's':
00340 strcpy(source_eid_str, optarg);
00341 break;
00342 case 'h':
00343 usage();
00344 break;
00345 default:
00346 break;
00347 }
00348 }
00349
00350 if ((optind < argc) && (strlen(dest_eid_str) == 0)) {
00351 strcpy(dest_eid_str, argv[optind++]);
00352 }
00353
00354 if (optind < argc) {
00355 fprintf(stderr, "unsupported argument '%s'\n", argv[optind]);
00356 exit(1);
00357 }
00358
00359 if (dest_eid_str[0] == '\0') {
00360 fprintf(stderr, "must supply a destination eid (or 'localhost')\n");
00361 exit(1);
00362 }
00363 }
00364