dtnrecv.c

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2004-2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
00015  */
00016 
00017 
00018 #include <stdio.h>
00019 #include <unistd.h>
00020 #include <errno.h>
00021 #include <strings.h>
00022 #include <string.h>
00023 #include <stdlib.h>
00024 #include <sys/time.h>
00025 #include "dtn_api.h"
00026 
00027 #define BUFSIZE 16
00028 
00029 const char *progname;
00030 
00031 int   verbose           = 0;            // verbose output
00032 int   quiet             = 0;            // quiet output
00033 char* endpoint          = NULL;         // endpoint for registration
00034 dtn_reg_id_t regid      = DTN_REGID_NONE;// registration id
00035 int   expiration        = 30;           // registration expiration time
00036 int   count             = 0;            // exit after count bundles received
00037 int   failure_action    = DTN_REG_DEFER;// registration delivery failure action
00038 char* failure_script    = "";           // script to exec
00039 int   register_only     = 0;            // register and quit
00040 int   change            = 0;            // change existing registration 
00041 int   unregister        = 0;            // remove existing registration 
00042 int   recv_timeout      = -1;           // timeout to dtn_recv call
00043 int   no_find_reg       = 0;            // omit call to dtn_find_registration
00044 
00045 void
00046 usage()
00047 {
00048     fprintf(stderr, "usage: %s [opts] <endpoint> \n", progname);
00049     fprintf(stderr, "options:\n");
00050     fprintf(stderr, " -v verbose\n");
00051     fprintf(stderr, " -q quiet\n");
00052     fprintf(stderr, " -h help\n");
00053     fprintf(stderr, " -d <eid|demux_string> endpoint id\n");
00054     fprintf(stderr, " -r <regid> use existing registration regid\n");
00055     fprintf(stderr, " -n <count> exit after count bundles received\n");
00056     fprintf(stderr, " -e <time> registration expiration time in seconds "
00057             "(default: one hour)\n");
00058     fprintf(stderr, " -f <defer|drop|exec> failure action\n");
00059     fprintf(stderr, " -F <script> failure script for exec action\n");
00060     fprintf(stderr, " -x call dtn_register and immediately exit\n");
00061     fprintf(stderr, " -c call dtn_change_registration and immediately exit\n");
00062     fprintf(stderr, " -u call dtn_unregister and immediately exit\n");
00063     fprintf(stderr, " -N don't try to find an existing registration\n");
00064     fprintf(stderr, " -t <timeout> timeout value for call to dtn_recv\n");
00065 }
00066 
00067 void
00068 parse_options(int argc, char**argv)
00069 {
00070     char c, done = 0;
00071 
00072     progname = argv[0];
00073 
00074     while (!done)
00075     {
00076         c = getopt(argc, argv, "vqhHd:r:e:f:F:xn:cuNt:");
00077         switch (c)
00078         {
00079         case 'v':
00080             verbose = 1;
00081             break;
00082         case 'q':
00083             quiet = 1;
00084             break;
00085         case 'h':
00086         case 'H':
00087             usage();
00088             exit(0);
00089             return;
00090         case 'r':
00091             regid = atoi(optarg);
00092             break;
00093         case 'e':
00094             expiration = atoi(optarg);
00095             break;
00096         case 'f':
00097             if (!strcasecmp(optarg, "defer")) {
00098                 failure_action = DTN_REG_DEFER;
00099 
00100             } else if (!strcasecmp(optarg, "drop")) {
00101                 failure_action = DTN_REG_DROP;
00102 
00103             } else if (!strcasecmp(optarg, "exec")) {
00104                 failure_action = DTN_REG_EXEC;
00105 
00106             } else {
00107                 fprintf(stderr, "invalid failure action '%s'\n", optarg);
00108                 usage();
00109                 exit(1);
00110             }
00111         case 'F':
00112             failure_script = optarg;
00113             break;
00114         case 'x':
00115             register_only = 1;
00116             break;
00117         case 'n':
00118             count = atoi(optarg);
00119             break;
00120         case 'c':
00121             change = 1;
00122             break;
00123         case 'u':
00124             unregister = 1;
00125             break;
00126         case 'N':
00127             no_find_reg = 1;
00128             break;
00129         case 't':
00130             recv_timeout = atoi(optarg);
00131             break;
00132         case -1:
00133             done = 1;
00134             break;
00135         default:
00136             // getopt already prints an error message for unknown
00137             // option characters
00138             usage();
00139             exit(1);
00140         }
00141     }
00142 
00143     endpoint = argv[optind];
00144     if (!endpoint && (regid == DTN_REGID_NONE)) {
00145         fprintf(stderr, "must specify either an endpoint or a regid\n");
00146         usage();
00147         exit(1);
00148     }
00149 
00150     if ((change || unregister) && (regid == DTN_REGID_NONE)) {
00151         fprintf(stderr, "must specify regid when using -%c option\n",
00152                 change ? 'c' : 'u');
00153         usage();
00154         exit(1);
00155     }
00156 
00157     if (failure_action == DTN_REG_EXEC && failure_script == NULL) {
00158         fprintf(stderr, "failure action EXEC must supply script\n");
00159         usage();
00160         exit(1);
00161     }
00162 }
00163 
00164 
00165 int
00166 main(int argc, char** argv)
00167 {
00168     int i;
00169     u_int k;
00170     int ret;
00171     int total_bytes = 0;
00172     dtn_handle_t handle;
00173     dtn_endpoint_id_t local_eid;
00174     dtn_reg_info_t reginfo;
00175     dtn_bundle_spec_t spec;
00176     dtn_bundle_payload_t payload;
00177     unsigned char* buffer;
00178     char s_buffer[BUFSIZE];
00179     int call_bind;
00180 
00181     // force stdout to always be line buffered, even if output is
00182     // redirected to a pipe or file
00183     setvbuf(stdout, (char *)NULL, _IOLBF, 0);
00184     
00185     progname = argv[0];
00186 
00187     parse_options(argc, argv);
00188 
00189     if (count == 0) { 
00190         printf("dtnrecv (pid %d) starting up\n", getpid());
00191     } else {
00192         printf("dtnrecv (pid %d) starting up -- count %u\n", getpid(), count);
00193     }
00194 
00195     // open the ipc handle
00196     if (verbose) printf("opening connection to dtn router...\n");
00197     int err = dtn_open(&handle);
00198     if (err != DTN_SUCCESS) {
00199         fprintf(stderr, "fatal error opening dtn handle: %s\n",
00200                 dtn_strerror(err));
00201         exit(1);
00202     }
00203     if (verbose) printf("opened connection to dtn router...\n");
00204 
00205     // if we're not given a regid, or we're in change mode, we need to
00206     // build up the reginfo
00207     memset(&reginfo, 0, sizeof(reginfo));
00208 
00209     if ((regid == DTN_REGID_NONE) || change)
00210     {
00211         // if the specified eid starts with '/', then build a local
00212         // eid based on the configuration of our dtn router plus the
00213         // demux string. otherwise make sure it's a valid one
00214         if (endpoint[0] == '/') {
00215             if (verbose) printf("calling dtn_build_local_eid.\n");
00216             dtn_build_local_eid(handle, &local_eid, (char *) endpoint);
00217             if (verbose) printf("local_eid [%s]\n", local_eid.uri);
00218         } else {
00219             if (verbose) printf("calling parse_eid_string\n");
00220             if (dtn_parse_eid_string(&local_eid, endpoint)) {
00221                 fprintf(stderr, "invalid destination endpoint '%s'\n",
00222                         endpoint);
00223                 goto err;
00224             }
00225         }
00226 
00227         // create a new registration based on this eid
00228         dtn_copy_eid(&reginfo.endpoint, &local_eid);
00229         reginfo.regid             = regid;
00230         reginfo.expiration        = expiration;
00231         reginfo.failure_action    = failure_action;
00232         reginfo.script.script_val = failure_script;
00233         reginfo.script.script_len = strlen(failure_script) + 1;
00234     }
00235 
00236     if (change) {
00237         if ((ret = dtn_change_registration(handle, regid, &reginfo)) != 0) {
00238             fprintf(stderr, "error changing registration: %d (%s)\n",
00239                     ret, dtn_strerror(dtn_errno(handle)));
00240             goto err;
00241         }
00242         printf("change registration succeeded, regid %d\n", regid);
00243         goto done;
00244     }
00245     
00246     if (unregister) {
00247         if (dtn_unregister(handle, regid) != 0) {
00248             fprintf(stderr, "error in unregister regid %d: %s\n",
00249                     regid, dtn_strerror(dtn_errno(handle)));
00250             goto err;
00251         }
00252         
00253         printf("unregister succeeded, regid %d\n", regid);
00254         goto done;
00255     }
00256     
00257     // try to see if there is an existing registration that matches
00258     // the given endpoint, in which case we'll use that one.
00259     if (regid == DTN_REGID_NONE && ! no_find_reg) {
00260         if (dtn_find_registration(handle, &local_eid, &regid) != 0) {
00261             if (dtn_errno(handle) != DTN_ENOTFOUND) {
00262                 fprintf(stderr, "error in find_registration: %s\n",
00263                         dtn_strerror(dtn_errno(handle)));
00264                 goto err;
00265             }
00266         }
00267         printf("find registration succeeded, regid %d\n", regid);
00268         call_bind = 1;
00269     }
00270     
00271     // if the user didn't give us a registration to use, get a new one
00272     if (regid == DTN_REGID_NONE) {
00273         if ((ret = dtn_register(handle, &reginfo, &regid)) != 0) {
00274             fprintf(stderr, "error creating registration: %d (%s)\n",
00275                     ret, dtn_strerror(dtn_errno(handle)));
00276             goto err;
00277         }
00278 
00279         printf("register succeeded, regid %d\n", regid);
00280         call_bind = 0;
00281     } else {
00282         call_bind = 1;
00283     }
00284     
00285     if (register_only) {
00286         goto done;
00287     }
00288 
00289     if (call_bind) {
00290         // bind the current handle to the found registration
00291         printf("binding to regid %d\n", regid);
00292         if (dtn_bind(handle, regid) != 0) {
00293             fprintf(stderr, "error binding to registration: %s\n",
00294                     dtn_strerror(dtn_errno(handle)));
00295             goto err;
00296         }
00297     }
00298 
00299     // loop waiting for bundles
00300     if (count == 0) {
00301         printf("looping forever to receive bundles\n");
00302     } else {
00303         printf("looping to receive %d bundles\n", count);
00304     }
00305     for (i = 0; (count == 0) || (i < count); ++i) {
00306         memset(&spec, 0, sizeof(spec));
00307         memset(&payload, 0, sizeof(payload));
00308 
00309         if (!quiet) {
00310             printf("dtn_recv [%s]...\n", local_eid.uri);
00311         }
00312     
00313         if ((ret = dtn_recv(handle, &spec,
00314                             DTN_PAYLOAD_MEM, &payload, recv_timeout)) < 0)
00315         {
00316             fprintf(stderr, "error getting recv reply: %d (%s)\n",
00317                     ret, dtn_strerror(dtn_errno(handle)));
00318             goto err;
00319         }
00320 
00321         total_bytes += payload.buf.buf_len;
00322 
00323         if (quiet) {
00324             dtn_free_payload(&payload);
00325             continue;
00326         }
00327         
00328         printf("%d bytes from [%s]: transit time=%d ms\n",
00329                payload.buf.buf_len,
00330                spec.source.uri, 0);
00331 
00332         buffer = (unsigned char *) payload.buf.buf_val;
00333         for (k=0; k < payload.buf.buf_len; k++)
00334         {
00335             if (buffer[k] >= ' ' && buffer[k] <= '~')
00336                 s_buffer[k%BUFSIZE] = buffer[k];
00337             else
00338                 s_buffer[k%BUFSIZE] = '.';
00339 
00340             if (k%BUFSIZE == 0) // new line every 16 bytes
00341             {
00342                 printf("%07x ", k);
00343             }
00344             else if (k%2 == 0)
00345             {
00346                 printf(" "); // space every 2 bytes
00347             }
00348                     
00349             printf("%02x", buffer[k] & 0xff);
00350                     
00351             // print character summary (a la emacs hexl-mode)
00352             if (k%BUFSIZE == BUFSIZE-1)
00353             {
00354                 printf(" |  %.*s\n", BUFSIZE, s_buffer);
00355             }
00356         }
00357 
00358         // print spaces to fill out the rest of the line
00359         if (k%BUFSIZE != BUFSIZE-1) {
00360             while (k%BUFSIZE != BUFSIZE-1) {
00361                 if (k%2 == 0) {
00362                     printf(" ");
00363                 }
00364                 printf("  ");
00365                 k++;
00366             }
00367             printf("   |  %.*s\n",
00368                    (int)payload.buf.buf_len%BUFSIZE, 
00369                    s_buffer);
00370         }
00371         printf("\n");
00372 
00373         dtn_free_payload(&payload);
00374     }
00375 
00376     printf("dtnrecv (pid %d) exiting: %d bundles received, %d total bytes\n\n",
00377            getpid(), i, total_bytes);
00378 
00379 done:
00380     dtn_close(handle);
00381     return 0;
00382 
00383 err:
00384     dtn_close(handle);
00385     return 1;
00386 }

Generated on Thu Jun 7 16:56:49 2007 for DTN Reference Implementation by  doxygen 1.5.1