dtncat.c

Go to the documentation of this file.
00001 /*
00002  * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By
00003  * downloading, copying, installing or using the software you agree to
00004  * this license. If you do not agree to this license, do not download,
00005  * install, copy or use the software.
00006  * 
00007  * Intel Open Source License 
00008  * 
00009  * Copyright (c) 2006 Intel Corporation. All rights reserved. 
00010  * 
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions are
00013  * met:
00014  * 
00015  *   Redistributions of source code must retain the above copyright
00016  *   notice, this list of conditions and the following disclaimer.
00017  * 
00018  *   Redistributions in binary form must reproduce the above copyright
00019  *   notice, this list of conditions and the following disclaimer in the
00020  *   documentation and/or other materials provided with the distribution.
00021  * 
00022  *   Neither the name of the Intel Corporation nor the names of its
00023  *   contributors may be used to endorse or promote products derived from
00024  *   this software without specific prior written permission.
00025  *  
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00027  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00028  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00029  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
00030  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00032  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00033  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00034  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00035  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00036  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037  */
00038 
00039 /*
00040  * dtncat: move stdin to bundles and vice-versa
00041  * resembles the nc (netcat) unix program
00042  * - kfall Apr 2006
00043  *
00044  *   Usage: dtncat [-options] -s EID -d EID
00045  *   dtncat -l -s EID -d EID
00046  */
00047 
00048 #include <stdio.h>
00049 #include <unistd.h>
00050 #include <errno.h>
00051 #include <strings.h>
00052 #include <string.h>
00053 #include <stdlib.h>
00054 #include <sys/time.h>
00055 #include <time.h>
00056 
00057 #include "dtn_api.h"
00058 
00059 char *progname;
00060 
00061 // global options
00062 int copies              = 1;    // the number of copies to send
00063 int verbose             = 0;
00064 
00065 // bundle options
00066 int expiration          = 3600; // expiration timer (default one hour)
00067 int delivery_receipts   = 0;    // request end to end delivery receipts
00068 int forwarding_receipts = 0;    // request per hop departure
00069 int custody             = 0;    // request custody transfer
00070 int custody_receipts    = 0;    // request per custodian receipts
00071 int receive_receipts    = 0;    // request per hop arrival receipt
00072 int wait_for_report     = 0;    // wait for bundle status reports
00073 int bundle_count        = -1;   // # bundles to receive (-l option)
00074 
00075 #define DEFAULT_BUNDLE_COUNT    1
00076 #define FAILURE_SCRIPT ""
00077 
00078 #ifdef MIN
00079 #undef MIN
00080 #endif
00081 #define MIN(a, b) ((a) < (b) ? (a) : (b))
00082 
00083 // specified options for bundle eids
00084 char * arg_replyto      = NULL;
00085 char * arg_source       = NULL;
00086 char * arg_dest         = NULL;
00087 char * arg_receive         = NULL;
00088 
00089 dtn_reg_id_t regid      = DTN_REGID_NONE;
00090 
00091 void parse_options(int, char**);
00092 dtn_endpoint_id_t * parse_eid(dtn_handle_t handle,
00093                               dtn_endpoint_id_t * eid,
00094                               char * str);
00095 void print_usage();
00096 void print_eid(FILE*, char * label, dtn_endpoint_id_t * eid);
00097 int fill_payload(dtn_bundle_payload_t* payload);
00098 
00099 FILE* info;     /* when -v option is used, write to here */
00100 #define REG_EXPIRE (60 * 60)
00101 char payload_buf[DTN_MAX_BUNDLE_MEM];
00102 
00103 int from_bundles_flag;
00104 
00105 void to_bundles();      // stdin -> bundles
00106 void from_bundles();    // bundles -> stdout
00107 void make_registration(dtn_reg_info_t*);
00108 
00109 dtn_handle_t handle;
00110 dtn_bundle_spec_t bundle_spec;
00111 dtn_bundle_spec_t reply_spec;
00112 dtn_bundle_payload_t primary_payload;
00113 dtn_bundle_payload_t reply_payload;
00114 dtn_bundle_id_t bundle_id;
00115 struct timeval start, end;
00116 
00117 
00118 int
00119 main(int argc, char** argv)
00120 {
00121 
00122     info = stderr;
00123     
00124     // force stdout to always be line buffered, even if output is
00125     // redirected to a pipe or file -- why? kf
00126     // setvbuf(stdout, (char *)NULL, _IOLBF, 0);
00127     
00128     parse_options(argc, argv);
00129 
00130     // open the ipc handle
00131     if (verbose)
00132         fprintf(info, "Opening connection to local DTN daemon\n");
00133 
00134     int err = dtn_open(&handle);
00135     if (err != DTN_SUCCESS) {
00136         fprintf(stderr, "%s: fatal error opening dtn handle: %s\n",
00137                 progname, dtn_strerror(err));
00138         exit(EXIT_FAILURE);
00139     }
00140 
00141     if (gettimeofday(&start, NULL) < 0) {
00142                 fprintf(stderr, "%s: gettimeofday(start) returned error %s\n",
00143                         progname, strerror(errno));
00144                 exit(EXIT_FAILURE);
00145     }
00146 
00147     if (from_bundles_flag)
00148             from_bundles();
00149     else
00150             to_bundles();
00151 
00152     dtn_close(handle);
00153     return (EXIT_SUCCESS);
00154 }
00155 
00156 
00157 /*
00158  * [bundles] -> stdout
00159  */
00160 
00161 void
00162 from_bundles()
00163 {
00164     int total_bytes = 0, i, ret;
00165     char *buffer;
00166     char s_buffer[BUFSIZ];
00167 
00168     dtn_reg_info_t reg;
00169     dtn_endpoint_id_t local_eid;
00170     dtn_bundle_spec_t receive_spec;
00171 
00172     parse_eid(handle, &local_eid, arg_receive);
00173 
00174     memset(&reg, 0, sizeof(reg));
00175     dtn_copy_eid(&reg.endpoint, &local_eid);
00176     make_registration(&reg);
00177 
00178     if (verbose)
00179             fprintf(info, "waiting to receive %d bundles using reg >%s<\n",
00180                             bundle_count, reg.endpoint.uri);
00181 
00182     // loop waiting for bundles
00183     for (i = 0; i < bundle_count; ++i) {
00184         size_t bytes = 0;
00185         u_int k;
00186         
00187         // read from network
00188         if ((ret = dtn_recv(handle, &receive_spec,
00189                 DTN_PAYLOAD_MEM, &primary_payload, -1)) < 0) {
00190             fprintf(stderr, "%s: error getting recv reply: %d (%s)\n",
00191                     progname, ret, dtn_strerror(dtn_errno(handle)));
00192             exit(EXIT_FAILURE);
00193         }
00194 
00195         bytes = primary_payload.dtn_bundle_payload_t_u.buf.buf_len;
00196         buffer =
00197           (char *) primary_payload.dtn_bundle_payload_t_u.buf.buf_val;
00198         total_bytes += bytes;
00199 
00200         // write to stdout
00201         if (fwrite(buffer, 1, bytes, stdout) != bytes) {
00202             fprintf(stderr, "%s: error writing to stdout\n",
00203                     progname);
00204             exit(EXIT_FAILURE);
00205         }
00206 
00207         if (!verbose) {
00208             continue;
00209         }
00210         
00211         fprintf(info, "%d bytes from [%s]: transit time=%d ms\n",
00212                primary_payload.dtn_bundle_payload_t_u.buf.buf_len,
00213                receive_spec.source.uri, 0);
00214 
00215         for (k=0; k < primary_payload.dtn_bundle_payload_t_u.buf.buf_len; k++) {
00216             if (buffer[k] >= ' ' && buffer[k] <= '~')
00217                 s_buffer[k%BUFSIZ] = buffer[k];
00218             else
00219                 s_buffer[k%BUFSIZ] = '.';
00220 
00221             if (k%BUFSIZ == 0) // new line every 16 bytes
00222             {
00223                 fprintf(info,"%07x ", k);
00224             }
00225             else if (k%2 == 0)
00226             {
00227                 fprintf(info," "); // space every 2 bytes
00228             }
00229                     
00230             fprintf(info,"%02x", buffer[k] & 0xff);
00231                     
00232             // print character summary (a la emacs hexl-mode)
00233             if (k%BUFSIZ == BUFSIZ-1)
00234             {
00235                 fprintf(info," |  %.*s\n", BUFSIZ, s_buffer);
00236             }
00237         }
00238 
00239         // print spaces to fill out the rest of the line
00240         if (k%BUFSIZ != BUFSIZ-1) {
00241             while (k%BUFSIZ != BUFSIZ-1) {
00242                 if (k%2 == 0) {
00243                     fprintf(info," ");
00244                 }
00245                 fprintf(info,"  ");
00246                 k++;
00247             }
00248             fprintf(info,"   |  %.*s\n",
00249               (int)primary_payload.dtn_bundle_payload_t_u.buf.buf_len%BUFSIZ, 
00250                    s_buffer);
00251         }
00252         fprintf(info,"\n");
00253     }
00254 }
00255 
00256 /*
00257  * stdout -> [bundles]
00258  */
00259 
00260 void
00261 to_bundles()
00262 {
00263 
00264     int bytes, ret;
00265     dtn_reg_info_t reg_report; /* for reports, if reqd */
00266         
00267     // initialize bundle spec
00268     memset(&bundle_spec, 0, sizeof(bundle_spec));
00269     parse_eid(handle, &bundle_spec.dest, arg_dest);
00270     parse_eid(handle, &bundle_spec.source, arg_source);
00271 
00272     if (arg_replyto == NULL) {
00273         dtn_copy_eid(&bundle_spec.replyto, &bundle_spec.source);
00274     } else {
00275         parse_eid(handle, &bundle_spec.replyto, arg_replyto);
00276     }
00277 
00278     if (verbose) {
00279         print_eid(info, "source_eid", &bundle_spec.source);
00280         print_eid(info, "replyto_eid", &bundle_spec.replyto);
00281         print_eid(info, "dest_eid", &bundle_spec.dest);
00282     }
00283 
00284     if (wait_for_report) {
00285         // make a registration for incoming reports
00286         memset(&reg_report, 0, sizeof(reg_report));
00287         dtn_copy_eid(&reg_report.endpoint, &bundle_spec.replyto);
00288         make_registration(&reg_report);
00289     }
00290     
00291     // set the dtn options
00292     bundle_spec.expiration = expiration;
00293     
00294     if (delivery_receipts) {
00295         // set the delivery receipt option
00296         bundle_spec.dopts |= DOPTS_DELIVERY_RCPT;
00297     }
00298 
00299     if (forwarding_receipts) {
00300         // set the forward receipt option
00301         bundle_spec.dopts |= DOPTS_FORWARD_RCPT;
00302     }
00303 
00304     if (custody) {
00305         // request custody transfer
00306         bundle_spec.dopts |= DOPTS_CUSTODY;
00307     }
00308 
00309     if (custody_receipts) {
00310         // request custody transfer
00311         bundle_spec.dopts |= DOPTS_CUSTODY_RCPT;
00312     }
00313 
00314     if (receive_receipts) {
00315         // request receive receipt
00316         bundle_spec.dopts |= DOPTS_RECEIVE_RCPT;
00317     }
00318     
00319 
00320     if ((bytes = fill_payload(&primary_payload)) < 0) {
00321         fprintf(stderr, "%s: error reading bundle data\n",
00322             progname);
00323         exit(EXIT_FAILURE);
00324     }
00325 
00326     memset(&bundle_id, 0, sizeof(bundle_id));
00327     if ((ret = dtn_send(handle, &bundle_spec, &primary_payload,
00328                         &bundle_id)) != 0) {
00329         fprintf(stderr, "%s: error sending bundle: %d (%s)\n",
00330             progname, ret, dtn_strerror(dtn_errno(handle)));
00331         exit(EXIT_FAILURE);
00332     }
00333 
00334     if (verbose)
00335         fprintf(info, "Read %d bytes from stdin and wrote to bundles\n",
00336                 bytes);
00337 
00338     if (wait_for_report) {
00339         memset(&reply_spec, 0, sizeof(reply_spec));
00340         memset(&reply_payload, 0, sizeof(reply_payload));
00341         
00342         // now we block waiting for any replies
00343         if ((ret = dtn_recv(handle, &reply_spec,
00344                             DTN_PAYLOAD_MEM, &reply_payload, -1)) < 0) {
00345             fprintf(stderr, "%s: error getting reply: %d (%s)\n",
00346                     progname, ret, dtn_strerror(dtn_errno(handle)));
00347             exit(EXIT_FAILURE);
00348         }
00349         if (gettimeofday(&end, NULL) < 0) {
00350             fprintf(stderr, "%s: gettimeofday(end) returned error %s\n",
00351                     progname, strerror(errno));
00352             exit(EXIT_FAILURE);
00353         }
00354     
00355         if (verbose)
00356             fprintf(info, "got %d byte report from [%s]: time=%.1f ms\n",
00357                reply_payload.dtn_bundle_payload_t_u.buf.buf_len,
00358                reply_spec.source.uri,
00359                ((double)(end.tv_sec - start.tv_sec) * 1000.0 + 
00360                 (double)(end.tv_usec - start.tv_usec)/1000.0));
00361     }
00362 }
00363 
00364 
00365 void print_usage()
00366 {
00367     fprintf(stderr, "To source bundles from stdin:\n");
00368     fprintf(stderr, "    usage: %s [opts] -s <source_eid> -d <dest_eid>\n",
00369             progname);
00370     fprintf(stderr, "To receive bundles to stdout:\n");
00371     fprintf(stderr, "    usage: %s [opts] -l <receive_eid>\n", progname);
00372 
00373     fprintf(stderr, "common options:\n");
00374     fprintf(stderr, " -v verbose\n");
00375     fprintf(stderr, " -h/H help\n");
00376     fprintf(stderr, "receive only options (-l option required):\n");
00377 
00378     fprintf(stderr, " -l <eid> receive bundles destined for eid (instead of sending)\n");
00379     fprintf(stderr, " -n <count> exit after count bundles received (-l option required)\n");
00380     fprintf(stderr, "send only options (-l option prohibited):\n");
00381     fprintf(stderr, " -s <eid|demux_string> source eid)\n");
00382     fprintf(stderr, " -d <eid|demux_string> destination eid)\n");
00383     fprintf(stderr, " -r <eid|demux_string> reply to eid)\n");
00384     fprintf(stderr, " -e <time> expiration time in seconds (default: one hour)\n");
00385     fprintf(stderr, " -i <regid> registration id for reply to\n");
00386     fprintf(stderr, " -c request custody transfer\n");
00387     fprintf(stderr, " -C request custody transfer receipts\n");
00388     fprintf(stderr, " -D request for end-to-end delivery receipt\n");
00389     fprintf(stderr, " -R request for bundle reception receipts\n");
00390     fprintf(stderr, " -F request for bundle forwarding receipts\n");
00391     fprintf(stderr, " -w wait for bundle status reports\n");
00392     
00393     return;
00394 }
00395 
00396 void
00397 parse_options(int argc, char**argv)
00398 {
00399     char c, done = 0;
00400     int lopts = 0, notlopts = 0;
00401 
00402     progname = argv[0];
00403 
00404     while (!done) {
00405         c = getopt(argc, argv, "l:vhHr:s:d:e:wDFRcCi:n:");
00406         switch (c) {
00407         case 'l':
00408             from_bundles_flag = 1;
00409             arg_receive = optarg;
00410             break;
00411         case 'v':
00412             verbose = 1;
00413             break;
00414         case 'h':
00415         case 'H':
00416             print_usage();
00417             exit(EXIT_SUCCESS);
00418             return;
00419         case 'r':
00420             arg_replyto = optarg;
00421             lopts++;
00422             break;
00423         case 's':
00424             arg_source = optarg;
00425             notlopts++;
00426             break;
00427         case 'd':
00428             arg_dest = optarg;
00429             notlopts++;
00430             break;
00431         case 'e':
00432             expiration = atoi(optarg);
00433             notlopts++;
00434             break;
00435         case 'w':
00436             wait_for_report = 1;
00437             notlopts++;
00438             break;
00439         case 'D':
00440             delivery_receipts = 1;
00441             notlopts++;
00442             break;
00443         case 'F':
00444             forwarding_receipts = 1;
00445             notlopts++;
00446             break;
00447         case 'R':
00448             receive_receipts = 1;
00449             notlopts++;
00450             break;
00451         case 'c':
00452             custody = 1;
00453             notlopts++;
00454             break;
00455         case 'C':
00456             custody_receipts = 1;
00457             notlopts++;
00458             break;
00459         case 'i':
00460             regid = atoi(optarg);
00461             notlopts++;
00462             break;
00463         case 'n':
00464             bundle_count = atoi(optarg);
00465             lopts++;
00466             break;
00467         case -1:
00468             done = 1;
00469             break;
00470         default:
00471             // getopt already prints an error message for unknown
00472             // option characters
00473             print_usage();
00474             exit(EXIT_FAILURE);
00475         }
00476     }
00477 
00478     if (from_bundles_flag && (notlopts > 0)) {
00479             fprintf(stderr, "%s: error: transmission options specified when using -l flag\n",
00480                         progname);
00481         print_usage();
00482         exit(EXIT_FAILURE);
00483     }
00484 
00485     if (!from_bundles_flag && (lopts > 0)) {
00486             fprintf(stderr, "%s: error: receive option specified but -l option not selected\n",
00487                         progname);
00488         print_usage();
00489         exit(EXIT_FAILURE);
00490     }
00491 
00492 
00493 #define CHECK_SET(_arg, _what)                                          \
00494     if (_arg == 0) {                                                    \
00495         fprintf(stderr, "%s: %s must be specified\n", progname, _what); \
00496         print_usage();                                                  \
00497         exit(EXIT_FAILURE);                                             \
00498     }
00499     
00500     if (!from_bundles_flag) {
00501             /* transmitting to bundles - no -l option */
00502             CHECK_SET(arg_source,   "source eid");
00503             CHECK_SET(arg_dest,     "destination eid");
00504     } else {
00505             /* receiving from bundles - -l option specified */
00506             CHECK_SET(arg_receive,  "receive eid");
00507             if (bundle_count == -1) {
00508                     bundle_count = DEFAULT_BUNDLE_COUNT;
00509             }
00510     }
00511 }
00512 
00513 dtn_endpoint_id_t *
00514 parse_eid(dtn_handle_t handle, dtn_endpoint_id_t* eid, char * str)
00515 {
00516     // try the string as an actual dtn eid
00517     if (!dtn_parse_eid_string(eid, str)) {
00518         if (verbose)
00519                 fprintf(info, "%s (literal)\n", str);
00520         return eid;
00521     } else if (!dtn_build_local_eid(handle, eid, str)) {
00522         // build a local eid based on the configuration of our dtn
00523         // router plus the str as demux string
00524         if (verbose) fprintf(info, "%s (local)\n", str);
00525         return eid;
00526     } else {
00527         fprintf(stderr, "invalid eid string '%s'\n", str);
00528         exit(EXIT_FAILURE);
00529     }
00530 }
00531 
00532 void
00533 print_eid(FILE *dest, char *  label, dtn_endpoint_id_t * eid)
00534 {
00535     fprintf(dest, "%s [%s]\n", label, eid->uri);
00536 }
00537 
00538 /*
00539  * read from stdin to get the payload
00540  */
00541 
00542 int
00543 fill_payload(dtn_bundle_payload_t* payload)
00544 {
00545 
00546    unsigned char buf[BUFSIZ];
00547    unsigned char *p = (unsigned char*) payload_buf;
00548    unsigned char *endp = p + sizeof(payload_buf);
00549    size_t n, total = 0;
00550    size_t maxread = sizeof(buf);
00551 
00552    while (1) {
00553        maxread = MIN((int)sizeof(buf), (endp-p));
00554        if ((n = fread(buf, 1, maxread, stdin)) == 0)
00555                break;
00556        memcpy(p, buf, n);
00557        p += n;
00558        total += n;
00559    }
00560    if (ferror(stdin))
00561        return (-1); 
00562 
00563    if (dtn_set_payload(payload, DTN_PAYLOAD_MEM, payload_buf, total) == DTN_ESIZE)
00564            return (-1);
00565    return(total);
00566 }
00567 
00568 void
00569 make_registration(dtn_reg_info_t* reginfo)
00570 {
00571         int ret;
00572 
00573         // try to find an existing registration to use
00574         ret = dtn_find_registration(handle, &reginfo->endpoint, &regid);
00575 
00576         if (ret == 0) {
00577 
00578             // found the registration, bind it to the handle
00579             if (dtn_bind(handle, regid) != DTN_SUCCESS) {
00580                 fprintf(stderr, "%s: error in bind (id=0x%x): %d (%s)\n",
00581                         progname, regid, ret, dtn_strerror(dtn_errno(handle)));
00582                 exit(EXIT_FAILURE);
00583             }
00584 
00585             return;
00586             
00587         } else if (dtn_errno(handle) == DTN_ENOTFOUND) {
00588             // fall through
00589 
00590         } else {
00591             fprintf(stderr, "%s: error in dtn_find_registration: %d (%s)\n",
00592                     progname, ret, dtn_strerror(dtn_errno(handle)));
00593             exit(EXIT_FAILURE);
00594         }
00595 
00596         // create a new dtn registration to receive bundles
00597         reginfo->regid = regid;
00598         reginfo->expiration = REG_EXPIRE;
00599         reginfo->failure_action = DTN_REG_DROP;
00600         reginfo->script.script_val = FAILURE_SCRIPT;
00601         reginfo->script.script_len = strlen(reginfo->script.script_val) + 1;
00602 
00603         if ((ret = dtn_register(handle, reginfo, &regid)) != 0) {
00604             fprintf(stderr, "%s: error creating registration (id=0x%x): %d (%s)\n",
00605                     progname, regid, ret, dtn_strerror(dtn_errno(handle)));
00606             exit(EXIT_FAILURE);
00607         }
00608     
00609         if (verbose)
00610             fprintf(info, "dtn_register succeeded, regid 0x%x\n", regid);
00611 }

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