dtnperf-client.c

Go to the documentation of this file.
00001 /* ----------------------
00002  *    dtnperf-client.c
00003  * ---------------------- */
00004 
00005 /* -----------------------------------------------------------
00006  *  PLEASE NOTE: this software was developed
00007  *    by Piero Cornice <piero.cornice@gmail.com>
00008  *    at DEIS - University of Bologna, Italy.
00009  *  If you want to modify it, please contact me
00010  *  at piero.cornice(at)gmail.com. Thanks =)
00011  * -----------------------------------------------------------
00012  */
00013 
00014 /*
00015  * Modified slightly (and renamed) by Michael Demmer
00016  * <demmer@cs.berkeley.edu> to fit in with the DTN2
00017  * source distribution.
00018  */
00019 
00020 /* version 1.6.0 - 23/06/06
00021  *
00022  * - compatible with DTN 2.2.0 reference implementation
00023  * - fixed measure units errors
00024  */
00025 
00026 #include <stdio.h>
00027 #include <unistd.h>
00028 #include <errno.h>
00029 #include <strings.h>
00030 #include <string.h>
00031 #include <stdlib.h>
00032 #include <sys/time.h>
00033 #include <sys/file.h>
00034 #include <time.h>
00035 #include <assert.h>
00036 
00037 #include "dtn_api.h"
00038 #include "dtn_types.h"
00039 
00040 #define MAX_MEM_PAYLOAD 50000 // max payload (in bytes) if bundles are stored into memory
00041 #define ILLEGAL_PAYLOAD 0     // illegal number of bytes for the bundle payload
00042 #define DEFAULT_PAYLOAD 50000 // default value (in bytes) for bundle payload
00043 
00044 /* ---------------------------------------------
00045  * Values inside [square brackets] are defaults
00046  * --------------------------------------------- */
00047 
00048 char *progname;
00049 
00050 // global options
00051 dtn_bundle_payload_location_t 
00052         payload_type    = DTN_PAYLOAD_FILE;    // the type of data source for the bundle [FILE]
00053 int verbose             = 0;    // if set to 1, execution becomes verbose (-v option) [0]
00054 char op_mode               ;    // operative mode (t = time_mode, d = data_mode)
00055 int debug               = 0;    // if set to 1, many debug messages are shown [0]
00056 int csv_out             = 0;    // if set to 1, a Comma-Separated-Values output is shown [0]
00057 /* -----------------------------------------------------------------------
00058  * NOTE - CSV output shows the following columns:
00059  *  Time-Mode: BUNDLES_SENT, PAYLOAD, TIME, DATA_SENT, GOODPUT
00060  *  Data-Mode: BUNDLE_ID, PAYLOAD, TIME, GOODPUT
00061  * ----------------------------------------------------------------------- */
00062 
00063 // bundle options
00064 int expiration          = 3600; // expiration time (sec) [3600]
00065 int delivery_receipts   = 1;    // request delivery receipts [1]
00066 int forwarding_receipts = 0;    // request per hop departure [0]
00067 int custody             = 0;    // request custody transfer [0]
00068 int custody_receipts    = 0;    // request per custodian receipts [0]
00069 int receive_receipts    = 0;    // request per hop arrival receipt [0]
00070 //int overwrite           = 0;    // queue overwrite option [0]
00071 int wait_for_report     = 1;    // wait for bundle status reports [1]
00072 
00073 // specified options for bundle tuples
00074 char * arg_replyto      = NULL; // replyto_tuple
00075 char * arg_source       = NULL; // source_tuple
00076 char * arg_dest         = NULL; // destination_tuple
00077 
00078 dtn_reg_id_t regid      = DTN_REGID_NONE;   // registration ID (-i option)
00079 long bundle_payload     = DEFAULT_PAYLOAD;  // quantity of data (in bytes) to send (-p option)
00080 char * p_arg              ;                 // argument of -p option
00081 
00082 // Time-Mode options
00083 int transmission_time   = 0;    // seconds of transmission
00084 
00085 // Data-Mode options
00086 long data_qty           = 0;    // data to be transmitted (bytes)
00087 char * n_arg               ;    // arguments of -n option
00088 char * p_arg               ;    // arguments of -p option
00089 int n_copies            = 1;    // number of trasmissions [1]
00090 int sleepVal            = 0;    // seconds to sleep between transmissions in Data-Mode [0]
00091 int use_file            = 1;    // if set to 1, a file is used instead of memory [1]
00092 char data_unit             ;    // B = bytes, K = kilobytes, M = megabytes
00093 
00094 // Data-Mode variables
00095 int fd                     ;    // file descriptor, used with -f option
00096 int data_written        = 0;    // data written on the file
00097 int data_read           = 0;    // data read from the file
00098 char * file_name_src    = "/var/lib/dtn/dtnperf/dtnbuffer.snd";    // name of the SOURCE file to be used
00099 
00100 /* -------------------------------
00101  *       function interfaces
00102  * ------------------------------- */
00103 void parse_options(int, char**);
00104 dtn_endpoint_id_t* parse_eid(dtn_handle_t handle, dtn_endpoint_id_t * eid, char * str);
00105 void print_usage(char* progname);
00106 void print_eid(char * label, dtn_endpoint_id_t * eid);
00107 void pattern(char *outBuf, int inBytes);
00108 struct timeval set(double sec);
00109 struct timeval add(double sec);
00110 void show_report (u_int buf_len, char* eid, struct timeval start, struct timeval end, int data);
00111 void csv_time_report(int b_sent, int payload, struct timeval start, struct timeval end);
00112 void csv_data_report(int b_id, int payload, struct timeval start, struct timeval end);
00113 long bundles_needed (long data, long pl);
00114 void check_options();
00115 void show_options();
00116 void add_time(struct timeval *tot_time, struct timeval part_time);
00117 long mega2byte(long n);
00118 long kilo2byte(long n);
00119 char findDataUnit(const char *inarg);
00120 
00121 /* -------------------------------------------------
00122  * main
00123  * ------------------------------------------------- */
00124 int main(int argc, char** argv)
00125 {
00126     /* -----------------------
00127      *  variables declaration
00128      * ----------------------- */
00129     int ret;                        // result of DTN-registration
00130     struct timeval start, end,
00131                    p_start, p_end, now; // time-calculation variables
00132 
00133     int i, j;                       // loop-control variables
00134     const char* time_report_hdr = "BUNDLE_SENT,PAYLOAD,TIME,DATA_SENT,GOODPUT";
00135     const char* data_report_hdr = "BUNDLE_ID,PAYLOAD,TIME,GOODPUT";
00136     int n_bundles = 0;              // number of bundles needed (Data-Mode)
00137     
00138     // DTN variables
00139     dtn_handle_t        handle;
00140     dtn_reg_info_t      reginfo;
00141     dtn_bundle_spec_t   bundle_spec;
00142     dtn_bundle_spec_t   reply_spec;
00143     dtn_bundle_id_t     bundle_id;
00144     dtn_bundle_payload_t send_payload;
00145     dtn_bundle_payload_t reply_payload;
00146     char demux[64];
00147 
00148     // buffer specifications
00149     char* buffer = NULL;            // buffer containing data to be transmitted
00150     int bufferLen;                  // lenght of buffer
00151     int bundles_sent;               // number of bundles sent in Time-Mode
00152     
00153     /* -------
00154      *  begin
00155      * ------- */
00156 
00157     // print information header
00158     printf("\nDTNperf - CLIENT - v 1.6.0");
00159     printf("\nwritten by piero.cornice@gmail.com");
00160     printf("\nDEIS - University of Bologna, Italy");
00161     printf("\n");
00162 
00163     // parse command-line options
00164     parse_options(argc, argv);
00165     if (debug) printf("[debug] parsed command-line options\n");
00166 
00167     // check command-line options
00168     if (debug) printf("[debug] checking command-line options...");
00169     check_options();
00170     if (debug) printf(" done\n");
00171 
00172     // show command-line options (if verbose)
00173     if (verbose) {
00174         show_options();
00175     }
00176 
00177     // open the ipc handle
00178     if (debug) fprintf(stdout, "Opening connection to local DTN daemon...");
00179     int err = dtn_open(&handle);
00180     if (err != DTN_SUCCESS) {
00181         fprintf(stderr, "fatal error opening dtn handle: %s\n", dtn_strerror(err));
00182         exit(1);
00183     }
00184     if (debug) printf(" done\n");
00185 
00186 
00187     /* ----------------------------------------------------- *
00188      *   initialize and parse bundle src/dest/replyto EIDs   *
00189      * ----------------------------------------------------- */
00190 
00191     // initialize bundle spec
00192     if (debug) printf("[debug] memset for bundle_spec...");
00193     memset(&bundle_spec, 0, sizeof(bundle_spec));
00194     if (debug) printf(" done\n");
00195 
00196     // SOURCE is local eid + demux string (optionally with file path)
00197     sprintf(demux, "/dtnperf:/src");
00198     dtn_build_local_eid(handle, &bundle_spec.source, demux);
00199     if (verbose) printf("\nSource     : %s\n", bundle_spec.source.uri);
00200 
00201     // DEST host is specified at run time, demux is hardcoded
00202     sprintf(demux, "/dtnperf:/dest");
00203     strcat(arg_dest, demux);
00204     parse_eid(handle, &bundle_spec.dest, arg_dest);
00205     if (verbose) printf("Destination: %s\n", bundle_spec.dest.uri);
00206 
00207     // REPLY-TO (if none specified, same as the source)
00208     if (arg_replyto == NULL) {
00209         if (debug) printf("[debug] setting replyto = source...");
00210         dtn_copy_eid(&bundle_spec.replyto, &bundle_spec.source);
00211         if (debug) printf(" done\n");
00212     }
00213     else {
00214         sprintf(demux, "/dtnperf:/src");
00215         strcat(arg_replyto, demux);
00216         parse_eid(handle, &bundle_spec.dest, arg_replyto);
00217     }
00218     if (verbose) printf("Reply-to   : %s\n\n", bundle_spec.replyto.uri);
00219 
00220     /* ------------------------
00221      * set the dtn options
00222      * ------------------------ */
00223     if (debug) printf("[debug] setting the DTN options: ");
00224 
00225     // expiration
00226     bundle_spec.expiration = expiration;
00227 
00228     // set the delivery receipt option
00229     if (delivery_receipts) {
00230         bundle_spec.dopts |= DOPTS_DELIVERY_RCPT;
00231         if (debug) printf("DELIVERY_RCPT ");
00232     }
00233 
00234     // set the forward receipt option
00235     if (forwarding_receipts) {
00236         bundle_spec.dopts |= DOPTS_FORWARD_RCPT;
00237         if (debug) printf("FORWARD_RCPT ");
00238     }
00239 
00240     // request custody transfer
00241     if (custody) {
00242         bundle_spec.dopts |= DOPTS_CUSTODY;
00243         if (debug) printf("CUSTODY ");
00244     }
00245 
00246     // request custody transfer
00247     if (custody_receipts) {
00248         bundle_spec.dopts |= DOPTS_CUSTODY_RCPT;
00249         if (debug) printf("CUSTODY_RCPT ");
00250     }
00251 
00252     // request receive receipt
00253     if (receive_receipts) {
00254         bundle_spec.dopts |= DOPTS_RECEIVE_RCPT;
00255         if (debug) printf("RECEIVE_RCPT ");
00256     }
00257 
00258 /*
00259     // overwrite
00260     if (overwrite) {
00261         bundle_spec.dopts |= DOPTS_OVERWRITE;
00262         if (debug) printf("OVERWRITE ");
00263     }
00264 */
00265     if (debug) printf("option(s) set\n");
00266 
00267     /* ----------------------------------------------
00268      * create a new registration based on the source
00269      * ---------------------------------------------- */
00270     if (debug) printf("[debug] memset for reginfo...");
00271     memset(&reginfo, 0, sizeof(reginfo));
00272     if (debug) printf(" done\n");
00273 
00274     if (debug) printf("[debug] copying bundle_spec.replyto to reginfo.endpoint...");
00275     dtn_copy_eid(&reginfo.endpoint, &bundle_spec.replyto);
00276     if (debug) printf(" done\n");
00277 
00278     if (debug) printf("[debug] setting up reginfo...");
00279     reginfo.failure_action = DTN_REG_DEFER;
00280     reginfo.regid = regid;
00281     reginfo.expiration = 30;
00282     if (debug) printf(" done\n");
00283 
00284     if (debug) printf("[debug] registering to local daemon...");
00285     if ((ret = dtn_register(handle, &reginfo, &regid)) != 0) {
00286         fprintf(stderr, "error creating registration: %d (%s)\n",
00287                 ret, dtn_strerror(dtn_errno(handle)));
00288         exit(1);
00289     }    
00290     if (debug) printf(" done: regid 0x%x\n", regid);
00291 
00292     // if bundle_payload > MAX_MEM_PAYLOAD, transfer a file
00293     if (bundle_payload > MAX_MEM_PAYLOAD)
00294         use_file = 1;
00295     else
00296         use_file = 0;
00297     
00298     /* ------------------------------------------------------------------------------
00299      * select the operative-mode (between Time_Mode and Data_Mode)
00300      * ------------------------------------------------------------------------------ */
00301 
00302     if (op_mode == 't') {
00303     /* ---------------------------------------
00304      * Time_Mode
00305      * --------------------------------------- */
00306         if (verbose) printf("Working in Time_Mode\n");
00307         if (verbose) printf("requested %d second(s) of transmission\n", transmission_time);
00308 
00309         if (debug) printf("[debug] bundle_payload %s %d bytes\n",
00310                             use_file ? ">=" : "<",
00311                             MAX_MEM_PAYLOAD);
00312         if (verbose) printf(" transmitting data %s\n", use_file ? "using a file" : "using memory");
00313 
00314         // reset data_qty
00315         if (debug) printf("[debug] reset data_qty and bundles_sent...");
00316         data_qty = 0;
00317         bundles_sent = 0;
00318         if (debug) printf(" done\n");
00319 
00320         // allocate buffer space
00321         if (debug) printf("[debug] malloc for the buffer...");
00322         buffer = malloc(bundle_payload);
00323         if (debug) printf(" done\n");
00324         
00325         // initialize buffer
00326         if (debug) printf("[debug] initialize the buffer with a pattern...");
00327         pattern(buffer, bundle_payload);
00328         if (debug) printf(" done\n");
00329         bufferLen = strlen(buffer);
00330         if (debug) printf("[debug] bufferLen = %d\n", bufferLen);
00331 
00332         if (use_file) {
00333             // create the file
00334             if (debug) printf("[debug] creating file %s...", file_name_src);
00335             fd = open(file_name_src, O_CREAT|O_TRUNC|O_WRONLY|O_APPEND, 0666);
00336             if (fd < 0) {
00337                 fprintf(stderr, "ERROR: couldn't create file %s [fd = %d].\n \
00338                                  Maybe you don't have permissions\n",
00339                         file_name_src, fd);
00340                 exit(2);
00341             }
00342             if (debug) printf(" done\n");
00343 
00344             // fill in the file with a pattern
00345             if (debug) printf("[debug] filling the file (%s) with the pattern...", file_name_src);
00346             data_written += write(fd, buffer, bufferLen);
00347             if (debug) printf(" done. Written %d bytes\n", data_written);
00348 
00349             // close the file
00350             if (debug) printf("[debug] closing file (%s)...", file_name_src);
00351             close(fd);
00352             if (debug) printf(" done\n");
00353         }
00354 
00355         // memset for payload
00356         if (debug) printf("[debug] memset for payload...");
00357         memset(&send_payload, 0, sizeof(send_payload));
00358         if (debug) printf(" done\n");
00359 
00360         // fill in the payload
00361         if (debug) printf("[debug] filling payload...");
00362         if (use_file)
00363             dtn_set_payload(&send_payload, DTN_PAYLOAD_FILE, file_name_src, strlen(file_name_src));
00364         else
00365             dtn_set_payload(&send_payload, DTN_PAYLOAD_MEM, buffer, bufferLen);
00366         if (debug) printf(" done\n");
00367 
00368         // initialize timer
00369         if (debug) printf("[debug] initializing timer...");
00370         gettimeofday(&start, NULL);
00371         if (debug) printf(" start.tv_sec = %d sec\n", (u_int)start.tv_sec);
00372 
00373         // calculate end-time
00374         if (debug) printf("[debug] calculating end-time...");
00375         end = set (0);
00376         end.tv_sec = start.tv_sec + transmission_time;
00377         if (debug) printf(" end.tv_sec = %d sec\n", (u_int)end.tv_sec);
00378 
00379         // loop
00380         if (debug) printf("[debug] entering loop...\n");
00381         for (now.tv_sec = start.tv_sec; now.tv_sec <= end.tv_sec; gettimeofday(&now, NULL)) {
00382 
00383             if (debug) printf("\t[debug] now.tv_sec = %u sec of %u\n", (u_int)now.tv_sec, (u_int)end.tv_sec);
00384 
00385             // send the bundle
00386             if (debug) printf("\t[debug] sending the bundle...");
00387             memset(&bundle_id, 0, sizeof(bundle_id));
00388             if ((ret = dtn_send(handle, &bundle_spec, &send_payload, &bundle_id)) != 0) {
00389                 fprintf(stderr, "error sending bundle: %d (%s)\n",
00390                         ret, dtn_strerror(dtn_errno(handle)));
00391                 exit(1);
00392             }
00393             if (debug) printf(" bundle sent\n");
00394 
00395             // increment bundles_sent
00396             bundles_sent++;
00397             if (debug) printf("\t[debug] now bundles_sent is %d\n", bundles_sent);
00398     
00399             // increment data_qty
00400             data_qty += bundle_payload;
00401             if (debug) printf("\t[debug] now data_qty is %lu\n", data_qty);
00402 
00403             // prepare memory for the reply
00404             if (wait_for_report)
00405             {
00406                 if (debug) printf("\t[debug] memset for reply_spec...");
00407                 memset(&reply_spec, 0, sizeof(reply_spec));
00408                 if (debug) printf(" done\n");
00409                 if (debug) printf("\t[debug] memset for reply_payload...");
00410                 memset(&reply_payload, 0, sizeof(reply_payload));
00411                 if (debug) printf(" done\n");
00412             }
00413             
00414             // wait for the reply
00415             if (debug) printf("\t[debug] waiting for the reply...");
00416             if ((ret = dtn_recv(handle, &reply_spec, DTN_PAYLOAD_MEM, &reply_payload, -1)) < 0)
00417             {
00418                 fprintf(stderr, "error getting reply: %d (%s)\n", ret, dtn_strerror(dtn_errno(handle)));
00419                 exit(1);
00420             }
00421             if (debug) printf(" reply received\n");
00422 
00423             // get the PARTIAL end time
00424             if (debug) printf("\t[debug] getting partial end-time...");
00425             gettimeofday(&p_end, NULL);
00426             if (debug) printf(" end.tv_sec = %u sec\n", (u_int)p_end.tv_sec);
00427 
00428             if (debug) printf("----- END OF THIS LOOP -----\n\n");
00429         } // -- for
00430         if (debug) printf("[debug] out from loop\n");
00431 
00432         // deallocate buffer memory
00433         if (debug) printf("[debug] deallocating buffer memory...");
00434         free((void*)buffer);
00435         if (debug) printf(" done\n");
00436 
00437         // get the TOTAL end time
00438         if (debug) printf("[debug] getting total end-time...");
00439         gettimeofday(&end, NULL);
00440         if (debug) printf(" end.tv_sec = %u sec\n", (u_int)end.tv_sec);
00441     
00442         // show the report
00443         if (csv_out == 0) {
00444             printf("%d bundles sent, each with a %ld bytes payload\n", bundles_sent, bundle_payload);
00445             show_report(reply_payload.dtn_bundle_payload_t_u.buf.buf_len,
00446                         reply_spec.source.uri,
00447                         start,
00448                         end,
00449                         data_qty);
00450         }
00451         if (csv_out == 1) {
00452             printf("%s\n", time_report_hdr);
00453             csv_time_report(bundles_sent, bundle_payload, start, end);
00454         }
00455 
00456     } // -- time_mode
00457 
00458     else if (op_mode == 'd') {
00459     /* ---------------------------------------
00460      * Data_Mode
00461      * --------------------------------------- */
00462         if (verbose) printf("Working in Data_Mode\n");
00463 
00464         // initialize the buffer
00465         if (debug) printf("[debug] initializing buffer...");
00466         if (!use_file) {
00467             buffer = malloc( (data_qty < bundle_payload) ? data_qty : bundle_payload );
00468             memset(buffer, 0, (data_qty < bundle_payload) ? data_qty : bundle_payload );
00469             pattern(buffer, (data_qty < bundle_payload) ? data_qty : bundle_payload );
00470         }
00471         if (use_file) {
00472             buffer = malloc(data_qty);
00473             memset(buffer, 0, data_qty);
00474             pattern(buffer, data_qty);
00475         }
00476         bufferLen = strlen(buffer);
00477         if (debug) printf(" done. bufferLen = %d (should equal %s)\n",
00478                             bufferLen, use_file ? "data_qty" : "bundle_payload");
00479 
00480         if (use_file) {
00481             // create the file
00482             if (debug) printf("[debug] creating file %s...", file_name_src);
00483             fd = open(file_name_src, O_CREAT|O_TRUNC|O_WRONLY|O_APPEND, 0666);
00484             if (fd < 0) {
00485                 fprintf(stderr, "ERROR: couldn't create file [fd = %d]. Maybe you don't have permissions\n", fd);
00486                 exit(2);
00487             }
00488             if (debug) printf(" done\n");
00489 
00490             // fill in the file with a pattern
00491             if (debug) printf("[debug] filling the file (%s) with the pattern...", file_name_src);
00492             data_written += write(fd, buffer, bufferLen);
00493             if (debug) printf(" done. Written %d bytes\n", data_written);
00494 
00495             // close the file
00496             if (debug) printf("[debug] closing file (%s)...", file_name_src);
00497             close(fd);
00498             if (debug) printf(" done\n");
00499         }
00500 
00501         // fill in the payload
00502         if (debug) printf("[debug] filling the bundle payload...");
00503         memset(&send_payload, 0, sizeof(send_payload));
00504         if (use_file) {
00505             dtn_set_payload(&send_payload, DTN_PAYLOAD_FILE, file_name_src, strlen(file_name_src));
00506         } else {
00507             dtn_set_payload(&send_payload, DTN_PAYLOAD_MEM, buffer, bufferLen);
00508         }
00509         if (debug) printf(" done\n");
00510 
00511         // if CSV option is set, print the data_report_hdr
00512         if (csv_out == 1)
00513             printf("%s\n", data_report_hdr);
00514 
00515         // 1) If you're using MEMORY (-m option), the maximum data quantity is MAX_MEM_PAYLOAD bytes.
00516         //    So, if someone tries to send more data, you have to do multiple transmission
00517         //    in order to avoid daemon failure.
00518         //    This, however, doesn't affect the goodput measurement, since it is calculated
00519         //    for each transmission.
00520         // 2) If you are using FILE, you may want to send an amount of data
00521         //    using smaller bundles.
00522         // So it's necessary to calculate how many bundles are needed.
00523         if (debug) printf("[debug] calculating how many bundles are needed...");
00524         n_bundles = bundles_needed(data_qty, bundle_payload);
00525         if (debug) printf(" n_bundles = %d\n", n_bundles);
00526 
00527         // initialize TOTAL start timer
00528         if (debug) printf("[debug] initializing TOTAL start timer...");
00529         gettimeofday(&start, NULL);
00530         if (debug) printf(" start.tv_sec = %u sec\n", (u_int)start.tv_sec);
00531 
00532         if (debug) printf("[debug] entering n_copies loop...\n");
00533         // --------------- loop until all n_copies are sent
00534         for (i=0; i<n_copies; i++) {
00535 
00536                 if (debug) printf("\t[debug] entering n_bundles loop...\n");
00537                 for (j=0; j<n_bundles; j++) {
00538 
00539                     // initialize PARTIAL start timer
00540                     if (debug) printf("\t\t[debug] initializing PARTIAL start timer...");
00541                     gettimeofday(&p_start, NULL);
00542                     if (debug) printf(" p_start.tv_sec = %u sec\n", (u_int)p_start.tv_sec);
00543 
00544                     // send the bundle
00545                     if (debug) printf("\t\t[debug] sending copy %d...", i+1);
00546                     memset(&bundle_id, 0, sizeof(bundle_id));
00547                     if ((ret = dtn_send(handle, &bundle_spec, &send_payload, &bundle_id)) != 0) {
00548                         fprintf(stderr, "error sending bundle: %d (%s)\n",
00549                                 ret, dtn_strerror(dtn_errno(handle)));
00550                         exit(1);
00551                     }
00552                     if (debug) printf(" bundle sent\n");
00553 
00554                     // prepare memory areas for the reply
00555                     if (wait_for_report)
00556                     {
00557                         if (debug) printf("\t\t[debug] setting memory for reply...");
00558                         memset(&reply_spec, 0, sizeof(reply_spec));
00559                         memset(&reply_payload, 0, sizeof(reply_payload));
00560                         if (debug) printf(" done\n");
00561                     }
00562 
00563                     // wait for the reply
00564                     if (debug) printf("\t\t[debug] waiting for the reply...");
00565                     if ((ret = dtn_recv(handle, &reply_spec, DTN_PAYLOAD_MEM, &reply_payload, -1)) < 0)
00566                     {
00567                         fprintf(stderr, "error getting reply: %d (%s)\n", ret, dtn_strerror(dtn_errno(handle)));
00568                         exit(1);
00569                     }
00570                     if (debug) printf(" reply received\n");
00571 
00572                     // get PARTIAL end time
00573                     if (debug) printf("\t\t[debug] stopping PARTIAL timer...");
00574                     gettimeofday(&p_end, NULL);
00575                     if (debug) printf(" p_end.tv_sec = %u sec\n", (u_int)p_end.tv_sec);
00576 
00577                     // show the PARTIAL report (verbose mode)
00578                     if (verbose) {
00579                         printf("[%d/%d] ", j+1, n_bundles);
00580                         show_report(reply_payload.dtn_bundle_payload_t_u.buf.buf_len,
00581                                     bundle_spec.source.uri,
00582                                     p_start,
00583                                     p_end,
00584                                     ((bundle_payload <= data_qty)?bundle_payload:data_qty));
00585                     }
00586                 } // end for(n_bundles)
00587                 if (debug) printf("\t[debug] ...out from n_bundles loop\n");
00588 
00589             // calculate TOTAL end time
00590             if (debug) printf("\t[debug] calculating TOTAL end time...");
00591             gettimeofday(&end, NULL);
00592             if (debug) printf(" end.tv_sec = %u sec\n", (u_int)end.tv_sec);
00593 
00594             // show the TOTAL report
00595             if (csv_out == 0) {
00596                 show_report(reply_payload.dtn_bundle_payload_t_u.buf.buf_len,
00597                             reply_spec.source.uri,
00598                             start,
00599                             end,
00600                             data_qty);
00601             }
00602             if (csv_out == 1) {    
00603                 csv_data_report(i+1, data_qty, start, end);
00604             }
00605 
00606             if (n_copies > 0)
00607                 sleep(sleepVal);
00608 
00609         } // end for(n_copies)
00610         if (debug) printf("[debug] ...out from n_copies loop\n");
00611         // -------------------------- end of loop
00612 
00613         // deallocate buffer memory
00614         if (debug) printf("[debug] deallocating buffer memory...");
00615         free(buffer);
00616         if (debug) printf(" done\n");
00617 
00618     } // -- data_mode
00619 
00620     else {        // this should not be executed (written only for debug purpouse)
00621         fprintf(stderr, "ERROR: invalid operative mode! Specify -t or -n\n");
00622         exit(3);
00623     }
00624 
00625     // close dtn-handle -- IN DTN_2.1.1 SIMPLY RETURNS -1
00626     if (debug) printf("[debug] closing DTN handle...");
00627     if (dtn_close(handle) != DTN_SUCCESS)
00628     {
00629         fprintf(stderr, "fatal error closing dtn handle: %s\n",
00630                 strerror(errno));
00631         exit(1);
00632     }
00633     if (debug) printf(" done\n");
00634 
00635     // final carriage return
00636     printf("\n");
00637 
00638     return 0;
00639 } // end main
00640 
00641 
00642 
00643 /* ----------------------------------------
00644  *           UTILITY FUNCTIONS
00645  * ---------------------------------------- */
00646 
00647 /* ----------------------------
00648  * print_usage
00649  * ---------------------------- */
00650 void print_usage(char* progname)
00651 {
00652     fprintf(stderr, "\nSYNTAX: %s "
00653             "-d <dest_eid> "
00654             "[-t <sec> | -n <num>] [options]\n\n", progname);
00655     fprintf(stderr, "where:\n");
00656     fprintf(stderr, " -d <eid> destination eid (required)\n");
00657     fprintf(stderr, " -t <sec> Time-Mode: seconds of transmission\n");
00658     fprintf(stderr, " -n <num> Data-Mode: number of MBytes to send\n");
00659     fprintf(stderr, "Options common to both Time and Data Mode:\n");
00660     fprintf(stderr, " -p <size> size in KBytes of bundle payload\n");
00661     fprintf(stderr, " -r <eid> reply-to eid (if none specified, source tuple is used)\n");
00662     fprintf(stderr, "Data-Mode options:\n");
00663     fprintf(stderr, " -m use memory instead of file\n");
00664     fprintf(stderr, " -B <num> number of consecutive transmissions (default 1)\n");
00665     fprintf(stderr, " -S <sec> sleeping seconds between consecutive transmissions (default 1)\n");
00666     fprintf(stderr, "Other options:\n");
00667     fprintf(stderr, " -c CSV output (useful with redirection of the output to a file)\n");
00668     fprintf(stderr, " -h help: show this message\n");
00669     fprintf(stderr, " -v verbose\n");
00670     fprintf(stderr, " -D debug messages (many)\n");
00671     fprintf(stderr, " -F enables forwarding receipts\n");
00672     fprintf(stderr, " -R enables receive receipts\n");
00673     fprintf(stderr, "\n");
00674     exit(1);
00675 } // end print_usage
00676 
00677 
00678 /* ----------------------------
00679  * parse_options
00680  * ---------------------------- */
00681 void parse_options(int argc, char**argv)
00682 {
00683     char c, done = 0;
00684 
00685     while (!done)
00686     {
00687         c = getopt(argc, argv, "hvDcmr:d:i:t:p:n:S:B:FRf:");
00688         switch (c)
00689         {
00690         case 'v':
00691             verbose = 1;
00692             break;
00693         case 'h':
00694             print_usage(argv[0]);
00695             exit(0);
00696             return;
00697         case 'c':
00698             csv_out = 1;
00699             break;
00700         case 'r':
00701             arg_replyto = optarg;
00702             break;
00703         case 'd':
00704             arg_dest = optarg;
00705             break;
00706         case 'i':
00707             regid = atoi(optarg);
00708             break;
00709         case 'D':
00710             debug = 1;
00711             break;
00712         case 't':
00713             op_mode = 't';
00714             transmission_time = atoi(optarg);
00715             break;
00716         case 'n':
00717             op_mode = 'd';
00718             n_arg = optarg;
00719             data_unit = findDataUnit(n_arg);
00720             switch (data_unit) {
00721                 case 'B':
00722                     data_qty = atol(n_arg);
00723                     break;
00724                 case 'K':
00725                     data_qty = kilo2byte(atol(n_arg));
00726                     break;
00727                 case 'M':
00728                     data_qty = mega2byte(atol(n_arg));
00729                     break;
00730                 default:
00731                     printf("\nWARNING: (-n option) invalid data unit, assuming 'M' (MBytes)\n\n");
00732                     data_qty = mega2byte(atol(n_arg));
00733                     break;
00734             }
00735             break;
00736         case 'p':
00737             p_arg = optarg;
00738             data_unit = findDataUnit(p_arg);
00739             switch (data_unit) {
00740                 case 'B':
00741                     bundle_payload = atol(p_arg);
00742                     break;
00743                 case 'K':
00744                     bundle_payload = kilo2byte(atol(p_arg));
00745                     break;
00746                 case 'M':
00747                     bundle_payload = mega2byte(atol(p_arg));
00748                     break;
00749                 default:
00750                     printf("\nWARNING: (-p option) invalid data unit, assuming 'K' (KBytes)\n\n");
00751                     bundle_payload = kilo2byte(atol(p_arg));
00752                     break;
00753             }
00754             break;
00755         case 'B':
00756             n_copies = atoi(optarg);
00757             break;
00758         case 'S':
00759             sleepVal = atoi(optarg);
00760             break;
00761 
00762         case 'f':
00763             use_file = 1;
00764             file_name_src = strdup(optarg);
00765             break;
00766 
00767         case 'm':
00768             use_file = 0;
00769             payload_type = DTN_PAYLOAD_MEM;
00770             break;
00771 
00772         case 'F':
00773             forwarding_receipts = 1;
00774             break;
00775 
00776         case 'R':
00777             receive_receipts = 1;
00778             break;
00779 
00780         case -1:
00781             done = 1;
00782             break;
00783         default:
00784             // getopt already prints an error message for unknown option characters
00785             print_usage(argv[0]);
00786             exit(1);
00787         } // --switch
00788     } // -- while
00789 
00790 #define CHECK_SET(_arg, _what)                                          \
00791     if (_arg == 0) {                                                    \
00792         fprintf(stderr, "\nSYNTAX ERROR: %s must be specified\n", _what);      \
00793         print_usage(argv[0]);                                                  \
00794         exit(1);                                                        \
00795     }
00796     
00797     CHECK_SET(arg_dest,     "destination tuple");
00798     CHECK_SET(op_mode,      "-t or -n");
00799 } // end parse_options
00800 
00801 /* ----------------------------
00802  * check_options
00803  * ---------------------------- */
00804 void check_options() {
00805     // checks on values
00806     if (n_copies <= 0) {
00807         fprintf(stderr, "\nSYNTAX ERROR: (-B option) consecutive retransmissions should be a positive number\n\n");
00808         exit(2);
00809     }
00810     if (sleepVal < 0) {
00811         fprintf(stderr, "\nSYNTAX ERROR: (-S option) sleeping seconds should be a positive number\n\n");
00812         exit(2);
00813     }
00814     if ((op_mode == 't') && (transmission_time <= 0)) {
00815         fprintf(stderr, "\nSYNTAX ERROR: (-t option) you should specify a positive time\n\n");
00816         exit(2);
00817     }
00818     if ((op_mode == 'd') && (data_qty <= 0)) {
00819         fprintf(stderr, "\nSYNTAX ERROR: (-n option) you should send a positive number of MBytes (%ld)\n\n", data_qty);
00820         exit(2);
00821     }
00822     // checks on options combination
00823     if ((use_file) && (op_mode == 't')) {
00824         if (bundle_payload <= ILLEGAL_PAYLOAD) {
00825             bundle_payload = DEFAULT_PAYLOAD;
00826             fprintf(stderr, "\nWARNING (a): bundle payload set to %ld bytes\n", bundle_payload);
00827             fprintf(stderr, "(use_file && op_mode=='t' + payload <= %d)\n\n", ILLEGAL_PAYLOAD);
00828         }
00829     }
00830     if ((use_file) && (op_mode == 'd')) {
00831         if ((bundle_payload <= ILLEGAL_PAYLOAD) || (bundle_payload > data_qty)) {
00832             bundle_payload = data_qty;
00833             fprintf(stderr, "\nWARNING (b): bundle payload set to %ld bytes\n", bundle_payload);
00834             fprintf(stderr, "(use_file && op_mode=='d' + payload <= %d or > %ld)\n\n", ILLEGAL_PAYLOAD, data_qty);
00835         }
00836     }
00837     if ((!use_file) && (bundle_payload <= ILLEGAL_PAYLOAD) && (op_mode == 'd')) {
00838         if (data_qty <= MAX_MEM_PAYLOAD) {
00839             bundle_payload = data_qty;
00840             fprintf(stderr, "\nWARNING (c1): bundle payload set to %ld bytes\n", bundle_payload);
00841             fprintf(stderr, "(!use_file + payload <= %d + data_qty <= %d + op_mode=='d')\n\n",
00842                             ILLEGAL_PAYLOAD, MAX_MEM_PAYLOAD);
00843         }
00844         if (data_qty > MAX_MEM_PAYLOAD) {
00845             bundle_payload = MAX_MEM_PAYLOAD;
00846             fprintf(stderr, "(!use_file + payload <= %d + data_qty > %d + op_mode=='d')\n",
00847                             ILLEGAL_PAYLOAD, MAX_MEM_PAYLOAD);
00848             fprintf(stderr, "\nWARNING (c2): bundle payload set to %ld bytes\n\n", bundle_payload);
00849         }
00850     }
00851     if ((!use_file) && (op_mode == 't')) {
00852         if (bundle_payload <= ILLEGAL_PAYLOAD) {
00853             bundle_payload = DEFAULT_PAYLOAD;
00854             fprintf(stderr, "\nWARNING (d1): bundle payload set to %ld bytes\n\n", bundle_payload);
00855             fprintf(stderr, "(!use_file + payload <= %d + op_mode=='t')\n\n", ILLEGAL_PAYLOAD);
00856         }
00857         if (bundle_payload > MAX_MEM_PAYLOAD) {
00858             fprintf(stderr, "\nWARNING (d2): bundle payload was set to %ld bytes, now set to %ld bytes\n",
00859                     bundle_payload, (long)DEFAULT_PAYLOAD);
00860             bundle_payload = DEFAULT_PAYLOAD;
00861             fprintf(stderr, "(!use_file + payload > %d)\n\n", MAX_MEM_PAYLOAD);
00862         }
00863     }
00864     if ((csv_out == 1) && ((verbose == 1) || (debug == 1))) {
00865         fprintf(stderr, "\nSYNTAX ERROR: (-c option) you cannot use -v or -D together with CSV output\n\n");
00866         exit(2);
00867     }
00868     if ((op_mode == 't') && (n_copies != 1)) {
00869         fprintf(stderr, "\nSYNTAX ERROR: you cannot use -B option in Time-Mode\n\n");
00870         exit(2);
00871     }
00872     if ((op_mode == 't') && (sleepVal != 0)) {
00873         fprintf(stderr, "\nSYNTAX ERROR: you cannot use -S option in Time-Mode\n\n");
00874         exit(2);
00875     }
00876 } // end check_options
00877 
00878 
00879 /* ----------------------------
00880  * show_options
00881  * ---------------------------- */
00882 void show_options() {
00883     printf("\nRequested");
00884     if (op_mode == 't')
00885         printf(" %d second(s) of transmission\n", transmission_time);
00886     if (op_mode == 'd') {
00887         printf(" %ld byte(s) to be transmitted %d time(s) every %d second(s)\n", 
00888                 data_qty, n_copies, sleepVal);
00889     }
00890     printf(" payload of each bundle = %ld byte(s)", bundle_payload);
00891     printf("\n\n");
00892 }
00893 
00894 
00895 /* ----------------------------
00896  * parse_eid
00897  * ---------------------------- */
00898 dtn_endpoint_id_t* parse_eid(dtn_handle_t handle, dtn_endpoint_id_t* eid, char * str)
00899 {
00900     // try the string as an actual dtn tuple
00901     if (!dtn_parse_eid_string(eid, str)) 
00902     {
00903 //        if (verbose) fprintf(stdout, "%s (literal)\n", str);
00904         return eid;
00905     }
00906     // build a local tuple based on the configuration of our dtn
00907     // router plus the str as demux string
00908     else if (!dtn_build_local_eid(handle, eid, str))
00909     {
00910         if (verbose) fprintf(stdout, "%s (local)\n", str);
00911         return eid;
00912     }
00913     else
00914     {
00915         fprintf(stderr, "invalid eid string '%s'\n", str);
00916         exit(1);
00917     }
00918 } // end parse_eid
00919 
00920 
00921 /* ----------------------------
00922  * print_eid
00923  * ---------------------------- */
00924 void print_eid(char *  label, dtn_endpoint_id_t * eid)
00925 {
00926     printf("%s [%s]\n", label, eid->uri);
00927 } // end print_eid
00928 
00929 
00930 /* -------------------------------------------------------------------
00931  * pattern
00932  *
00933  * Initialize the buffer with a pattern of (index mod 10).
00934  * ------------------------------------------------------------------- */
00935 void pattern(char *outBuf, int inBytes) {
00936     assert (outBuf != NULL);
00937     while (inBytes-- > 0) {
00938         outBuf[inBytes] = (inBytes % 10) + '0';
00939     }
00940 } // end pattern
00941 
00942 
00943 /* -------------------------------------------------------------------
00944  * Set timestamp to the given seconds
00945  * ------------------------------------------------------------------- */
00946 struct timeval set( double sec ) {
00947     struct timeval mTime;
00948 
00949     mTime.tv_sec  = (long) sec;
00950     mTime.tv_usec = (long) ((sec - mTime.tv_sec) * 1000000);
00951 
00952     return mTime;
00953 } // end set
00954 
00955 
00956 /* -------------------------------------------------------------------
00957  * Add seconds to my timestamp.
00958  * ------------------------------------------------------------------- */
00959 struct timeval add( double sec ) {
00960     struct timeval mTime;
00961 
00962     mTime.tv_sec  += (long) sec;
00963     mTime.tv_usec += (long) ((sec - ((long) sec )) * 1000000);
00964 
00965     // watch for overflow
00966     if ( mTime.tv_usec >= 1000000 ) {
00967         mTime.tv_usec -= 1000000;
00968         mTime.tv_sec++;
00969     }
00970 
00971     assert( mTime.tv_usec >= 0  && mTime.tv_usec <  1000000 );
00972 
00973     return mTime;
00974 } // end add
00975 
00976 
00977 /* --------------------------------------------------
00978  * show_report
00979  * -------------------------------------------------- */
00980 void show_report (u_int buf_len, char* eid, struct timeval start, struct timeval end, int data) {
00981     double g_put;
00982 
00983     printf("got %d byte report from [%s]: time=%.1f ms - %d bytes sent",
00984                 buf_len,
00985                 eid,
00986                 ((double)(end.tv_sec - start.tv_sec) * 1000.0 + 
00987                 (double)(end.tv_usec - start.tv_usec)/1000.0),
00988                 data);
00989 
00990     // report goodput (bits transmitted / time)
00991     g_put = (data*8) / ((double)(end.tv_sec - start.tv_sec) * 1000.0 + 
00992                       (double)(end.tv_usec - start.tv_usec)/1000.0);
00993     printf(" (goodput = %.2f Kbit/s)\n", g_put);
00994 
00995     if (debug) {
00996         // report start - end time
00997         printf("[debug] started at %u sec - ended at %u sec\n", (u_int)start.tv_sec, (u_int)end.tv_sec);
00998     }
00999 } // end show_report
01000 
01001 
01002 /* --------------------------------------------------
01003  * csv_time_report
01004  * -------------------------------------------------- */
01005 void csv_time_report(int b_sent, int payload, struct timeval start, struct timeval end) {
01006     
01007     double g_put, data;
01008 
01009     data = b_sent * payload;
01010     
01011     g_put = (data*8) / ((double)(end.tv_sec - start.tv_sec) * 1000.0 + 
01012                       (double)(end.tv_usec - start.tv_usec)/1000.0);
01013 
01014     printf("%d,%d,%.1f,%d,%.2f\n", b_sent, 
01015                                    payload,
01016                                    ((double)(end.tv_sec - start.tv_sec) * 1000.0 + 
01017                                        (double)(end.tv_usec - start.tv_usec)/1000.0),
01018                                    (b_sent * payload),
01019                                    g_put);
01020 } // end csv_time_report
01021 
01022 
01023 /* --------------------------------------------------
01024  * csv_data_report
01025  * -------------------------------------------------- */
01026 void csv_data_report(int b_id, int payload, struct timeval start, struct timeval end) {
01027     // const char* time_hdr = "BUNDLES_ID,PAYLOAD,TIME,GOODPUT";
01028     double g_put;
01029     
01030     g_put = (payload*8) / ((double)(end.tv_sec - start.tv_sec) * 1000.0 + 
01031                       (double)(end.tv_usec - start.tv_usec)/1000.0);
01032 
01033     printf("%d,%d,%.1f,%.2f\n", b_id,
01034                                 payload,
01035                                 ((double)(end.tv_sec - start.tv_sec) * 1000.0 + 
01036                                        (double)(end.tv_usec - start.tv_usec)/1000.0),
01037                                 g_put);
01038 } // end csv_data_report
01039 
01040 
01041 /* ----------------------------------------------
01042  * bundles_needed
01043  * ---------------------------------------------- */
01044 long bundles_needed (long data, long pl) {
01045     long res = 0;
01046     ldiv_t r;
01047 
01048     r = ldiv(data, pl);
01049     res = r.quot;
01050     if (r.rem > 0)
01051         res += 1;
01052 
01053     return res;
01054 } // end bundles_needed
01055 
01056 
01057 /* ------------------------------------------
01058  * add_time
01059  * ------------------------------------------ */
01060 void add_time(struct timeval *tot_time, struct timeval part_time) {
01061     tot_time->tv_sec += part_time.tv_sec;
01062     tot_time->tv_usec += part_time.tv_sec;
01063 
01064     if (tot_time->tv_usec >= 1000000) {
01065         tot_time->tv_sec++;
01066         tot_time->tv_usec -= 1000000;
01067     }
01068 
01069 } // end add_time
01070 
01071 /* ------------------------------------------
01072  * mega2byte
01073  *
01074  * Converts MBytes into Bytes
01075  * ------------------------------------------ */
01076 long mega2byte(long n) {
01077     return (n * 1048576);
01078 } // end mega2byte
01079 
01080 /* ------------------------------------------
01081  * kilo2byte
01082  *
01083  * Converts KBytes into Bytes
01084  * ------------------------------------------ */
01085 long kilo2byte(long n) {
01086     return (n * 1024);
01087 } // end kilo2byte
01088 
01089 /* ------------------------------------------
01090  * findDataUnit
01091  *
01092  * Extracts the data unit from the given string.
01093  * If no unit is specified, returns 'Z'.
01094  * ------------------------------------------ */
01095 char findDataUnit(const char *inarg) {
01096     // units are B (Bytes), K (KBytes) and M (MBytes)
01097     const char unitArray[] = {'B', 'K', 'M'};
01098     char * unit = malloc(sizeof(char));
01099 
01100     if ((unit = strpbrk(inarg, unitArray)) == NULL) {
01101         unit = "Z";
01102     }
01103     return unit[0];
01104 } // end findUnit

Generated on Fri Dec 22 14:47:58 2006 for DTN Reference Implementation by  doxygen 1.5.1