dtnping.c

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2004-2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
00015  */
00016 
00017 
00018 #include <stdio.h>
00019 #include <unistd.h>
00020 #include <errno.h>
00021 #include <strings.h>
00022 #include <string.h>
00023 #include <stdlib.h>
00024 #include <sys/time.h>
00025 
00026 #include "dtn_api.h"
00027 
00028 const char *progname;
00029 
00030 void
00031 usage()
00032 {
00033     fprintf(stderr, "usage: %s [-c count] [-i interval] [-e expiration] eid\n",
00034             progname);
00035     exit(1);
00036 }
00037 
00038 void doOptions(int argc, const char **argv);
00039 
00040 int interval = 1;
00041 int count = 0;
00042 int expiration = 30;
00043 char dest_eid_str[DTN_MAX_ENDPOINT_ID] = "";
00044 char source_eid_str[DTN_MAX_ENDPOINT_ID] = "";
00045 char replyto_eid_str[DTN_MAX_ENDPOINT_ID] = "";
00046 
00047 #define MAX_PINGS_IN_FLIGHT 1024
00048 
00049 #define TIMEVAL_DIFF_MSEC(t1, t2) \
00050     ((unsigned long int)(((t1).tv_sec  - (t2).tv_sec)  * 1000) + \
00051      (((t1).tv_usec - (t2).tv_usec) / 1000))
00052 
00053 typedef struct {
00054     char      ping[8]; // dtn_ping!
00055     u_int32_t seqno;
00056     u_int32_t nonce;
00057     u_int32_t time;
00058 } ping_payload_t;
00059 
00060 int
00061 main(int argc, const char** argv)
00062 {
00063     int i;
00064     int ret;
00065     dtn_handle_t handle;
00066     dtn_endpoint_id_t source_eid;
00067     dtn_reg_info_t reginfo;
00068     dtn_reg_id_t regid;
00069     dtn_bundle_spec_t ping_spec;
00070     dtn_bundle_spec_t reply_spec;
00071     dtn_bundle_payload_t ping_payload;
00072     ping_payload_t payload_contents;
00073     ping_payload_t recv_contents;
00074     dtn_bundle_payload_t reply_payload;
00075     dtn_bundle_status_report_t* sr_data;
00076     dtn_bundle_id_t bundle_id;
00077     int debug = 1;
00078     char demux[64];
00079     int dest_len = 0;
00080     struct timeval send_times[MAX_PINGS_IN_FLIGHT];
00081     dtn_timestamp_t creation_times[MAX_PINGS_IN_FLIGHT];
00082     struct timeval now, recv_start, recv_end;
00083     u_int32_t nonce;
00084     u_int32_t seqno = 0;
00085     int time_until_send;
00086     const char* ping_str = "dtnping!";
00087 
00088     // force stdout to always be line buffered, even if output is
00089     // redirected to a pipe or file
00090     setvbuf(stdout, (char *)NULL, _IOLBF, 0);
00091     
00092     doOptions(argc, argv);
00093 
00094     memset(&ping_spec, 0, sizeof(ping_spec));
00095 
00096     gettimeofday(&now, 0);
00097     srand(now.tv_sec);
00098     nonce = rand();
00099     
00100     // open the ipc handle
00101     int err = dtn_open(&handle);
00102     if (err != DTN_SUCCESS) {
00103         fprintf(stderr, "fatal error opening dtn handle: %s\n",
00104                 dtn_strerror(err));
00105         exit(1);
00106     }
00107 
00108     // make sure they supplied a valid destination eid or
00109     // "localhost", in which case we just use the local daemon
00110     if (strcmp(dest_eid_str, "localhost") == 0) {
00111         dtn_build_local_eid(handle, &ping_spec.dest, "ping");
00112         
00113     } else {
00114         if (dtn_parse_eid_string(&ping_spec.dest, dest_eid_str)) {
00115             fprintf(stderr, "invalid destination eid string '%s'\n",
00116                     dest_eid_str);
00117             exit(1);
00118         }
00119     }
00120 
00121     dest_len = strlen(ping_spec.dest.uri);
00122     if ((dest_len < 4) ||
00123         (strcmp(ping_spec.dest.uri + dest_len - 4, "ping") != 0))
00124     {
00125         fprintf(stderr, "\nWARNING: ping destination does not end in \"ping\"\n\n");
00126     }
00127     
00128     // if the user specified a source eid, register on it.
00129     // otherwise, build a local eid based on the configuration of
00130     // our dtn router plus the demux string
00131     snprintf(demux, sizeof(demux), "/ping.%d", getpid());
00132     if (source_eid_str[0] != '\0') {
00133         if (dtn_parse_eid_string(&source_eid, source_eid_str)) {
00134             fprintf(stderr, "invalid source eid string '%s'\n",
00135                     source_eid_str);
00136             exit(1);
00137         }
00138     } else {
00139         dtn_build_local_eid(handle, &source_eid, demux);
00140     }
00141 
00142     // set the source and replyto eids in the bundle spec
00143     if (debug) printf("source_eid [%s]\n", source_eid.uri);
00144     dtn_copy_eid(&ping_spec.source, &source_eid);
00145     dtn_copy_eid(&ping_spec.replyto, &source_eid);
00146     
00147     // now create a new registration based on the source
00148     memset(&reginfo, 0, sizeof(reginfo));
00149     dtn_copy_eid(&reginfo.endpoint, &source_eid);
00150     reginfo.failure_action = DTN_REG_DEFER;
00151     reginfo.regid = DTN_REGID_NONE;
00152     reginfo.expiration = 0;
00153     if ((ret = dtn_register(handle, &reginfo, &regid)) != 0) {
00154         fprintf(stderr, "error creating registration: %d (%s)\n",
00155                 ret, dtn_strerror(dtn_errno(handle)));
00156         exit(1);
00157     }    
00158     if (debug) printf("dtn_register succeeded, regid %d\n", regid);
00159 
00160     // set the expiration time and request deletion status reports
00161     ping_spec.expiration = expiration;
00162     ping_spec.dopts = DOPTS_DELETE_RCPT;
00163 
00164     printf("PING [%s]...\n", ping_spec.dest.uri);
00165     if (interval == 0) {
00166         printf("WARNING: zero second interval will result in flooding pings!!\n");
00167     }
00168     
00169     // loop, sending pings and polling for activity
00170     for (i = 0; count == 0 || i < count; ++i) {
00171         gettimeofday(&send_times[seqno], NULL);
00172         
00173         // fill in a short payload string, a nonce, and a sequence number
00174         // to verify the echo feature and make sure we're not getting
00175         // duplicate responses or ping responses from another app
00176         memcpy(&payload_contents.ping, ping_str, 8);
00177         payload_contents.seqno = seqno;
00178         payload_contents.nonce = nonce;
00179         payload_contents.time = send_times[seqno].tv_sec;
00180         
00181         memset(&ping_payload, 0, sizeof(ping_payload));
00182         dtn_set_payload(&ping_payload, DTN_PAYLOAD_MEM,
00183                         (char*)&payload_contents, sizeof(payload_contents));
00184         
00185         memset(&bundle_id, 0, sizeof(bundle_id));
00186         if ((ret = dtn_send(handle, &ping_spec, &ping_payload,
00187                             &bundle_id)) != 0) {
00188             fprintf(stderr, "error sending bundle: %d (%s)\n",
00189                     ret, dtn_strerror(dtn_errno(handle)));
00190             exit(1);
00191         }
00192         
00193         creation_times[seqno] = bundle_id.creation_ts;
00194 
00195         memset(&reply_spec, 0, sizeof(reply_spec));
00196         memset(&reply_payload, 0, sizeof(reply_payload));
00197 
00198         // now loop waiting for replies / status reports until it's
00199         // time to send again
00200         time_until_send = interval * 1000;
00201         do {
00202             gettimeofday(&recv_start, 0);
00203             if ((ret = dtn_recv(handle, &reply_spec,
00204                                 DTN_PAYLOAD_MEM, &reply_payload, time_until_send)) < 0)
00205             {
00206                 if (dtn_errno(handle) == DTN_ETIMEOUT) {
00207                     break; // time to send again
00208                 }
00209                 
00210                 fprintf(stderr, "error getting ping reply: %d (%s)\n",
00211                         ret, dtn_strerror(dtn_errno(handle)));
00212                 exit(1);
00213             }
00214             gettimeofday(&recv_end, 0);
00215             
00216             if (reply_payload.status_report != NULL)
00217             {
00218                 sr_data = reply_payload.status_report;
00219                 if (sr_data->flags != STATUS_DELETED) {
00220                     fprintf(stderr, "(bad status report from %s: flags 0x%x)\n",
00221                             reply_spec.source.uri, sr_data->flags);
00222                     goto next;
00223                 }
00224 
00225                 // find the seqno corresponding to the original
00226                 // transmission time in the status report
00227                 int j = 0;
00228                 for (j = 0; j < MAX_PINGS_IN_FLIGHT; ++j) {
00229                     if (creation_times[j].secs  ==
00230                             sr_data->bundle_id.creation_ts.secs &&
00231                         creation_times[j].seqno ==
00232                             sr_data->bundle_id.creation_ts.seqno)
00233                     {
00234                         printf("bundle deleted at [%s] (%s): seqno=%d, time=%ld ms\n",
00235                                reply_spec.source.uri,
00236                                dtn_status_report_reason_to_str(sr_data->reason),
00237                                j, TIMEVAL_DIFF_MSEC(recv_end, send_times[j]));
00238                         goto next;
00239                     }
00240                 }
00241 
00242                 printf("bundle deleted at [%s] (%s): ERROR: can't find seqno\n",
00243                        reply_spec.source.uri, 
00244                        dtn_status_report_reason_to_str(sr_data->reason));
00245             }
00246             else {
00247                 if (reply_payload.buf.buf_len != sizeof(ping_payload_t))
00248                 {
00249                     printf("%d bytes from [%s]: ERROR: length != %zu\n",
00250                            reply_payload.buf.buf_len,
00251                            reply_spec.source.uri,
00252                            sizeof(ping_payload_t));
00253                     goto next;
00254                 }
00255 
00256                 memcpy(&recv_contents, reply_payload.buf.buf_val,
00257                        sizeof(recv_contents));
00258                 
00259                 if (recv_contents.seqno > MAX_PINGS_IN_FLIGHT)
00260                 {
00261                     printf("%d bytes from [%s]: ERROR: invalid seqno %d\n",
00262                            reply_payload.buf.buf_len,
00263                            reply_spec.source.uri,
00264                            recv_contents.seqno);
00265                     goto next;
00266                 }
00267 
00268                 if (recv_contents.nonce != nonce)
00269                 {
00270                     printf("%d bytes from [%s]: ERROR: invalid nonce %u != %u\n",
00271                            reply_payload.buf.buf_len,
00272                            reply_spec.source.uri,
00273                            recv_contents.nonce, nonce);
00274                     goto next;
00275                 }
00276 
00277                 if (recv_contents.time != (u_int32_t)send_times[seqno].tv_sec)
00278                 {
00279                     printf("%d bytes from [%s]: ERROR: time mismatch %u != %lu\n",
00280                            reply_payload.buf.buf_len,
00281                            reply_spec.source.uri,
00282                            recv_contents.time,
00283                            (long unsigned int)send_times[seqno].tv_sec);
00284                     goto next;
00285                 }
00286                 
00287                 printf("%d bytes from [%s]: '%.*s' seqno=%d, time=%ld ms\n",
00288                        reply_payload.buf.buf_len,
00289                        reply_spec.source.uri,
00290                        (u_int)strlen(ping_str),
00291                        reply_payload.buf.buf_val,
00292                        recv_contents.seqno,
00293                        TIMEVAL_DIFF_MSEC(recv_end,
00294                                          send_times[recv_contents.seqno]));
00295                 fflush(stdout);
00296             }
00297 next:
00298             dtn_free_payload(&reply_payload);
00299             time_until_send -= TIMEVAL_DIFF_MSEC(recv_end, recv_start);
00300 
00301         } while (time_until_send > 0);
00302         
00303         seqno++;
00304         seqno %= MAX_PINGS_IN_FLIGHT;
00305     }
00306 
00307     dtn_close(handle);
00308 
00309     return 0;
00310 }
00311 
00312 void
00313 doOptions(int argc, const char **argv)
00314 {
00315     int c;
00316 
00317     progname = argv[0];
00318 
00319     while ( (c=getopt(argc, (char **) argv, "hc:i:e:d:s:r:")) !=EOF ) {
00320         switch (c) {
00321         case 'c':
00322             count = atoi(optarg);
00323             break;
00324         case 'i':
00325             interval = atoi(optarg);
00326             break;
00327         case 'e':
00328             expiration = atoi(optarg);
00329             break;
00330         case 'd':
00331             strcpy(dest_eid_str, optarg);
00332             break;
00333         case 's':
00334             strcpy(source_eid_str, optarg);
00335             break;
00336         case 'h':
00337             usage();
00338             break;
00339         default:
00340             break;
00341         }
00342     }
00343 
00344     if ((optind < argc) && (strlen(dest_eid_str) == 0)) {
00345         strcpy(dest_eid_str, argv[optind++]);
00346     }
00347 
00348     if (optind < argc) {
00349         fprintf(stderr, "unsupported argument '%s'\n", argv[optind]);
00350         exit(1);
00351     }
00352 
00353     if (dest_eid_str[0] == '\0') {
00354         fprintf(stderr, "must supply a destination eid (or 'localhost')\n");
00355         exit(1);
00356     }
00357 }
00358 

Generated on Thu Jun 7 12:54:27 2007 for DTN Reference Implementation by  doxygen 1.5.1