dtnperf-client.c

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

Generated on Sat Sep 8 08:36:16 2007 for DTN Reference Implementation by  doxygen 1.5.3