apps/dtnrespond/dtnrespond.c
changeset 1 44c5e3fa6d30
child 2 9daf757dfa63
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 #define DTN_BPQ_BLOCK_TYPE 0xC8
       
    38 #define DTN_BPQ_BLOCK_FLAGS 0x00
       
    39 
       
    40 #define DTN_BPQ_KIND_QUERY 0x00
       
    41 #define DTN_BPQ_KIND_RESPONSE 0x01
       
    42 
       
    43 // Find the maximum commandline length
       
    44 #ifdef __FreeBSD__
       
    45 /* Needed for PATH_MAX, Linux doesn't need it */
       
    46 #include <sys/syslimits.h>
       
    47 #endif
       
    48 
       
    49 #ifndef PATH_MAX
       
    50 /* A conservative fallback */
       
    51 #define PATH_MAX 1024
       
    52 #endif
       
    53 
       
    54 //global variables
       
    55 const char* progname;
       
    56 
       
    57 /*******************************************************************************
       
    58 * usage:
       
    59 * display cmd line options to user.
       
    60 *******************************************************************************/
       
    61 int
       
    62 usage()
       
    63 {
       
    64     fprintf(stderr, "usage: %s -l < local endpoint > -f < matching filename > "
       
    65                     "[opts]\n", progname);
       
    66     fprintf(stderr, "options:\n");
       
    67     fprintf(stderr, " -n  < count > exit after count bundles received\n");
       
    68     fprintf(stderr, " -e  < seconds > bundle expiry time\n");
       
    69     fprintf(stderr, " -i  < regid > existing registration id\n");
       
    70     fprintf(stderr, " -E  < seconds > registration expiry time\n");
       
    71     fprintf(stderr, " -A  < defer | drop | exec > failure action\n");
       
    72     fprintf(stderr, " -S  < script > failure script for exec action\n");
       
    73     fprintf(stderr, " -P  < bulk | normal | expedited | reserved > priority\n");
       
    74     fprintf(stderr, " -D  request end-to-end delivery receipt\n");
       
    75     fprintf(stderr, " -X  request deletion receipt\n");
       
    76     fprintf(stderr, " -F  request bundle forwarding receipts\n");
       
    77     fprintf(stderr, " -R  request bundle reception receipts\n");
       
    78     fprintf(stderr, " -c  request custody transfer\n");
       
    79     fprintf(stderr, " -C  request custody transfer receipts\n");
       
    80     fprintf(stderr, " -1  assert destination endpoint is a singleton\n");
       
    81     fprintf(stderr, " -N  assert destination endpoint is not a singleton\n");
       
    82     fprintf(stderr, " -W  set the do not fragment option\n");
       
    83     fprintf(stderr, " -h  help\n");
       
    84     fprintf(stderr, " -v  verbose\n");
       
    85 
       
    86     return 0;
       
    87 }
       
    88 
       
    89 /*******************************************************************************
       
    90 * parse options:
       
    91 * set internal variables based on cmd line args.
       
    92 * calls parse matching file if required.
       
    93 * returns success or exits on failure.
       
    94 *******************************************************************************/
       
    95 int
       
    96 parse_options(int argc, char** argv,
       
    97     char * local_eid_name,              // l
       
    98     char * matching_filename,           // f
       
    99     int * count,                        // n
       
   100     dtn_timeval_t * bundle_expiry,      // e
       
   101     dtn_reg_id_t * regid,               // i
       
   102     dtn_timeval_t * reg_expiry,         // E
       
   103     int * reg_fail_action,              // A
       
   104     char * reg_fail_script,             // S
       
   105     dtn_bundle_priority_t * priority,   // P
       
   106     int * delivery_options,             // D X F R c C 1 N W
       
   107     int * verbose)                      // v
       
   108 {
       
   109     int c, done = 0;
       
   110 
       
   111     progname = argv[0];
       
   112 
       
   113     //initialize strings
       
   114     memset(local_eid_name,    0, sizeof(char) * PATH_MAX);
       
   115     memset(matching_filename, 0, sizeof(char) * PATH_MAX);
       
   116     memset(reg_fail_script,   0, sizeof(char) * PATH_MAX);
       
   117 
       
   118     while( !done )
       
   119     {
       
   120         c = getopt(argc, argv, "l:f:n:e:i:E:A:S:P:DXFRcC1NWvhH");
       
   121         switch(c)
       
   122         {
       
   123         case 'l':
       
   124             strncpy(local_eid_name, optarg, PATH_MAX);
       
   125             break;
       
   126         case 'f':
       
   127             strncpy(matching_filename, optarg, PATH_MAX);
       
   128             break;
       
   129         case 'n':
       
   130             *count = atoi(optarg);
       
   131             break;
       
   132         case 'e':
       
   133             *bundle_expiry = atoi(optarg);
       
   134             break;
       
   135         case 'i':
       
   136             *regid = atoi(optarg);
       
   137             break;
       
   138         case 'E':
       
   139             *reg_expiry = atoi(optarg);
       
   140             break;
       
   141         case 'A':
       
   142             if (!strcasecmp(optarg, "defer")) {
       
   143                 *reg_fail_action = DTN_REG_DEFER;
       
   144 
       
   145             } else if (!strcasecmp(optarg, "drop")) {
       
   146                 *reg_fail_action = DTN_REG_DROP;
       
   147 
       
   148             } else if (!strcasecmp(optarg, "exec")) {
       
   149                 *reg_fail_action = DTN_REG_EXEC;
       
   150 
       
   151             } else {
       
   152                 fprintf(stderr, "invalid failure action '%s'\n", optarg);
       
   153                 usage();
       
   154                 exit(1);
       
   155             }
       
   156             break;
       
   157         case 'S':
       
   158             strncpy(reg_fail_script, optarg, PATH_MAX);
       
   159             break;
       
   160         case 'P':
       
   161             if (!strcasecmp(optarg, "bulk"))   {
       
   162                 *priority = COS_BULK;
       
   163             } else if (!strcasecmp(optarg, "normal")) {
       
   164                 *priority = COS_NORMAL;
       
   165             } else if (!strcasecmp(optarg, "expedited")) {
       
   166                 *priority = COS_EXPEDITED;
       
   167             } else if (!strcasecmp(optarg, "reserved")) {
       
   168                 *priority = COS_RESERVED;
       
   169             } else {
       
   170                 fprintf(stderr, "invalid priority value %s\n", optarg);
       
   171                 usage();
       
   172                 exit(1);
       
   173             }
       
   174             break;
       
   175         case 'D':
       
   176             *delivery_options |= DOPTS_DELIVERY_RCPT;
       
   177             break;
       
   178         case 'X':
       
   179             *delivery_options |= DOPTS_DELETE_RCPT;
       
   180             break;
       
   181         case 'F':
       
   182             *delivery_options |= DOPTS_FORWARD_RCPT;
       
   183             break;
       
   184         case 'R':
       
   185             *delivery_options |= DOPTS_RECEIVE_RCPT;
       
   186             break;
       
   187         case 'c':
       
   188             *delivery_options |= DOPTS_CUSTODY;
       
   189             break;
       
   190         case 'C':
       
   191             *delivery_options |= DOPTS_CUSTODY_RCPT;
       
   192             break;
       
   193         case '1':
       
   194             *delivery_options |= DOPTS_SINGLETON_DEST;
       
   195             break;
       
   196         case 'N':
       
   197             *delivery_options |= DOPTS_MULTINODE_DEST;
       
   198             break;
       
   199         case 'W':
       
   200             *delivery_options |= DOPTS_DO_NOT_FRAGMENT;
       
   201             break;
       
   202         case 'v':
       
   203             *verbose = 1;
       
   204             break;
       
   205         case 'h':
       
   206         case 'H':
       
   207             usage();
       
   208             exit(0);
       
   209         case -1:
       
   210             done = 1;
       
   211             break;
       
   212         default:
       
   213             // getopt already prints error message for unknown option characters
       
   214             usage();
       
   215             exit(1);
       
   216         }             
       
   217     }
       
   218     return 0;
       
   219 }
       
   220 
       
   221 /*******************************************************************************
       
   222 * validate options:
       
   223 * returns success or exits on failure 
       
   224 *******************************************************************************/
       
   225 int
       
   226 validate_options(const char * local_eid_name, const char * matching_filename)
       
   227 {
       
   228 #define REQUIRE(test, err_msg) \
       
   229     if(!test) { \
       
   230         fprintf(stderr, err_msg); \
       
   231         usage(); \
       
   232         exit(1); \
       
   233     }
       
   234 
       
   235     REQUIRE(strlen(local_eid_name) > 0, "-l <local eid> required\n");
       
   236     REQUIRE(strlen(matching_filename) > 0, "-f <matching filename> required\n");
       
   237     
       
   238     return 0;
       
   239 }
       
   240 
       
   241 /*******************************************************************************
       
   242 * register with dtn:
       
   243 * 
       
   244 *******************************************************************************/
       
   245 int
       
   246 register_with_dtn(dtn_handle_t handle,
       
   247     dtn_endpoint_id_t * local_eid,
       
   248     const char * local_eid_name,
       
   249     dtn_reg_id_t * regid,
       
   250     dtn_timeval_t reg_expiration,
       
   251     int reg_fail_action,
       
   252     char * reg_fail_script)
       
   253 {
       
   254     int call_bind = 0;
       
   255     dtn_reg_info_t reginfo;
       
   256 
       
   257     memset(local_eid, 0, sizeof(dtn_endpoint_id_t));
       
   258 
       
   259     // if no regid has been given we need to create a new registration
       
   260     if (*regid == DTN_REGID_NONE) {
       
   261         if (local_eid_name[0] == '/') {
       
   262             if (dtn_build_local_eid(handle, local_eid, local_eid_name) != DTN_SUCCESS) {
       
   263                 fprintf(stderr, "error building local eid: %s\n",
       
   264                         dtn_strerror(dtn_errno(handle)));
       
   265                 dtn_close(handle); 
       
   266                 exit(1);
       
   267             }
       
   268         } else {
       
   269             if (dtn_parse_eid_string(local_eid, local_eid_name) != DTN_SUCCESS) {
       
   270                 fprintf(stderr, "error parsing eid string: %s\n",
       
   271                         dtn_strerror(dtn_errno(handle)));
       
   272                 dtn_close(handle);
       
   273                 exit(1);
       
   274             }
       
   275         }
       
   276 
       
   277         memset(&reginfo, 0, sizeof(dtn_reg_info_t));
       
   278 
       
   279         // create a new registration based on this eid
       
   280         dtn_copy_eid(&reginfo.endpoint, local_eid);
       
   281         reginfo.regid             = *regid;
       
   282         reginfo.expiration        = reg_expiration;
       
   283         reginfo.flags             = reg_fail_action;
       
   284         reginfo.script.script_val = reg_fail_script;
       
   285         reginfo.script.script_len = strlen(reg_fail_script) + 1;
       
   286     }
       
   287 
       
   288     // try to see if there is an existing registration that matches
       
   289     // the given endpoint, in which case we'll use that one.
       
   290     if (*regid == DTN_REGID_NONE) {
       
   291         if (dtn_find_registration(handle, local_eid, regid) != DTN_SUCCESS &&
       
   292             dtn_errno(handle) != DTN_ENOTFOUND) {
       
   293             fprintf(stderr, "error finding registration: %s\n",
       
   294                     dtn_strerror(dtn_errno(handle)));
       
   295             dtn_close(handle);
       
   296             exit(1);
       
   297         }
       
   298         call_bind = 1;
       
   299     }
       
   300 
       
   301     // if the user didn't give us a registration to use, get a new one
       
   302     if (*regid == DTN_REGID_NONE) {
       
   303         if (dtn_register(handle, &reginfo, regid) != DTN_SUCCESS) {
       
   304             fprintf(stderr, "error registering: %s\n",
       
   305                     dtn_strerror(dtn_errno(handle)));
       
   306             dtn_close(handle);
       
   307             exit(1); 
       
   308         }
       
   309         call_bind = 0;
       
   310     } else {
       
   311         call_bind = 1;
       
   312     }
       
   313 
       
   314     if (call_bind) {
       
   315         // bind the current handle to the found registration
       
   316         if (dtn_bind(handle, *regid) != DTN_SUCCESS) {
       
   317             fprintf(stderr, "error binding to registration: %s\n",
       
   318                     dtn_strerror(dtn_errno(handle)));
       
   319             dtn_close(handle);
       
   320             exit(1);
       
   321         }
       
   322     }
       
   323 
       
   324     return DTN_SUCCESS;
       
   325 }
       
   326 
       
   327 /*******************************************************************************
       
   328 * trim whitespace:
       
   329 * first move past any leading whitespace 
       
   330 * after the first non-whitespace char bef=gin copying to output
       
   331 * finish by setting any trailing whitespace to 0
       
   332 * @return 0 on success or -1 if input not completely read
       
   333 *******************************************************************************/
       
   334 int
       
   335 trim_whitespace(const char * in, char * out, int out_len)
       
   336 {
       
   337     int i=0, j=0;
       
   338     char space = ' ';
       
   339     char tab = '\t';
       
   340 
       
   341     memset(out, 0, out_len);
       
   342 
       
   343     // move past any leading whitespace
       
   344     while (i<strlen(in) && in[i] == space ||
       
   345            i<strlen(in) && in[i] == tab)
       
   346         ++i;
       
   347     
       
   348     // body case
       
   349     for ( ; i<strlen(in) && j<out_len-2; ++i){
       
   350             out[j++] = in[i];
       
   351     }
       
   352 
       
   353     // remove any trailing whitespace
       
   354     // out[j] now points to the null char that terminates the string
       
   355     j--;
       
   356     while (j >= 0 && out[j] == space ||
       
   357            j >= 0 && out[j] == tab)
       
   358         out[j--] = 0;
       
   359 
       
   360     if (i <  strlen(in))
       
   361         return -1;
       
   362     else
       
   363         return 0;
       
   364 }   
       
   365 
       
   366 /*******************************************************************************
       
   367 * escape spaces:
       
   368 * first move past any leading whitespace 
       
   369 * after the first non-whitespace char escape any whitespace
       
   370 * @return 0 on success or -1 if input not completely read
       
   371 *******************************************************************************/
       
   372 int
       
   373 escape_spaces(const char * in, char * out, int out_len)
       
   374 {
       
   375     int i=0, j=0;
       
   376     char escape = '\\';
       
   377     char space = ' ';
       
   378 
       
   379     memset(out, 0, out_len);
       
   380 
       
   381     // move past any leading whitespace
       
   382     while (i<strlen(in) && in[i] == space)
       
   383         ++i;
       
   384     
       
   385     // body case
       
   386     for ( ; i<strlen(in) && j<out_len-2; ++i){
       
   387         if (in[i] == space && in[i-1] != escape) {
       
   388             out[j++] = escape;
       
   389             out[j++] = space;
       
   390         } else {
       
   391             out[j++] = in[i];
       
   392         }
       
   393     }
       
   394 
       
   395     if (i <  strlen(in))
       
   396         return -1;
       
   397     else
       
   398         return 0;
       
   399 }   
       
   400 
       
   401 /*******************************************************************************
       
   402 * find query
       
   403 * search all files in 'dir' for a query match
       
   404 * test against query len & query val and update found
       
   405 * @return 0 or -1 if error
       
   406 *******************************************************************************/
       
   407 int
       
   408 find_query(const char * dir, const char * query, int * found)
       
   409 {
       
   410     FILE *file;
       
   411     int i, status;
       
   412     char ls_result[PATH_MAX];
       
   413     char ls_cmd[PATH_MAX];
       
   414     char esc_dir[PATH_MAX];
       
   415 
       
   416     *found = 0;
       
   417 
       
   418     // trim & escape spaces in dir before calling ls
       
   419     if (escape_spaces(dir, esc_dir, PATH_MAX) != DTN_SUCCESS)
       
   420         return -1;
       
   421     
       
   422     snprintf (ls_cmd, PATH_MAX, "ls %s", esc_dir);
       
   423     file = popen (ls_cmd, "r");
       
   424 
       
   425     if (file == NULL)
       
   426         return -1;
       
   427 
       
   428     for (i=0; fgets(ls_result, PATH_MAX, file) != NULL; ++i) {
       
   429         if (ls_result[strlen(ls_result)-1] == '\n')
       
   430             ls_result[strlen(ls_result)-1] = 0;
       
   431 
       
   432         if (strlen(query) == strlen(ls_result) &&
       
   433             strncmp (query, ls_result, strlen(query)) == 0) {
       
   434             *found = 1;
       
   435             break;
       
   436         }
       
   437     }
       
   438 
       
   439     status = pclose(file);
       
   440     if (status == -1) 
       
   441         return -1;
       
   442 
       
   443     return 0;
       
   444 }
       
   445 
       
   446 
       
   447 /*******************************************************************************
       
   448 * match bpq:
       
   449 * read in paths to search for query in from 'matching file'
       
   450 * for each record in the matching file, extract the response path
       
   451 * matching file format: [matching_rule, encoding, query, response_path, expiry]
       
   452 *******************************************************************************/
       
   453 int
       
   454 match_bpq(const dtn_bpq_extension_block_data_t * bpq,
       
   455     const char * matching_filename,
       
   456     char * pathname,
       
   457     int * found)
       
   458 {
       
   459     char line[PATH_MAX];
       
   460     char trim_response_path[PATH_MAX];
       
   461     char * response_path;
       
   462     FILE * file;
       
   463     
       
   464     *found = 0;
       
   465 
       
   466     if ((file = fopen(matching_filename, "r")) == 0)
       
   467         return -1;
       
   468     
       
   469     memset(line, 0 , PATH_MAX);
       
   470     while (fgets(line, PATH_MAX, file) != NULL) {
       
   471         strtok(line, ",");
       
   472         strtok(NULL, ",");
       
   473         strtok(NULL, ",");
       
   474         response_path = strtok(NULL, ",");  
       
   475 //      expiry = strtok(NULL, ",");                 
       
   476 
       
   477         // trim whitespace from response path
       
   478         trim_whitespace(response_path, trim_response_path, PATH_MAX);
       
   479 
       
   480         if (find_query(trim_response_path, bpq->query.query_val, found) != DTN_SUCCESS)
       
   481             return -1;
       
   482 
       
   483         // if found build pathname and stop looking
       
   484         if (*found == 1) {
       
   485             // ensure path ends in slash
       
   486             if (trim_response_path[strlen(trim_response_path)-1] == '/'){
       
   487                 snprintf(pathname, PATH_MAX, "%s%s", trim_response_path, bpq->query.query_val);
       
   488             } else {
       
   489                 snprintf(pathname, PATH_MAX, "%s/%s", trim_response_path, bpq->query.query_val);
       
   490             }
       
   491 
       
   492             break;
       
   493         }
       
   494         memset(line, 0 , PATH_MAX);
       
   495     }
       
   496     fclose (file);
       
   497 
       
   498     return 0;
       
   499 }
       
   500 
       
   501 /*******************************************************************************
       
   502 * bpq to char array:
       
   503 * encode as SDNVs,
       
   504 *   BPQ-kind             1-byte
       
   505 *   matching rule type   1-byte
       
   506 *   BPQ-value-length     SDNV
       
   507 *   BPQ-value            n-bytes
       
   508 *   number of fragments  SDNV
       
   509 *   fragment offsets     SDNV
       
   510 *   fragment lengths     SDNV
       
   511 *
       
   512 * @return The number of bytes or -1 on error
       
   513 *******************************************************************************/
       
   514 int
       
   515 bpq_to_char_array(const dtn_bpq_extension_block_data_t * bpq,
       
   516     char* buf,
       
   517     size_t buf_len)
       
   518 {
       
   519     int i=0, j=0, k=0;
       
   520     int encoding_len;
       
   521     char encoding[PATH_MAX];
       
   522 
       
   523     // BPQ-kind             1-byte
       
   524     if (i < buf_len)    buf[i++] = (char) bpq->kind;
       
   525 
       
   526     // matching rule type   1-byte
       
   527     if (i < buf_len)    buf[i++] = (char) bpq->matching_rule;
       
   528 
       
   529     // BPQ-value-length     SDNV
       
   530     if ( (encoding_len = sdnv_encode (bpq->query.query_len, encoding, PATH_MAX)) == -1 )
       
   531         return -1;
       
   532     for (j=0; i<buf_len && j<encoding_len; ++j)
       
   533         buf[i++] = encoding[j];
       
   534 
       
   535     // BPQ-value            n-bytes
       
   536     for (j=0; i<buf_len && j<bpq->query.query_len; ++j)
       
   537         buf[i++] = bpq->query.query_val[j];
       
   538 
       
   539     // number of fragments  SDNV
       
   540     if ( (encoding_len = sdnv_encode (bpq->fragments.num_frag_returned, encoding, PATH_MAX)) == -1 )
       
   541         return -1;
       
   542     for (j=0; i<buf_len && j<encoding_len; ++j)
       
   543         buf[i++] = encoding[j];
       
   544 
       
   545     for (k=0; k<bpq->fragments.num_frag_returned; ++k) {
       
   546 
       
   547         // fragment offsets     SDNV
       
   548         if ( (encoding_len = sdnv_encode (bpq->fragments.frag_offsets[k], encoding, PATH_MAX)) == -1 )
       
   549             return -1;
       
   550         for (j=0; i<buf_len && j<encoding_len; ++j)
       
   551             buf[i++] = encoding[j];
       
   552 
       
   553         // fragment lengths     SDNV
       
   554         if ( (encoding_len = sdnv_encode (bpq->fragments.frag_lenghts[k], encoding, PATH_MAX)) == -1 )
       
   555             return -1;
       
   556         for (j=0; i<buf_len && j<encoding_len; ++j)
       
   557             buf[i++] = encoding[j];
       
   558     }
       
   559 
       
   560 
       
   561     return i;
       
   562 }
       
   563 
       
   564 /*******************************************************************************
       
   565 * char array to bpq:
       
   566 * decode as SDNVs,
       
   567 *   BPQ-kind             1-byte
       
   568 *   matching rule type   1-byte
       
   569 *   BPQ-value-length     SDNV
       
   570 *   BPQ-value            n-bytes
       
   571 *   number of fragments  SDNV
       
   572 *   fragment offsets     SDNV
       
   573 *   fragment lengths     SDNV
       
   574 *
       
   575 * @return DTN_SUCCESS or -1 on error
       
   576 *******************************************************************************/
       
   577 int
       
   578 char_array_to_bpq(const char* buf,
       
   579     size_t buf_len,
       
   580     dtn_bpq_extension_block_data_t * bpq)
       
   581 {
       
   582     int i=0, j=0;
       
   583     int decoding_len=0;
       
   584 
       
   585     // BPQ-kind             1-byte
       
   586     if (i<buf_len) bpq->kind = (u_int) buf[i++];
       
   587 
       
   588     // matching rule type   1-byte
       
   589     if (i<buf_len) bpq->matching_rule = (u_int) buf[i++];
       
   590 
       
   591     // BPQ-value-length     SDNV
       
   592     if ( (decoding_len = sdnv_decode (&(buf[i]), buf_len - i, &(bpq->query.query_len))) == -1 )
       
   593         return -1;
       
   594     i += decoding_len;
       
   595 
       
   596     // BPQ-value            n-bytes
       
   597     if (i<buf_len) bpq->query.query_val = &(buf[i]);
       
   598     i += bpq->query.query_len;
       
   599 
       
   600     // number of fragments  SDNV
       
   601     if ( (decoding_len = sdnv_decode (&(buf[i]), buf_len - i, &(bpq->fragments.num_frag_returned))) == -1 )
       
   602         return -1;
       
   603     i += decoding_len;
       
   604 
       
   605     for (j=0; i<buf_len && j<bpq->fragments.num_frag_returned; ++j) {
       
   606 
       
   607         // fragment offsets     SDNV
       
   608         if ( (decoding_len = sdnv_decode (&(buf[i]), buf_len - i, &(bpq->fragments.frag_offsets[j]))) == -1 )
       
   609             return -1;
       
   610         i += decoding_len;
       
   611 
       
   612         // fragment lengths     SDNV
       
   613         if ( (decoding_len = sdnv_decode (&(buf[i]), buf_len - i, &(bpq->fragments.frag_lenghts[j]))) == -1 )
       
   614             return -1;
       
   615         i += decoding_len;
       
   616     }
       
   617 
       
   618     if (i != buf_len)
       
   619         return -1;
       
   620 
       
   621     return DTN_SUCCESS;
       
   622 }
       
   623 
       
   624 /*******************************************************************************
       
   625 * send response bpq:
       
   626 * build a response bundle containing the queried object file as the payload
       
   627 * attach a BPQ extension describing the query & object
       
   628 * and send to the source of the query
       
   629 * @return 0 if successful or -1 if error
       
   630 *******************************************************************************/
       
   631 int
       
   632 send_response_bpq(dtn_handle_t * handle,
       
   633     dtn_reg_id_t regid,
       
   634     dtn_bundle_spec_t * query_bundle_spec,
       
   635     dtn_bpq_extension_block_data_t * query_bpq_block_data,
       
   636     const char * pathname,
       
   637     int bundle_expiry,
       
   638     dtn_bundle_priority_t  priority,
       
   639     int delivery_options,
       
   640     int verbose)
       
   641 {
       
   642     int  ret = 0;
       
   643     char buf [PATH_MAX];
       
   644     size_t buf_len = 0;
       
   645     dtn_bundle_id_t                 response_bundle_id;
       
   646     dtn_bundle_spec_t               response_bundle_spec;
       
   647     dtn_extension_block_t           response_bpq_block;
       
   648     dtn_bpq_extension_block_data_t  response_bpq_block_data;
       
   649     dtn_bundle_payload_t            response_payload;
       
   650     u_int offsets[1];
       
   651     u_int lengths[1];
       
   652 
       
   653     memset(buf,                      0, PATH_MAX);
       
   654     memset(&response_bundle_spec,    0, sizeof(dtn_bundle_spec_t));
       
   655     memset(&response_bpq_block,      0, sizeof(dtn_extension_block_t));
       
   656     memset(&response_bpq_block_data, 0, sizeof(dtn_bpq_extension_block_data_t));
       
   657     memset(&response_payload,        0, sizeof(dtn_bundle_payload_t));
       
   658 
       
   659     // set the payload
       
   660     dtn_set_payload(&response_payload, DTN_PAYLOAD_FILE, pathname, strlen(pathname)); 
       
   661 
       
   662     // set the bpq block data
       
   663     response_bpq_block_data.kind = DTN_BPQ_KIND_RESPONSE;
       
   664     response_bpq_block_data.matching_rule = query_bpq_block_data->matching_rule;
       
   665     response_bpq_block_data.query.query_len = query_bpq_block_data->query.query_len;
       
   666     response_bpq_block_data.query.query_val = query_bpq_block_data->query.query_val;
       
   667 
       
   668     offsets[0] = 0;
       
   669     lengths[0] = 100;   //todo: add payload length here
       
   670 
       
   671     response_bpq_block_data.fragments.num_frag_returned = 1;
       
   672     response_bpq_block_data.fragments.frag_offsets = offsets;
       
   673     response_bpq_block_data.fragments.frag_lenghts = lengths; 
       
   674 
       
   675     if ( (buf_len = bpq_to_char_array(&response_bpq_block_data, buf, PATH_MAX)) == -1 ) {
       
   676         fprintf (stderr, "error encoding bpq: %d", buf_len);
       
   677         return -1;
       
   678     }
       
   679 
       
   680     // set the bpq block
       
   681     response_bpq_block.type = DTN_BPQ_BLOCK_TYPE;
       
   682     response_bpq_block.flags = DTN_BPQ_BLOCK_FLAGS;
       
   683     response_bpq_block.data.data_len = buf_len;
       
   684     response_bpq_block.data.data_val = buf;
       
   685 
       
   686     // copy dest src
       
   687     dtn_copy_eid(&response_bundle_spec.dest,    &(query_bundle_spec->source));
       
   688     dtn_copy_eid(&response_bundle_spec.source,  &(query_bundle_spec->dest));
       
   689     dtn_copy_eid(&response_bundle_spec.replyto, &(query_bundle_spec->dest));
       
   690 
       
   691     // set the bundle spec dtn options
       
   692     response_bundle_spec.expiration = bundle_expiry;
       
   693     response_bundle_spec.dopts = delivery_options;
       
   694     response_bundle_spec.priority = priority;
       
   695 
       
   696     // set the bundle extension
       
   697     response_bundle_spec.blocks.blocks_len = 1;
       
   698     response_bundle_spec.blocks.blocks_val = &response_bpq_block;
       
   699 
       
   700 
       
   701     // send the bundle, bpq extension and empty payload
       
   702     ret = dtn_send(*handle, regid, &response_bundle_spec, &response_payload, &response_bundle_id);
       
   703     if (ret != DTN_SUCCESS) {
       
   704         fprintf(stderr, "error sending response bundle: %d (%s)\n",
       
   705                     ret, dtn_strerror(dtn_errno(handle)));
       
   706     } else if (verbose) {
       
   707         fprintf(stdout, "bundle sent successfully: id %s,%llu.%llu\n",
       
   708                     response_bundle_id.source.uri,
       
   709                     response_bundle_id.creation_ts.secs,
       
   710                     response_bundle_id.creation_ts.seqno);
       
   711     }
       
   712     return ret;
       
   713 }
       
   714 
       
   715 /*******************************************************************************
       
   716 * receive bpq:
       
   717 * listen for incoming bundles, 
       
   718 * upon receipt of a new bundle ckeck for bpq expension block. 
       
   719 * Attempt to match the query in the bpq.
       
   720 * If a match is found, send a response containing the queied object to the 
       
   721 * source of the query.
       
   722 *******************************************************************************/
       
   723 int
       
   724 receive_bpq(dtn_handle_t * handle,
       
   725     dtn_reg_id_t regid,
       
   726     const char * matching_filename,
       
   727     int  count,
       
   728     int bundle_expiry,
       
   729     dtn_bundle_priority_t  priority,
       
   730     int delivery_options,
       
   731     int verbose)
       
   732 {
       
   733     int i, j, num_blocks, found, ret = 0;
       
   734     char pathname[PATH_MAX];
       
   735     dtn_bundle_spec_t              bundle_spec;
       
   736     dtn_extension_block_t          * bpq_blocks;
       
   737     dtn_bpq_extension_block_data_t bpq_block_data;
       
   738     dtn_bundle_payload_t           payload;
       
   739 
       
   740     // start listening for bpq bundles
       
   741     for (i = 0; count == -1 || i < count; ++i) {
       
   742         found = 0;
       
   743         memset(&bundle_spec,    0, sizeof(dtn_bundle_spec_t));
       
   744         memset(&bpq_block_data, 0, sizeof(dtn_bpq_extension_block_data_t));
       
   745         memset(&payload,        0, sizeof(dtn_bundle_payload_t));
       
   746         memset(pathname,        0, PATH_MAX);
       
   747         pathname[0] = '\0';
       
   748 
       
   749         if (verbose) fprintf(stdout, "blocking waiting for dtn_recv\n");
       
   750         ret = dtn_recv(*handle,
       
   751                        &bundle_spec,
       
   752                        DTN_PAYLOAD_FILE,
       
   753                        &payload,
       
   754                        DTN_TIMEOUT_INF);
       
   755         if (ret != DTN_SUCCESS) {
       
   756             fprintf(stderr, "error receiving bundle: %d (%s)\n",
       
   757                     ret, dtn_strerror(dtn_errno(*handle)));
       
   758             return ret;
       
   759         } else if (verbose) {
       
   760             fprintf(stdout, "bundle %d received successfully: id %s,%llu.%llu\n",
       
   761                              i,
       
   762                              bundle_spec.source.uri,
       
   763                              bundle_spec.creation_ts.secs,
       
   764                              bundle_spec.creation_ts.seqno);
       
   765         }
       
   766 
       
   767         // extract the bpq
       
   768         num_blocks = bundle_spec.blocks.blocks_len;
       
   769         bpq_blocks = bundle_spec.blocks.blocks_val;    
       
   770 
       
   771         for (j = 0; j < num_blocks; ++j) {
       
   772             if (bpq_blocks[j].type == DTN_BPQ_BLOCK_TYPE) {
       
   773 
       
   774                 if (verbose) fprintf(stdout, "bundle %d contains a "
       
   775                                              "BPQ extension block\n", i);
       
   776 
       
   777                 ret = char_array_to_bpq(bpq_blocks[j].data.data_val, 
       
   778                                         bpq_blocks[j].data.data_len, 
       
   779                                         &bpq_block_data);
       
   780                 if (ret != DTN_SUCCESS) {
       
   781                     fprintf(stderr, "error decoding query bundle: %d\n", ret);
       
   782                     return ret;
       
   783                 }
       
   784 
       
   785                 match_bpq(&bpq_block_data, matching_filename, pathname, &found);
       
   786                 break;
       
   787             }                
       
   788         }
       
   789 
       
   790         // if found respond and continue listening
       
   791         if (found) {
       
   792             if (verbose) fprintf(stdout, "BPQ match found for query: %s\n",
       
   793                                          bpq_block_data.query.query_val);
       
   794 
       
   795             ret = send_response_bpq(handle,
       
   796                                     regid,
       
   797                                     &bundle_spec,
       
   798                                     &bpq_block_data,
       
   799                                     pathname,
       
   800                                     bundle_expiry,
       
   801                                     priority,
       
   802                                     delivery_options,
       
   803                                     verbose);
       
   804             if (ret != DTN_SUCCESS) {
       
   805                 fprintf(stderr, "error sending response bundle: %d (%s)\n",
       
   806                         ret, dtn_strerror(dtn_errno(*handle)));
       
   807                 return ret;
       
   808             }
       
   809         }
       
   810         dtn_free_payload(&payload);
       
   811     }
       
   812 
       
   813     return ret;
       
   814 }
       
   815 
       
   816 /*******************************************************************************
       
   817 * main:
       
   818 *
       
   819 *******************************************************************************/
       
   820 int
       
   821 main(int argc, char** argv)
       
   822 {
       
   823     dtn_endpoint_id_t local_eid;
       
   824     char local_eid_name[PATH_MAX];
       
   825     char matching_filename[PATH_MAX];
       
   826     int count = -1;                                     //forever
       
   827     dtn_timeval_t bundle_expiry = 3600;                 //one hour
       
   828     dtn_reg_id_t regid = DTN_REGID_NONE;
       
   829     dtn_timeval_t reg_expiry = 30;
       
   830     int reg_fail_action = DTN_REG_DEFER;
       
   831     char reg_fail_script[PATH_MAX]; 
       
   832     dtn_bundle_priority_t priority = COS_NORMAL;
       
   833     int delivery_options = 0;
       
   834     int verbose = 0;
       
   835     int err = 0;
       
   836     dtn_handle_t handle;
       
   837 
       
   838     parse_options(argc, argv,
       
   839         local_eid_name,
       
   840         matching_filename,
       
   841         &count,
       
   842         &bundle_expiry,
       
   843         &regid,
       
   844         &reg_expiry,
       
   845         &reg_fail_action,
       
   846         reg_fail_script,
       
   847         &priority,
       
   848         &delivery_options,
       
   849         &verbose);
       
   850 
       
   851     validate_options(local_eid_name, matching_filename);
       
   852 
       
   853     // open the ipc handle
       
   854     if (verbose) fprintf(stdout, "opening connection to dtn router...\n");
       
   855     if ((err = dtn_open(&handle)) != DTN_SUCCESS) {
       
   856         fprintf(stderr, "fatal error opening dtn handle: %s\n",
       
   857                 dtn_strerror(err));
       
   858         exit(1);
       
   859     }
       
   860     if (verbose) fprintf(stdout, "opened connection to dtn router...\n");
       
   861 
       
   862     // get dtn registration
       
   863     if (verbose) fprintf(stdout, "registering with dtn...\n");
       
   864     register_with_dtn(handle,
       
   865         &local_eid,
       
   866         local_eid_name,
       
   867         &regid,
       
   868         reg_expiry,
       
   869         reg_fail_action,
       
   870         reg_fail_script);
       
   871     if (verbose) fprintf(stdout, "registered with dtn, "
       
   872                                  "regid: %d local eid: %s\n",
       
   873                                  regid, local_eid.uri);
       
   874 
       
   875     // get to work
       
   876     // this fn will likely never exit so the handle won't be closed...
       
   877     receive_bpq(&handle,
       
   878         regid,
       
   879         matching_filename,
       
   880         count,
       
   881         bundle_expiry,
       
   882         priority,
       
   883         delivery_options,
       
   884         verbose);
       
   885 
       
   886 // UNREACHABLE CODE if count = -1 //////////////////////////////////////////////
       
   887 
       
   888     // close the ipc handle
       
   889     if (verbose) fprintf(stdout, "closing connection to dtn router...\n");
       
   890     dtn_close(handle);
       
   891     if (verbose) fprintf(stdout, "closed connection to dtn router...\n");
       
   892 
       
   893     return 0;
       
   894 
       
   895 // UNREACHABLE CODE if count = -1 //////////////////////////////////////////////
       
   896 }
       
   897