apps/dtnquery/dtnquery.c
changeset 1 44c5e3fa6d30
child 8 ce3cb8a86959
equal deleted inserted replaced
0:2b3e5ec03512 1:44c5e3fa6d30
       
     1 /*
       
     2  *    Copyright 2004-2006 Intel Corporation
       
     3  * 
       
     4  *    Licensed under the Apache License, Version 2.0 (the "License");
       
     5  *    you may not use this file except in compliance with the License.
       
     6  *    You may obtain a copy of the License at
       
     7  * 
       
     8  *        http://www.apache.org/licenses/LICENSE-2.0
       
     9  * 
       
    10  *    Unless required by applicable law or agreed to in writing, software
       
    11  *    distributed under the License is distributed on an "AS IS" BASIS,
       
    12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    13  *    See the License for the specific language governing permissions and
       
    14  *    limitations under the License.
       
    15  */
       
    16 
       
    17 #ifdef HAVE_CONFIG_H
       
    18 #  include <dtn-config.h>
       
    19 #endif
       
    20 
       
    21 #include <stdio.h>
       
    22 #include <unistd.h>
       
    23 #include <errno.h>
       
    24 #include <strings.h>
       
    25 #include <string.h>
       
    26 #include <stdlib.h>
       
    27 #include <sys/time.h>
       
    28 #include <sys/stat.h>
       
    29 #include <fcntl.h>
       
    30 #include "dtn_api.h"
       
    31 #include "sdnv-c.h"
       
    32 
       
    33 #define BUFSIZE 16
       
    34 #define BLOCKSIZE 8192
       
    35 #define COUNTER_MAX_DIGITS 9
       
    36 
       
    37 // todo: move these out to a header file
       
    38 #define DTN_BPQ_LITERAL 1
       
    39 #define DTN_BPQ_BASE64 2
       
    40 #define DTN_BPQ_FILE 3
       
    41 
       
    42 #define DTN_BPQ_EXACT 1
       
    43 
       
    44 #define DTN_BPQ_SEND 1
       
    45 #define DTN_BPQ_RECV 2
       
    46 #define DTN_BPQ_SEND_RECV 3
       
    47 
       
    48 #define DTN_BPQ_BLOCK_TYPE 0xC8
       
    49 #define DTN_BPQ_BLOCK_FLAGS 0x00
       
    50 
       
    51 #define DTN_BPQ_KIND_QUERY 0x00
       
    52 #define DTN_BPQ_KIND_RESPONSE 0x01
       
    53 
       
    54 // Find the maximum commandline length
       
    55 #ifdef __FreeBSD__
       
    56 /* Needed for PATH_MAX, Linux doesn't need it */
       
    57 #include <sys/syslimits.h>
       
    58 #endif
       
    59 
       
    60 #ifndef PATH_MAX
       
    61 /* A conservative fallback */
       
    62 #define PATH_MAX 1024
       
    63 #endif
       
    64 
       
    65 //global variables
       
    66 const char* progname;
       
    67 
       
    68 /*******************************************************************************
       
    69 * usage:
       
    70 * display cmd line options to user.
       
    71 *******************************************************************************/
       
    72 int
       
    73 usage()
       
    74 {
       
    75     fprintf(stderr, "usage: %s -s < src endpoint > -d < dest endpoint > "
       
    76                     "[opts]\n", progname);
       
    77     fprintf(stderr, "options:\n");
       
    78     fprintf(stderr, " -f  < filename > response filename\n");
       
    79     fprintf(stderr, " -q  < query > query or matching file\n");
       
    80     fprintf(stderr, " -t  < literal | base64 | file > query type\n");
       
    81     fprintf(stderr, " -r  < exact > matching rule\n");
       
    82     fprintf(stderr, " -m  < send | receive | both > mode\n");
       
    83     fprintf(stderr, " -o  < seconds > timeout\n");
       
    84     fprintf(stderr, " -e  < seconds > bundle expiry time\n");
       
    85     fprintf(stderr, " -i  < regid > existing registration id\n");
       
    86     fprintf(stderr, " -E  < seconds > registration expiry time\n");
       
    87     fprintf(stderr, " -A  < defer | drop | exec > failure action\n");
       
    88     fprintf(stderr, " -S  < script > failure script for exec action\n");
       
    89     fprintf(stderr, " -P  < bulk | normal | expedited | reserved > priority\n");
       
    90     fprintf(stderr, " -D  request end-to-end delivery receipt\n");
       
    91     fprintf(stderr, " -X  request deletion receipt\n");
       
    92     fprintf(stderr, " -F  request bundle forwarding receipts\n");
       
    93     fprintf(stderr, " -R  request bundle reception receipts\n");
       
    94     fprintf(stderr, " -c  request custody transfer\n");
       
    95     fprintf(stderr, " -C  request custody transfer receipts\n");
       
    96     fprintf(stderr, " -1  assert destination endpoint is a singleton\n");
       
    97     fprintf(stderr, " -N  assert destination endpoint is not a singleton\n");
       
    98     fprintf(stderr, " -W  set the do not fragment option\n");
       
    99     fprintf(stderr, " -h  help\n");
       
   100     fprintf(stderr, " -v  verbose\n");
       
   101 
       
   102     return 0;
       
   103 }
       
   104 
       
   105 /*******************************************************************************
       
   106 * parse matching file
       
   107 * if matching file is passed in rather than cml line literal query,
       
   108 * extract relevant information by reading the csv file and splitting
       
   109 * it into tokens.
       
   110 *
       
   111 * Matching File Format:
       
   112 * [ matching_rule, encoding, query, response_path, expiry ]
       
   113 *******************************************************************************/
       
   114 int
       
   115 parse_matching_file(const char * filename,
       
   116     int * matching_rule,
       
   117     int * query_type,
       
   118     char * query,
       
   119     dtn_timeval_t * bundle_expiry,
       
   120     int verbose)
       
   121 {
       
   122     FILE * file;
       
   123     char * token;
       
   124     char line[PATH_MAX];
       
   125 
       
   126     memset(line, 0, sizeof(char) * PATH_MAX);
       
   127     
       
   128     if (verbose) fprintf(stdout, "openning matching file...\n");
       
   129     file = fopen(filename, "r");
       
   130     if (file == NULL) {
       
   131         fprintf(stderr, "Error opening file: %s", filename);
       
   132         return 1;    
       
   133     }
       
   134 
       
   135     fgets(line, PATH_MAX, file);
       
   136     if (verbose) fprintf(stdout, "matching file %s contains [ %s ]\n", filename, line);
       
   137 
       
   138     fclose(file);
       
   139     if (verbose) fprintf(stdout, "closed matching file...\n");
       
   140 
       
   141     //matching rule
       
   142     token = strtok (line, ",");
       
   143     if (token == NULL)  return 1;
       
   144     *matching_rule = atoi(token);        
       
   145 
       
   146     //encoding
       
   147     token = strtok (NULL, ",");
       
   148     if (token == NULL)  return 1;
       
   149     *query_type = atoi(token);
       
   150 
       
   151     //query
       
   152     token = strtok (NULL, ",");
       
   153     if (token == NULL)  return 1;
       
   154     strncpy(query, token, PATH_MAX);
       
   155 
       
   156     //response path - to be ignored
       
   157     token = strtok (NULL, ",");
       
   158     if (token == NULL)  return 1;
       
   159 
       
   160     //expiry
       
   161     token = strtok (NULL, ",");
       
   162     if (token == NULL)  return 1;
       
   163     *bundle_expiry = atoi(token);
       
   164 
       
   165     //ensure there are no more tokens
       
   166     token = strtok (NULL, ",");
       
   167     if (token != NULL)  return 1;
       
   168 
       
   169     return 0;
       
   170 }
       
   171 
       
   172 /*******************************************************************************
       
   173 * parse options:
       
   174 * set internal variables based on cmd line args.
       
   175 * calls parse matching file if required.
       
   176 * returns success or exits on failure.
       
   177 *******************************************************************************/
       
   178 int
       
   179 parse_options(int argc, char** argv,
       
   180     char * src_eid_name,                // s
       
   181     char * dest_eid_name,               // d
       
   182     char * filename,                    // f
       
   183     char * query,                       // q
       
   184     int * query_type,                   // t
       
   185     int * matching_rule,                // r
       
   186     int * mode,                         // m
       
   187     dtn_timeval_t * timeout,            // o
       
   188     dtn_timeval_t * bundle_expiry,      // e
       
   189     dtn_reg_id_t  * regid,              // i
       
   190     dtn_timeval_t * reg_expiry,         // E
       
   191     int  * reg_fail_action,             // A
       
   192     char * reg_fail_script,             // S
       
   193     dtn_bundle_priority_t * priority,   // P
       
   194     int * delivery_options,             // D X F R c C 1 N W
       
   195     int * verbose)                      // v
       
   196 {
       
   197     int c, done = 0;
       
   198     char matching_file[PATH_MAX];
       
   199 
       
   200     progname = argv[0];
       
   201 
       
   202     //initialize strings
       
   203     memset(src_eid_name,    0, sizeof(char) * PATH_MAX);
       
   204     memset(dest_eid_name,   0, sizeof(char) * PATH_MAX);
       
   205     memset(filename,        0, sizeof(char) * PATH_MAX);
       
   206     memset(query,           0, sizeof(char) * PATH_MAX);
       
   207     memset(matching_file,   0, sizeof(char) * PATH_MAX);
       
   208     memset(reg_fail_script, 0, sizeof(char) * PATH_MAX);
       
   209 
       
   210     while( !done )
       
   211     {
       
   212         c = getopt(argc, argv, "s:d:f:q:t:r:m:o:e:i:E:A:S:P:DXFcC1NWvhH");
       
   213         switch(c)
       
   214         {
       
   215         case 's':            
       
   216             strncpy(src_eid_name, optarg, PATH_MAX);
       
   217             break;
       
   218         case 'd':    
       
   219             strncpy(dest_eid_name, optarg, PATH_MAX);
       
   220             break;
       
   221         case 'f':    
       
   222             strncpy(filename, optarg, PATH_MAX);
       
   223             break;
       
   224         case 'q':            
       
   225             strncpy(query, optarg, PATH_MAX);
       
   226             break;
       
   227         case 't':
       
   228             if (!strcasecmp(optarg, "literal")) {
       
   229                 *query_type = DTN_BPQ_LITERAL;
       
   230                 break;
       
   231             } else if (!strcasecmp(optarg, "base64")) {
       
   232                 *query_type = DTN_BPQ_BASE64;
       
   233                 break;
       
   234             } else if (!strcasecmp(optarg, "file")) {
       
   235                 *query_type = DTN_BPQ_FILE;
       
   236                 break;
       
   237             } else {
       
   238                 fprintf(stderr, "invalid query type '%s'\n", optarg);
       
   239                 usage();
       
   240                 exit(1);
       
   241             }
       
   242         case 'r':
       
   243             if (!strcasecmp(optarg, "exact")) {
       
   244                 *matching_rule = DTN_BPQ_EXACT;
       
   245                 break;
       
   246             } else {
       
   247                 fprintf(stderr, "invalid query type '%s'\n", optarg);
       
   248                 usage();
       
   249                 exit(1);
       
   250             }
       
   251         case 'm':
       
   252             if (!strcasecmp(optarg, "send")) {
       
   253                 *mode = DTN_BPQ_SEND;
       
   254                 break;
       
   255             } else if (!strcasecmp(optarg, "receive")) {
       
   256                 *mode = DTN_BPQ_RECV;
       
   257                 break;
       
   258             } else if (!strcasecmp(optarg, "both")) {
       
   259                 *mode = DTN_BPQ_SEND_RECV;
       
   260                 break;
       
   261             } else {
       
   262                 fprintf(stderr, "invalid mode '%s'\n", optarg);
       
   263                 usage();
       
   264                 exit(1);
       
   265             }
       
   266         case 'o':
       
   267             *timeout = atoi(optarg);
       
   268             break;
       
   269         case 'e':
       
   270             *bundle_expiry = atoi(optarg);  
       
   271             break;
       
   272         case 'i':
       
   273             *regid = atoi(optarg);
       
   274             break;
       
   275         case 'E':
       
   276             *reg_expiry = atoi(optarg);
       
   277             break;
       
   278         case 'A':
       
   279             if (!strcasecmp(optarg, "defer")) {
       
   280                 *reg_fail_action = DTN_REG_DEFER;
       
   281 
       
   282             } else if (!strcasecmp(optarg, "drop")) {
       
   283                 *reg_fail_action = DTN_REG_DROP;
       
   284 
       
   285             } else if (!strcasecmp(optarg, "exec")) {
       
   286                 *reg_fail_action = DTN_REG_EXEC;
       
   287 
       
   288             } else {
       
   289                 fprintf(stderr, "invalid failure action '%s'\n", optarg);
       
   290                 usage();
       
   291                 exit(1);
       
   292             }
       
   293             break;
       
   294         case 'S':
       
   295             strncpy(reg_fail_script, optarg, PATH_MAX);
       
   296             break;
       
   297         case 'P':
       
   298             if (!strcasecmp(optarg, "bulk"))   {
       
   299                 *priority = COS_BULK;
       
   300             } else if (!strcasecmp(optarg, "normal")) {
       
   301                 *priority = COS_NORMAL;
       
   302             } else if (!strcasecmp(optarg, "expedited")) {
       
   303                 *priority = COS_EXPEDITED;
       
   304             } else if (!strcasecmp(optarg, "reserved")) {
       
   305                 *priority = COS_RESERVED;
       
   306             } else {
       
   307                 fprintf(stderr, "invalid priority value %s\n", optarg);
       
   308                 usage();
       
   309                 exit(1);
       
   310             }
       
   311             break;
       
   312         case 'D':
       
   313             *delivery_options |= DOPTS_DELIVERY_RCPT;
       
   314             break;
       
   315         case 'X':
       
   316             *delivery_options |= DOPTS_DELETE_RCPT;
       
   317             break;
       
   318         case 'F':
       
   319             *delivery_options |= DOPTS_FORWARD_RCPT;
       
   320             break;
       
   321         case 'R':
       
   322             *delivery_options |= DOPTS_RECEIVE_RCPT;
       
   323             break;
       
   324         case 'c':
       
   325             *delivery_options |= DOPTS_CUSTODY;
       
   326             break;
       
   327         case 'C':
       
   328             *delivery_options |= DOPTS_CUSTODY_RCPT;
       
   329             break;
       
   330         case '1':
       
   331             *delivery_options |= DOPTS_SINGLETON_DEST;
       
   332             break;
       
   333         case 'N':
       
   334             *delivery_options |= DOPTS_MULTINODE_DEST;
       
   335             break;
       
   336         case 'W':
       
   337             *delivery_options |= DOPTS_DO_NOT_FRAGMENT;
       
   338             break;
       
   339         case 'v':
       
   340             *verbose = 1;
       
   341             break;
       
   342         case 'h':
       
   343         case 'H':
       
   344             usage();
       
   345 
       
   346             exit(0);
       
   347         case -1:
       
   348             done = 1;
       
   349             break;
       
   350         default:
       
   351             // getopt already prints error message for unknown option characters
       
   352             usage();
       
   353             exit(1);
       
   354         }
       
   355         
       
   356         // now set matching file if required
       
   357         if (*query_type == DTN_BPQ_FILE) {
       
   358             strncpy(matching_file, query, PATH_MAX);
       
   359             memset(query, 0, sizeof(char) * PATH_MAX);
       
   360 
       
   361             int ret = parse_matching_file(matching_file, matching_rule,
       
   362                                           query_type, query, bundle_expiry, *verbose);
       
   363             if (ret != DTN_SUCCESS) {
       
   364                 fprintf(stderr, "error parsing matching file, "
       
   365                                 "see man page dtnmatch(1)\n");
       
   366                 usage(1);
       
   367                 exit(1);
       
   368             }
       
   369         }
       
   370     }
       
   371     return 0;
       
   372 }
       
   373 
       
   374 /*******************************************************************************
       
   375 * validate options:
       
   376 * as there are different requirements depending on the mode,
       
   377 * the validation will differ accordingly.
       
   378 * returns success or exits on failure
       
   379 *******************************************************************************/
       
   380 int
       
   381 validate_options(const char * src_eid_name,
       
   382     const char * dest_eid_name,
       
   383     const char * filename,
       
   384     const char * query,
       
   385     int query_type,
       
   386     int matching_rule,
       
   387     int mode,
       
   388     dtn_timeval_t timeout,
       
   389     dtn_timeval_t bundle_expiry)
       
   390 {
       
   391 //todo: add new options
       
   392 #define REQUIRE(test, err_msg) \
       
   393     if(!test) { \
       
   394         fprintf(stderr, err_msg); \
       
   395         usage(); \
       
   396         exit(1); \
       
   397     }
       
   398 
       
   399     switch (mode)
       
   400     {
       
   401     case DTN_BPQ_SEND:  //requires src, dest, query
       
   402         REQUIRE(strlen(src_eid_name) > 0, "-s <src eid> required\n");
       
   403         REQUIRE(strlen(dest_eid_name) > 0, "-d <dest eid> required\n");
       
   404         REQUIRE(strlen(query) > 0, "-q <query> required\n");
       
   405         break;
       
   406 
       
   407     case DTN_BPQ_RECV:  //requires src, filename
       
   408         REQUIRE(strlen(src_eid_name) > 0, "-s <src eid> required\n");
       
   409         REQUIRE(strlen(filename) > 0, "-f <filename> required\n");
       
   410         break;
       
   411 
       
   412     case DTN_BPQ_SEND_RECV: //requires src, dest, query, filename
       
   413         REQUIRE(strlen(src_eid_name) > 0, "-s <src eid> required\n");
       
   414         REQUIRE(strlen(dest_eid_name) > 0, "-d <dest eid> required\n");
       
   415         REQUIRE(strlen(filename) > 0, "-f <filename> required\n");
       
   416         REQUIRE(strlen(query) > 0, "-q <query> required\n");
       
   417         break;
       
   418     default:  
       
   419         REQUIRE(mode == DTN_BPQ_SEND ||
       
   420                 mode == DTN_BPQ_RECV ||
       
   421                 mode == DTN_BPQ_SEND_RECV, "-m <mode> invalid mode\n")
       
   422     }
       
   423     REQUIRE(query_type == DTN_BPQ_LITERAL ||
       
   424             query_type == DTN_BPQ_BASE64  ||
       
   425             query_type == DTN_BPQ_FILE, "-t <query type> invalid type\n");
       
   426 
       
   427     REQUIRE(matching_rule == DTN_BPQ_EXACT, "-r <matching rule> invalid rule\n");
       
   428 fprintf(stdout, "timeout: %d, REQUIRE(timeout >= -1): %d\n", timeout, timeout >= -1);
       
   429 //    REQUIRE(timeout >= -1, "-o <timeout> must ba a positive integer or -1: forever\n");
       
   430     REQUIRE(bundle_expiry > 0, "-e <expiry> must be a positive integer\n");
       
   431 #undef REQUIRE
       
   432 //todo: check this is ok
       
   433     return 0;
       
   434 }
       
   435 
       
   436 /*******************************************************************************
       
   437 * register with dtn:
       
   438 * 
       
   439 *******************************************************************************/
       
   440 int
       
   441 register_with_dtn(dtn_handle_t handle,
       
   442     dtn_endpoint_id_t * src_eid,
       
   443     dtn_reg_id_t * regid,
       
   444     dtn_timeval_t reg_expiration,
       
   445     int reg_fail_action,
       
   446     char * reg_fail_script)
       
   447 {
       
   448     int call_bind = 0;
       
   449     dtn_reg_info_t reginfo;
       
   450 
       
   451     // if no regid has been given we need to create a new registration
       
   452     if (*regid == DTN_REGID_NONE) {
       
   453         memset(&reginfo, 0, sizeof(dtn_reg_info_t));
       
   454 
       
   455         // create a new registration based on this eid
       
   456         dtn_copy_eid(&reginfo.endpoint, src_eid);
       
   457         reginfo.regid             = *regid;
       
   458         reginfo.expiration        = reg_expiration;
       
   459         reginfo.flags             = reg_fail_action;
       
   460         reginfo.script.script_val = reg_fail_script;
       
   461         reginfo.script.script_len = strlen(reg_fail_script) + 1;
       
   462     }
       
   463 
       
   464     // try to see if there is an existing registration that matches
       
   465     // the given endpoint, in which case we'll use that one.
       
   466     if (*regid == DTN_REGID_NONE) {
       
   467         fprintf(stdout, "### src_eid: %s, regid: %d  ###\n", src_eid->uri, *regid);
       
   468         if (dtn_find_registration(handle, src_eid, regid) != DTN_SUCCESS &&
       
   469             dtn_errno(handle) != DTN_ENOTFOUND) {
       
   470             fprintf(stderr, "error finding registration: %s\n",
       
   471                     dtn_strerror(dtn_errno(handle)));
       
   472             dtn_close(handle);
       
   473             exit(1);
       
   474         }
       
   475         call_bind = 1;
       
   476     }
       
   477     // if the user didn't give us a registration to use, get a new one
       
   478     if (*regid == DTN_REGID_NONE) {
       
   479         if (dtn_register(handle, &reginfo, regid) != DTN_SUCCESS) {
       
   480             fprintf(stderr, "error registering: %s\n",
       
   481                     dtn_strerror(dtn_errno(handle)));
       
   482             dtn_close(handle);
       
   483             exit(1);
       
   484         }
       
   485         call_bind = 0;
       
   486     } else {
       
   487         call_bind = 1;
       
   488     }
       
   489 
       
   490     if (call_bind) {
       
   491         // bind the current handle to the found registration
       
   492         if (dtn_bind(handle, *regid) != DTN_SUCCESS) {
       
   493             fprintf(stderr, "error binding to registration: %s\n",
       
   494                     dtn_strerror(dtn_errno(handle)));
       
   495             dtn_close(handle);
       
   496             exit(1);
       
   497         }
       
   498     }
       
   499 
       
   500     return DTN_SUCCESS;
       
   501 }
       
   502 
       
   503 /*******************************************************************************
       
   504 * parse eid:
       
   505 *  
       
   506 * code lifted from dtnsend
       
   507 * todo: check this
       
   508 *******************************************************************************/
       
   509 dtn_endpoint_id_t *
       
   510 parse_eid(dtn_handle_t handle,
       
   511     dtn_endpoint_id_t * eid,
       
   512     const char * str,
       
   513     int verbose)
       
   514 {
       
   515     // try the string as an actual dtn eid
       
   516     if (dtn_parse_eid_string(eid, str) == DTN_SUCCESS) {
       
   517         if (verbose) fprintf(stdout, "%s (literal)\n", str);
       
   518         return eid;
       
   519     }
       
   520 
       
   521     // build a local eid based on the configuration of our dtn
       
   522     // router plus the str as demux string
       
   523     else if (dtn_build_local_eid(handle, eid, str) == DTN_SUCCESS) {
       
   524         if (verbose) fprintf(stdout, "%s (local)\n", str);
       
   525         return eid;
       
   526     }
       
   527     else {
       
   528         fprintf(stderr, "invalid eid string '%s'\n", str);
       
   529         exit(1);
       
   530     }
       
   531 }
       
   532 
       
   533 /*******************************************************************************
       
   534 * handle file transfer:
       
   535 * 
       
   536 *******************************************************************************/
       
   537 int
       
   538 handle_file_transfer(dtn_bundle_spec_t bundle_spec,
       
   539     dtn_bundle_payload_t payload,
       
   540     const char * filename,
       
   541     int verbose)
       
   542 {
       
   543     int i;
       
   544     char line[PATH_MAX];
       
   545     char new_filename[PATH_MAX];
       
   546     FILE * output_file = NULL;
       
   547     FILE * input_file = NULL;
       
   548 
       
   549     strncpy(new_filename, filename, PATH_MAX);
       
   550 
       
   551     // try to open file (need to find a filename + version that does not already exist)
       
   552     // if it does exist, close, create new filename + version and try to reopen
       
   553     // return error if can't find a valid filename after 100 attempts
       
   554     output_file = fopen(new_filename, "r");
       
   555     for (i=0; output_file != NULL; ++i) {
       
   556         fclose(output_file);
       
   557 
       
   558         if (i >= 100)
       
   559             return -1;
       
   560 
       
   561         snprintf(new_filename, PATH_MAX, "%s.%02d", filename, i);
       
   562         output_file = fopen(new_filename, "r");
       
   563     }
       
   564 
       
   565     if (verbose) fprintf(stdout, "saving payload file as: %s\n", new_filename);
       
   566 
       
   567     // new_filename now contains the name of the 
       
   568     // new file in which to store the payload
       
   569     if ((output_file = fopen(new_filename, "w")) == NULL) {
       
   570         fprintf(stderr, "error opening file in which to store received payload\n");
       
   571         return -1;
       
   572     }
       
   573   
       
   574     if ((input_file = fopen(payload.filename.filename_val, "r")) == NULL) {
       
   575         fprintf(stderr, "error opening the received payload file\n");
       
   576         return -1;
       
   577     }
       
   578 
       
   579     // copy payload to file
       
   580     while (fgets(line, PATH_MAX, input_file) != NULL) 
       
   581         fprintf(output_file, "%s", line);
       
   582         
       
   583     fclose(input_file);
       
   584     fclose(output_file);
       
   585 
       
   586     return 0;
       
   587 }
       
   588 
       
   589 /*******************************************************************************
       
   590 * bpq to char array:
       
   591 * encode as SDNVs,
       
   592 *   BPQ-kind             1-byte
       
   593 *   matching rule type   1-byte
       
   594 *   BPQ-value-length     SDNV
       
   595 *   BPQ-value            n-bytes
       
   596 *   number of fragments  SDNV
       
   597 *   fragment offsets     SDNV
       
   598 *   fragment lengths     SDNV
       
   599 *
       
   600 * @return The number of bytes or -1 on error
       
   601 *******************************************************************************/
       
   602 int
       
   603 bpq_to_char_array(const dtn_bpq_extension_block_data_t * bpq, char* buf, size_t buf_len)
       
   604 {
       
   605     int i=0, j=0, k=0;
       
   606     int encoding_len;    
       
   607     char encoding[PATH_MAX];
       
   608 
       
   609     memset(buf, 0, buf_len);
       
   610 
       
   611     // BPQ-kind             1-byte
       
   612     if (i < buf_len)    buf[i++] = (char) bpq->kind;
       
   613 
       
   614     // matching rule type   1-byte
       
   615     if (i < buf_len)    buf[i++] = (char) bpq->matching_rule;
       
   616 
       
   617     // BPQ-value-length     SDNV
       
   618     if ( (encoding_len = sdnv_encode (bpq->query.query_len, encoding, PATH_MAX)) == -1 )
       
   619         return -1;
       
   620     for (j=0; i<buf_len && j<encoding_len; ++j)
       
   621         buf[i++] = encoding[j];
       
   622 
       
   623     // BPQ-value            n-bytes
       
   624     for (j=0; i<buf_len && j<bpq->query.query_len; ++j)
       
   625         buf[i++] = bpq->query.query_val[j];
       
   626 
       
   627     // number of fragments  SDNV
       
   628     if ( (encoding_len = sdnv_encode (bpq->fragments.num_frag_returned, encoding, PATH_MAX)) == -1 )
       
   629         return -1;
       
   630     for (j=0; i<buf_len && j<encoding_len; ++j)
       
   631         buf[i++] = encoding[j];
       
   632 
       
   633     
       
   634     for (k=0; k<bpq->fragments.num_frag_returned; ++k) {
       
   635 
       
   636         // fragment offsets     SDNV
       
   637         if ( (encoding_len = sdnv_encode (bpq->fragments.frag_offsets[k], encoding, PATH_MAX)) == -1 )
       
   638             return -1;
       
   639         for (j=0; i<buf_len && j<encoding_len; ++j)
       
   640             buf[i++] = encoding[j];
       
   641 
       
   642         // fragment lengths     SDNV
       
   643         if ( (encoding_len = sdnv_encode (bpq->fragments.frag_lenghts[k], encoding, PATH_MAX)) == -1 )
       
   644             return -1;
       
   645         for (j=0; i<buf_len && j<encoding_len; ++j)
       
   646             buf[i++] = encoding[j];
       
   647     }
       
   648 
       
   649     
       
   650     return i;
       
   651 }
       
   652 /*******************************************************************************
       
   653 * char array to bpq:
       
   654 * decode as SDNVs,
       
   655 *   BPQ-kind             1-byte
       
   656 *   matching rule type   1-byte
       
   657 *   BPQ-value-length     SDNV
       
   658 *   BPQ-value            n-bytes
       
   659 *   number of fragments  SDNV
       
   660 *   fragment offsets     SDNV
       
   661 *   fragment lengths     SDNV
       
   662 *
       
   663 * @return DTN_SUCCESS or -1 on error
       
   664 *******************************************************************************/
       
   665 int
       
   666 char_array_to_bpq(const char* buf, size_t buf_len, dtn_bpq_extension_block_data_t * bpq) 
       
   667 {
       
   668     int i=0, j=0;
       
   669     int decoding_len=0;
       
   670 
       
   671     // BPQ-kind             1-byte
       
   672     if (i<buf_len) bpq->kind = (u_int) buf[i++];
       
   673 
       
   674     // matching rule type   1-byte
       
   675     if (i<buf_len) bpq->matching_rule = (u_int) buf[i++];
       
   676 
       
   677     // BPQ-value-length     SDNV
       
   678     if ( (decoding_len = sdnv_decode (buf[i], buf_len - i, &(bpq->query.query_len))) == -1 )
       
   679         return -1;
       
   680     i += decoding_len;
       
   681 
       
   682     // BPQ-value            n-bytes
       
   683     if (i<buf_len) bpq->query.query_val = &(buf[i]);
       
   684     i += bpq->query.query_len;
       
   685 
       
   686     // number of fragments  SDNV
       
   687     if ( (decoding_len = sdnv_decode (buf[i], buf_len - i, &(bpq->fragments.num_frag_returned))) == -1 )
       
   688         return -1;
       
   689     i += decoding_len;
       
   690 
       
   691     for (j=0; i<buf_len && j<bpq->fragments.num_frag_returned; ++j) {
       
   692 
       
   693         // fragment offsets     SDNV
       
   694         if ( (decoding_len = sdnv_decode (buf[i], buf_len - i, &(bpq->fragments.frag_offsets[j]))) == -1 )
       
   695             return -1;
       
   696         i += decoding_len;
       
   697 
       
   698         // fragment lengths     SDNV
       
   699         if ( (decoding_len = sdnv_decode (buf[i], buf_len - i, &(bpq->fragments.frag_lenghts[j]))) == -1 )
       
   700             return -1;
       
   701         i += decoding_len;
       
   702     }
       
   703 
       
   704     if (i != buf_len)
       
   705         return -1;
       
   706 
       
   707     return DTN_SUCCESS;
       
   708 }
       
   709 
       
   710 /*******************************************************************************
       
   711 * send bpq:
       
   712 * given a registration handle, build a bundle with
       
   713 * a BPQ extension block and an empty payload and 
       
   714 * send it to the destination.
       
   715 *******************************************************************************/
       
   716 int
       
   717 send_bpq(dtn_handle_t handle,
       
   718     dtn_reg_id_t regid,
       
   719     const dtn_endpoint_id_t * src_eid,
       
   720     const dtn_endpoint_id_t * dest_eid,
       
   721     char * query,
       
   722     int matching_rule,
       
   723     int bundle_expiry,
       
   724     dtn_bundle_priority_t  priority,
       
   725     int delivery_options,
       
   726     int verbose)
       
   727 {
       
   728     int  ret = 0;
       
   729     char buf [PATH_MAX];
       
   730     size_t buf_len = 0;
       
   731     dtn_bundle_id_t                 bundle_id;
       
   732     dtn_bundle_spec_t               bundle_spec;
       
   733     dtn_extension_block_t           bpq_block;
       
   734     dtn_bpq_extension_block_data_t  bpq_block_data;
       
   735     dtn_bundle_payload_t            payload;
       
   736 
       
   737     memset(buf,             0, PATH_MAX);
       
   738     memset(&bundle_spec,    0, sizeof(dtn_bundle_spec_t));
       
   739     memset(&bpq_block,      0, sizeof(dtn_extension_block_t));
       
   740     memset(&bpq_block_data, 0, sizeof(dtn_bpq_extension_block_data_t));
       
   741     memset(&payload,        0, sizeof(dtn_bundle_payload_t));
       
   742     
       
   743     // set the bpq block data
       
   744     bpq_block_data.kind = DTN_BPQ_KIND_QUERY;
       
   745     bpq_block_data.matching_rule = matching_rule;
       
   746     bpq_block_data.query.query_len = strlen(query) + 1;     // include the null char at the end
       
   747     bpq_block_data.query.query_val = query; 
       
   748     bpq_block_data.fragments.num_frag_returned = 0;
       
   749     bpq_block_data.fragments.frag_offsets = NULL;
       
   750     bpq_block_data.fragments.frag_lenghts = NULL;
       
   751 
       
   752     buf_len = bpq_to_char_array(&bpq_block_data, buf, PATH_MAX);
       
   753 
       
   754     // set the bpq block
       
   755     bpq_block.type = DTN_BPQ_BLOCK_TYPE;
       
   756     bpq_block.flags = DTN_BPQ_BLOCK_FLAGS;
       
   757     bpq_block.data.data_len = buf_len;
       
   758     bpq_block.data.data_val = buf;
       
   759     
       
   760     // set the payload (empty)
       
   761     dtn_set_payload(&payload, DTN_PAYLOAD_MEM, NULL, 0);    
       
   762 
       
   763     // set the bundle spec eids
       
   764     if (verbose) fprintf(stdout, "Source: %s\n", src_eid->uri);
       
   765     if (verbose) fprintf(stdout, "Destination: %s\n", dest_eid->uri);
       
   766     bundle_spec.source = *src_eid;
       
   767     bundle_spec.dest = *dest_eid;
       
   768 
       
   769     dtn_copy_eid(&bundle_spec.replyto, &bundle_spec.source);// add support for this to be set differently
       
   770 
       
   771     // set the bundle spec dtn options
       
   772     bundle_spec.expiration = bundle_expiry;
       
   773     bundle_spec.dopts = delivery_options;
       
   774     bundle_spec.priority = priority;
       
   775 
       
   776     // set the bundle extension
       
   777     bundle_spec.blocks.blocks_len = 1;
       
   778     bundle_spec.blocks.blocks_val = &bpq_block;
       
   779 
       
   780     // send the bundle, bpq extension and empty payload
       
   781     if (verbose) fprintf(stdout, "Sending bundle to: %s\n", dest_eid->uri);
       
   782     ret = dtn_send(handle, regid, &bundle_spec, &payload, &bundle_id);
       
   783     if (ret != DTN_SUCCESS) {
       
   784         fprintf(stderr, "error sending bundle: %d (%s)\n",
       
   785                     ret, dtn_strerror(dtn_errno(handle)));
       
   786     } else if (verbose) {
       
   787         fprintf(stdout, "bundle sent successfully: id %s,%llu.%llu\n",
       
   788                     bundle_id.source.uri,
       
   789                     bundle_id.creation_ts.secs,
       
   790                     bundle_id.creation_ts.seqno); 
       
   791     }
       
   792     return ret;   
       
   793 }
       
   794 
       
   795 /*******************************************************************************
       
   796 * recv bpq:
       
   797 * todo.
       
   798 *******************************************************************************/
       
   799 int
       
   800 recv_bpq(dtn_handle_t handle,
       
   801     dtn_timeval_t timeout,
       
   802     const char * filename,
       
   803     int verbose)
       
   804 {
       
   805     int ret = 0;
       
   806     dtn_bundle_spec_t bundle_spec;
       
   807     dtn_bundle_payload_t payload;
       
   808 
       
   809     memset(&bundle_spec, 0, sizeof(bundle_spec));
       
   810     memset(&payload, 0, sizeof(payload));
       
   811 
       
   812     // recv the bpq bundle
       
   813     if (verbose) fprintf(stdout, "blocking waiting for dtn_recv\n");
       
   814     ret = dtn_recv(handle, &bundle_spec, DTN_PAYLOAD_FILE, &payload, timeout);
       
   815     if (ret != DTN_SUCCESS) {
       
   816         fprintf(stderr, "error receiving bundle: %d (%s)\n",
       
   817                     ret, dtn_strerror(dtn_errno(handle)));
       
   818         return ret;
       
   819     } else if (verbose) {
       
   820             fprintf(stdout, "bundle received successfully: id %s,%llu.%llu\n",
       
   821                              bundle_spec.source.uri,
       
   822                              bundle_spec.creation_ts.secs,
       
   823                              bundle_spec.creation_ts.seqno);
       
   824     }
       
   825 
       
   826     // handle the payload file
       
   827     ret = handle_file_transfer(bundle_spec, payload, filename, verbose);
       
   828     if (ret != DTN_SUCCESS) {
       
   829         fprintf(stderr, "error handling file transfer: %d\n", ret);
       
   830     } else if (verbose) {
       
   831         fprintf(stdout, "sucessfully handled file transfer\n");        
       
   832     }
       
   833 
       
   834     dtn_free_payload(&payload);  
       
   835     return ret;
       
   836 }
       
   837 
       
   838 /*******************************************************************************
       
   839 * main:
       
   840 *******************************************************************************/
       
   841 int
       
   842 main(int argc, char** argv)
       
   843 {
       
   844     dtn_endpoint_id_t src_eid;
       
   845     dtn_endpoint_id_t dest_eid;
       
   846     char src_eid_name[PATH_MAX];
       
   847     char dest_eid_name[PATH_MAX];
       
   848     char filename[PATH_MAX];
       
   849     char query[PATH_MAX];
       
   850     int query_type = DTN_BPQ_LITERAL;
       
   851     int matching_rule = DTN_BPQ_EXACT;
       
   852     int mode = DTN_BPQ_SEND_RECV;
       
   853     dtn_timeval_t timeout = DTN_TIMEOUT_INF;    //forever
       
   854     dtn_timeval_t bundle_expiry = 3600;         //one hour
       
   855     dtn_reg_id_t regid = DTN_REGID_NONE;
       
   856     dtn_timeval_t reg_expiry = 30;
       
   857     int reg_fail_action = DTN_REG_DEFER;
       
   858     char reg_fail_script[PATH_MAX];
       
   859     dtn_bundle_priority_t priority = COS_NORMAL; 
       
   860     int delivery_options = 0;               
       
   861     int verbose = 0;
       
   862     int err = 0;
       
   863     dtn_handle_t handle;
       
   864 
       
   865     parse_options(argc, argv,
       
   866         src_eid_name,
       
   867         dest_eid_name,
       
   868         filename,
       
   869         query,
       
   870         &query_type,
       
   871         &matching_rule,
       
   872         &mode,
       
   873         &timeout,
       
   874         &bundle_expiry,
       
   875         &regid,
       
   876         &reg_expiry,
       
   877         &reg_fail_action,
       
   878         reg_fail_script,
       
   879         &priority,
       
   880         &delivery_options,
       
   881         &verbose);
       
   882 
       
   883     validate_options(src_eid_name,
       
   884         dest_eid_name,
       
   885         filename,
       
   886         query,
       
   887         query_type,
       
   888         matching_rule,
       
   889         mode,
       
   890         timeout,
       
   891         bundle_expiry);
       
   892 
       
   893     // open the ipc handle
       
   894     if (verbose) printf("opening connection to dtn router...\n");
       
   895     if ((err = dtn_open(&handle)) != DTN_SUCCESS) {
       
   896         fprintf(stderr, "fatal error opening dtn handle: %s\n",
       
   897                 dtn_strerror(err));
       
   898         exit(1);
       
   899     }
       
   900     if (verbose) fprintf(stdout, "opened connection to dtn router...\n");
       
   901 
       
   902     // parse eids
       
   903     parse_eid(handle, &src_eid, src_eid_name, verbose);
       
   904     parse_eid(handle, &dest_eid, dest_eid_name, verbose);
       
   905     if (verbose) fprintf(stdout, "parsed src_eid: %s\n", src_eid.uri);
       
   906     if (verbose) fprintf(stdout, "parsed dest_eid: %s\n", dest_eid.uri);
       
   907     if (verbose) fprintf(stdout, "regid: %d\n", regid);
       
   908 
       
   909     // get dtn registration
       
   910     if (verbose) fprintf(stdout, "registering with dtn...\n");
       
   911     register_with_dtn(handle,
       
   912         &src_eid,
       
   913         &regid,
       
   914         reg_expiry,
       
   915         reg_fail_action,
       
   916         reg_fail_script);
       
   917     if (verbose) fprintf(stdout, "registered with dtn, "
       
   918                                  "regid: %d local eid: %s\n",
       
   919                                  regid, src_eid.uri);
       
   920     
       
   921     //get to work
       
   922     switch (mode)
       
   923     {
       
   924 #define TRY(fn, err_msg) \
       
   925     if (fn != DTN_SUCCESS) { \
       
   926         fprintf(stderr, err_msg); \
       
   927         dtn_close(handle); \
       
   928         exit(1); \
       
   929     }
       
   930     case DTN_BPQ_SEND:
       
   931         TRY( send_bpq(handle, regid, &src_eid, &dest_eid, query,
       
   932                       matching_rule, bundle_expiry, priority,
       
   933                       delivery_options, verbose), "error sending query\n" );
       
   934         break;
       
   935 
       
   936     case DTN_BPQ_RECV:
       
   937         TRY( recv_bpq(handle, timeout, filename, verbose), 
       
   938              "error receiving query\n" );
       
   939         break;
       
   940 
       
   941     case DTN_BPQ_SEND_RECV:
       
   942         TRY( send_bpq(handle, regid, &src_eid, &dest_eid, query,
       
   943                       matching_rule, bundle_expiry, priority,
       
   944                       delivery_options, verbose), "error sending query\n" );
       
   945 
       
   946         TRY( recv_bpq(handle, timeout, filename, verbose), 
       
   947              "error receiving query\n" );
       
   948         break;
       
   949 
       
   950     default:
       
   951         fprintf(stderr, "invalid mode '%d'\n", mode);
       
   952         dtn_close(handle);
       
   953         exit(1);
       
   954 #undef TRY
       
   955     }
       
   956 
       
   957     // close the ipc handle
       
   958     if (verbose) fprintf(stdout, "closing connection to dtn router...\n");
       
   959     dtn_close(handle);
       
   960     if (verbose) fprintf(stdout, "closed connection to dtn router...\n");
       
   961 
       
   962     return 0;
       
   963 }
       
   964