dtncat.c

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

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