00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 # include <dtn-config.h>
00019 #endif
00020
00021 #include <assert.h>
00022 #include <stdio.h>
00023 #include <unistd.h>
00024 #include <errno.h>
00025 #include <string.h>
00026 #include <strings.h>
00027 #include <stdlib.h>
00028 #include <sys/time.h>
00029 #include <time.h>
00030
00031 #ifdef __FreeBSD__
00032
00033 #include <sys/syslimits.h>
00034 #endif
00035
00036 #ifndef PATH_MAX
00037
00038 #define PATH_MAX 1024
00039 #endif
00040
00041 #include <vector>
00042
00043 #include "dtn_api.h"
00044
00045 char *progname;
00046
00047
00048 int copies = 1;
00049 int verbose = 0;
00050 int sleep_time = 0;
00051 int wait_for_report = 0;
00052
00053
00054 int expiration = 3600;
00055 int delivery_options = 0;
00056 dtn_bundle_priority_t priority = COS_NORMAL;
00057
00058
00059 dtn_bundle_payload_location_t
00060 payload_type = DTN_PAYLOAD_FILE;
00061 char * data_source = NULL;
00062 char date_buf[256];
00063
00064
00065 class ExtBlock {
00066 public:
00067 ExtBlock(u_int type = 0): metadata_(false) {
00068 block_.type = type;
00069 block_.flags = 0;
00070 block_.data.data_len = 0;
00071 block_.data.data_val = NULL;
00072 }
00073 ~ExtBlock() {
00074 if (block_.data.data_val != NULL) {
00075 free(block_.data.data_val);
00076 block_.data.data_val = NULL;
00077 block_.data.data_len = 0;
00078 }
00079 }
00080
00081 ExtBlock(const ExtBlock& o)
00082 {
00083 metadata_ = o.metadata_;
00084 block_.type = o.block_.type;
00085 block_.flags = o.block_.flags;
00086 block_.data.data_len = o.block_.data.data_len;
00087 block_.data.data_val = (char*)malloc(block_.data.data_len);
00088 memcpy(block_.data.data_val, o.block_.data.data_val,
00089 block_.data.data_len);
00090 }
00091
00092 bool metadata() const { return metadata_; }
00093 void set_metadata() { metadata_ = true; }
00094
00095 dtn_extension_block_t & block() { return block_; }
00096 void set_block_buf(char * buf, u_int len) {
00097 if (block_.data.data_val != NULL) {
00098 free(block_.data.data_val);
00099 block_.data.data_val = NULL;
00100 block_.data.data_len = 0;
00101 }
00102 block_.data.data_val = buf;
00103 block_.data.data_len = len;
00104 }
00105
00106 static unsigned int num_meta_blocks_;
00107
00108 private:
00109 bool metadata_;
00110 dtn_extension_block_t block_;
00111 };
00112 unsigned int ExtBlock::num_meta_blocks_ = 0;
00113
00114 std::vector<ExtBlock> ext_blocks;
00115
00116
00117 char * arg_replyto = NULL;
00118 char * arg_source = NULL;
00119 char * arg_dest = NULL;
00120
00121 dtn_reg_id_t regid = DTN_REGID_NONE;
00122
00123
00124 void parse_options(int, char**);
00125 dtn_endpoint_id_t * parse_eid(dtn_handle_t handle,
00126 dtn_endpoint_id_t * eid,
00127 char * str);
00128 void print_usage();
00129 void print_eid(char * label, dtn_endpoint_id_t * eid);
00130 void fill_payload(dtn_bundle_payload_t* payload);
00131
00132 int
00133 main(int argc, char** argv)
00134 {
00135 int i;
00136 int ret;
00137 dtn_handle_t handle;
00138 dtn_reg_info_t reginfo;
00139 dtn_bundle_spec_t bundle_spec;
00140 dtn_bundle_spec_t reply_spec;
00141 dtn_bundle_id_t bundle_id;
00142 dtn_bundle_payload_t send_payload;
00143 dtn_bundle_payload_t reply_payload;
00144 struct timeval start, end;
00145
00146
00147
00148 setvbuf(stdout, (char *)NULL, _IOLBF, 0);
00149
00150 parse_options(argc, argv);
00151
00152
00153 if (verbose) fprintf(stdout, "Opening connection to local DTN daemon\n");
00154
00155 int err = dtn_open(&handle);
00156 if (err != DTN_SUCCESS) {
00157 fprintf(stderr, "fatal error opening dtn handle: %s\n",
00158 dtn_strerror(err));
00159 exit(1);
00160 }
00161
00162
00163 memset(&bundle_spec, 0, sizeof(bundle_spec));
00164
00165
00166 if (verbose) fprintf(stdout, "Destination: %s\n", arg_dest);
00167 parse_eid(handle, &bundle_spec.dest, arg_dest);
00168
00169 if (verbose) fprintf(stdout, "Source: %s\n", arg_source);
00170 parse_eid(handle, &bundle_spec.source, arg_source);
00171 if (arg_replyto == NULL)
00172 {
00173 if (verbose) fprintf(stdout, "Reply To: same as source\n");
00174 dtn_copy_eid(&bundle_spec.replyto, &bundle_spec.source);
00175 }
00176 else
00177 {
00178 if (verbose) fprintf(stdout, "Reply To: %s\n", arg_replyto);
00179 parse_eid(handle, &bundle_spec.replyto, arg_replyto);
00180 }
00181
00182 if (verbose)
00183 {
00184 print_eid("source_eid", &bundle_spec.source);
00185 print_eid("replyto_eid", &bundle_spec.replyto);
00186 print_eid("dest_eid", &bundle_spec.dest);
00187 }
00188
00189 if (wait_for_report)
00190 {
00191
00192 memset(®info, 0, sizeof(reginfo));
00193 dtn_copy_eid(®info.endpoint, &bundle_spec.replyto);
00194 reginfo.flags = DTN_REG_DROP;
00195 reginfo.regid = regid;
00196 reginfo.expiration = 60 * 60;
00197 if ((ret = dtn_register(handle, ®info, ®id)) != 0) {
00198 fprintf(stderr, "error creating registration (id=%d): %d (%s)\n",
00199 regid, ret, dtn_strerror(dtn_errno(handle)));
00200 exit(1);
00201 }
00202
00203 if (verbose) printf("dtn_register succeeded, regid 0x%x\n", regid);
00204 }
00205
00206
00207 bundle_spec.expiration = expiration;
00208 bundle_spec.dopts = delivery_options;
00209 bundle_spec.priority = priority;
00210
00211
00212 unsigned int num_ext_blocks = ext_blocks.size() - ExtBlock::num_meta_blocks_;
00213 unsigned int num_meta_blocks = ExtBlock::num_meta_blocks_;
00214
00215 if (num_ext_blocks > 0) {
00216 void* buf = malloc(num_ext_blocks * sizeof(dtn_extension_block_t));
00217 memset(buf, 0, num_ext_blocks * sizeof(dtn_extension_block_t));
00218
00219 dtn_extension_block_t * bp = (dtn_extension_block_t *)buf;
00220 for (unsigned int i = 0; i < ext_blocks.size(); ++i) {
00221 if (ext_blocks[i].metadata()) {
00222 continue;
00223 }
00224
00225 bp->type = ext_blocks[i].block().type;
00226 bp->flags = ext_blocks[i].block().flags;
00227 bp->data.data_len = ext_blocks[i].block().data.data_len;
00228 bp->data.data_val = ext_blocks[i].block().data.data_val;
00229 bp++;
00230 }
00231
00232 bundle_spec.blocks.blocks_len = num_ext_blocks;
00233 bundle_spec.blocks.blocks_val = (dtn_extension_block_t *)buf;
00234 }
00235
00236 if (num_meta_blocks > 0) {
00237 void* buf = malloc(num_meta_blocks * sizeof(dtn_extension_block_t));
00238 memset(buf, 0, num_ext_blocks * sizeof(dtn_extension_block_t));
00239
00240 dtn_extension_block_t * bp = (dtn_extension_block_t *)buf;
00241 for (unsigned int i = 0; i < ext_blocks.size(); ++i) {
00242 if (!ext_blocks[i].metadata()) {
00243 continue;
00244 }
00245
00246 bp->type = ext_blocks[i].block().type;
00247 bp->flags = ext_blocks[i].block().flags;
00248 bp->data.data_len = ext_blocks[i].block().data.data_len;
00249 bp->data.data_val = ext_blocks[i].block().data.data_val;
00250 bp++;
00251 }
00252
00253 bundle_spec.metadata.metadata_len = num_meta_blocks;
00254 bundle_spec.metadata.metadata_val = (dtn_extension_block_t *)buf;
00255 }
00256
00257
00258 for (i = 0; i < copies; ++i) {
00259 gettimeofday(&start, NULL);
00260
00261 fill_payload(&send_payload);
00262
00263 memset(&bundle_id, 0, sizeof(bundle_id));
00264
00265 if ((ret = dtn_send(handle, regid, &bundle_spec, &send_payload,
00266 &bundle_id)) != 0)
00267 {
00268 fprintf(stderr, "error sending bundle: %d (%s)\n",
00269 ret, dtn_strerror(dtn_errno(handle)));
00270 exit(1);
00271 }
00272
00273 if (verbose) fprintf(stdout, "bundle sent successfully: id %s,%u.%u\n",
00274 bundle_id.source.uri,
00275 bundle_id.creation_ts.secs,
00276 bundle_id.creation_ts.seqno);
00277
00278 if (wait_for_report)
00279 {
00280 memset(&reply_spec, 0, sizeof(reply_spec));
00281 memset(&reply_payload, 0, sizeof(reply_payload));
00282
00283
00284 if ((ret = dtn_recv(handle, &reply_spec,
00285 DTN_PAYLOAD_MEM, &reply_payload,
00286 DTN_TIMEOUT_INF)) < 0)
00287 {
00288 fprintf(stderr, "error getting reply: %d (%s)\n",
00289 ret, dtn_strerror(dtn_errno(handle)));
00290 exit(1);
00291 }
00292 gettimeofday(&end, NULL);
00293
00294 printf("got %d byte report from [%s]: time=%.1f ms\n",
00295 reply_payload.buf.buf_len,
00296 reply_spec.source.uri,
00297 ((double)(end.tv_sec - start.tv_sec) * 1000.0 +
00298 (double)(end.tv_usec - start.tv_usec)/1000.0));
00299 }
00300
00301 if (sleep_time != 0) {
00302 usleep(sleep_time * 1000);
00303 }
00304 }
00305
00306 dtn_close(handle);
00307
00308 if (num_ext_blocks > 0) {
00309 assert(bundle_spec.blocks.blocks_val != NULL);
00310 free(bundle_spec.blocks.blocks_val);
00311 bundle_spec.blocks.blocks_val = NULL;
00312 bundle_spec.blocks.blocks_len = 0;
00313 }
00314
00315 if (num_meta_blocks > 0) {
00316 assert(bundle_spec.metadata.metadata_val != NULL);
00317 free(bundle_spec.metadata.metadata_val);
00318 bundle_spec.metadata.metadata_val = NULL;
00319 bundle_spec.metadata.metadata_len = 0;
00320 }
00321
00322 return 0;
00323 }
00324
00325 void print_usage()
00326 {
00327 fprintf(stderr, "usage: %s [opts] "
00328 "-s <source_eid> -d <dest_eid> -t <type> -p <payload>\n",
00329 progname);
00330 fprintf(stderr, "options:\n");
00331 fprintf(stderr, " -v verbose\n");
00332 fprintf(stderr, " -h help\n");
00333 fprintf(stderr, " -s <eid|demux_string> source eid)\n");
00334 fprintf(stderr, " -d <eid|demux_string> destination eid)\n");
00335 fprintf(stderr, " -r <eid|demux_string> reply to eid)\n");
00336 fprintf(stderr, " -t <f|t|m|d> payload type: file, tmpfile, message, or date\n");
00337 fprintf(stderr, " -p <filename|string> payload data\n");
00338 fprintf(stderr, " -e <time> expiration time in seconds (default: one hour)\n");
00339 fprintf(stderr, " -P <priority> one of bulk, normal, expedited, or reserved\n");
00340 fprintf(stderr, " -i <regid> registration id for reply to\n");
00341 fprintf(stderr, " -n <int> copies of the bundle to send\n");
00342 fprintf(stderr, " -z <time> msecs to sleep between transmissions\n");
00343 fprintf(stderr, " -c request custody transfer\n");
00344 fprintf(stderr, " -C request custody transfer receipts\n");
00345 fprintf(stderr, " -D request for end-to-end delivery receipt\n");
00346 fprintf(stderr, " -X request for deletion receipt\n");
00347 fprintf(stderr, " -R request for bundle reception receipts\n");
00348 fprintf(stderr, " -F request for bundle forwarding receipts\n");
00349 fprintf(stderr, " -1 assert destination endpoint is a singleton\n");
00350 fprintf(stderr, " -N assert destination endpoint is not a singleton\n");
00351 fprintf(stderr, " -W set the do not fragment option\n");
00352 fprintf(stderr, " -w wait for bundle status reports\n");
00353 fprintf(stderr, " -E <int> include extension block and specify type\n");
00354 fprintf(stderr, " -M <int> include metadata block and specify type\n");
00355 fprintf(stderr, " -O <int> flags to include in extension/metadata block\n");
00356 fprintf(stderr, " -S <string> extension/metadata block content\n");
00357 exit(1);
00358 }
00359
00360 void parse_options(int argc, char**argv)
00361 {
00362 int c, done = 0;
00363 char arg_type = 0;
00364
00365 progname = argv[0];
00366
00367 while (!done)
00368 {
00369 c = getopt(argc, argv, "vhHr:s:d:e:P:n:woDXFRcC1NWt:p:i:z:E:M:O:S:");
00370 switch (c)
00371 {
00372 case 'v':
00373 verbose = 1;
00374 break;
00375 case 'h':
00376 case 'H':
00377 print_usage();
00378 exit(0);
00379 return;
00380 case 'r':
00381 arg_replyto = optarg;
00382 break;
00383 case 's':
00384 arg_source = optarg;
00385 break;
00386 case 'd':
00387 arg_dest = optarg;
00388 break;
00389 case 'e':
00390 expiration = atoi(optarg);
00391 break;
00392 case 'P':
00393 if (!strcasecmp(optarg, "bulk")) {
00394 priority = COS_BULK;
00395 } else if (!strcasecmp(optarg, "normal")) {
00396 priority = COS_NORMAL;
00397 } else if (!strcasecmp(optarg, "expedited")) {
00398 priority = COS_EXPEDITED;
00399 } else if (!strcasecmp(optarg, "reserved")) {
00400 priority = COS_RESERVED;
00401 } else {
00402 fprintf(stderr, "invalid priority value %s\n", optarg);
00403 exit(1);
00404 }
00405 break;
00406 case 'n':
00407 copies = atoi(optarg);
00408 break;
00409 case 'w':
00410 wait_for_report = 1;
00411 break;
00412 case 'D':
00413 delivery_options |= DOPTS_DELIVERY_RCPT;
00414 break;
00415 case 'X':
00416 delivery_options |= DOPTS_DELETE_RCPT;
00417 break;
00418 case 'F':
00419 delivery_options |= DOPTS_FORWARD_RCPT;
00420 break;
00421 case 'R':
00422 delivery_options |= DOPTS_RECEIVE_RCPT;
00423 break;
00424 case 'c':
00425 delivery_options |= DOPTS_CUSTODY;
00426 break;
00427 case 'C':
00428 delivery_options |= DOPTS_CUSTODY_RCPT;
00429 break;
00430 case '1':
00431 delivery_options |= DOPTS_SINGLETON_DEST;
00432 break;
00433 case 'N':
00434 delivery_options |= DOPTS_MULTINODE_DEST;
00435 break;
00436 case 'W':
00437 delivery_options |= DOPTS_DO_NOT_FRAGMENT;
00438 break;
00439 case 't':
00440 arg_type = optarg[0];
00441 break;
00442 case 'p':
00443 data_source = strdup(optarg);
00444 break;
00445 case 'i':
00446 regid = atoi(optarg);
00447 break;
00448 case 'z':
00449 sleep_time = atoi(optarg);
00450 break;
00451 case 'E':
00452 ext_blocks.push_back(ExtBlock(atoi(optarg)));
00453 break;
00454 case 'M':
00455 ext_blocks.push_back(ExtBlock(atoi(optarg)));
00456 ext_blocks.back().set_metadata();
00457 ExtBlock::num_meta_blocks_++;
00458 break;
00459 case 'O':
00460 if (ext_blocks.size() > 0) {
00461 ext_blocks.back().block().flags = atoi(optarg);
00462 }
00463 break;
00464 case 'S':
00465 if (ext_blocks.size() > 0) {
00466 char * block_buf = strdup(optarg);
00467 ext_blocks.back().set_block_buf(block_buf, strlen(block_buf));
00468 }
00469 break;
00470 case -1:
00471 done = 1;
00472 break;
00473 default:
00474
00475
00476 print_usage();
00477 exit(1);
00478 }
00479 }
00480
00481 #define CHECK_SET(_arg, _what) \
00482 if (_arg == 0) { \
00483 fprintf(stderr, "dtnsend: %s must be specified\n", _what); \
00484 print_usage(); \
00485 exit(1); \
00486 }
00487
00488 CHECK_SET(arg_source, "source eid");
00489 CHECK_SET(arg_dest, "destination eid");
00490 CHECK_SET(arg_type, "payload type");
00491 if (arg_type != 'd') {
00492 CHECK_SET(data_source, "payload data");
00493 }
00494
00495 switch (arg_type)
00496 {
00497 case 'f': payload_type = DTN_PAYLOAD_FILE; break;
00498 case 't': payload_type = DTN_PAYLOAD_TEMP_FILE; break;
00499 case 'm': payload_type = DTN_PAYLOAD_MEM; break;
00500 case 'd':
00501 payload_type = DTN_PAYLOAD_MEM;
00502 data_source = date_buf;
00503 break;
00504 default:
00505 fprintf(stderr, "dtnsend: type argument '%d' invalid\n", arg_type);
00506 print_usage();
00507 exit(1);
00508 }
00509
00510
00511 if ( arg_type == 'f' && data_source[0] != '/' )
00512 {
00513 char fullpath[PATH_MAX];
00514
00515 if ( getcwd(fullpath, PATH_MAX) == NULL )
00516 {
00517 perror("cwd");
00518 exit(1);
00519 }
00520
00521 strncat(fullpath, "/", PATH_MAX - strlen(fullpath) - 1 );
00522 strncat(fullpath, data_source, PATH_MAX - strlen(fullpath) - 1);
00523
00524 free(data_source);
00525
00526 data_source = (char*)malloc(sizeof(char)*(strlen(fullpath) + 1));
00527 memcpy(data_source, fullpath, sizeof(char)*(strlen(fullpath) + 1));
00528 }
00529 }
00530
00531 dtn_endpoint_id_t * parse_eid(dtn_handle_t handle,
00532 dtn_endpoint_id_t* eid, char * str)
00533 {
00534
00535 if (!dtn_parse_eid_string(eid, str))
00536 {
00537 if (verbose) fprintf(stdout, "%s (literal)\n", str);
00538 return eid;
00539 }
00540
00541
00542 else if (!dtn_build_local_eid(handle, eid, str))
00543 {
00544 if (verbose) fprintf(stdout, "%s (local)\n", str);
00545 return eid;
00546 }
00547 else
00548 {
00549 fprintf(stderr, "invalid eid string '%s'\n", str);
00550 exit(1);
00551 }
00552 }
00553
00554 void print_eid(char * label, dtn_endpoint_id_t * eid)
00555 {
00556 printf("%s [%s]\n", label, eid->uri);
00557 }
00558
00559 void fill_payload(dtn_bundle_payload_t* payload)
00560 {
00561 memset(payload, 0, sizeof(*payload));
00562
00563 if (data_source == date_buf) {
00564 time_t current = time(NULL);
00565 strcpy(date_buf, ctime(¤t));
00566 }
00567
00568
00569
00570
00571 if (copies != 1 && payload_type == DTN_PAYLOAD_TEMP_FILE) {
00572 char tmp[PATH_MAX];
00573 snprintf(tmp, PATH_MAX, "%s.tmplink", data_source);
00574
00575 if (link(data_source, tmp) != 0) {
00576 fprintf(stderr, "error creating hard link %s -> %s: %s",
00577 data_source, tmp, strerror(errno));
00578 exit(1);
00579 }
00580
00581 dtn_set_payload(payload, payload_type, tmp, strlen(tmp));
00582 } else {
00583 dtn_set_payload(payload, payload_type, data_source, strlen(data_source));
00584 }
00585 }