00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <errno.h>
00019 #include <oasys/debug/Log.h>
00020 #include <oasys/io/NetUtils.h>
00021 #include <oasys/tclcmd/ConsoleCommand.h>
00022 #include <oasys/tclcmd/TclCommand.h>
00023 #include <oasys/util/Getopt.h>
00024 #include <oasys/util/OptParser.h>
00025
00026 #include <dtn_api.h>
00027 #include <dtn_ipc.h>
00028 #include <APIEndpointIDOpt.h>
00029
00030 typedef std::map<int, dtn_handle_t> HandleMap;
00031
00032 struct State : public oasys::Singleton<State> {
00033 State() : handle_num_(0) {}
00034
00035 HandleMap handles_;
00036 int handle_num_;
00037 };
00038
00039 template <> State* oasys::Singleton<State>::instance_ = 0;
00040
00041 extern int dtnipc_version;
00042
00043
00044 class DTNOpenCommand : public oasys::TclCommand {
00045 public:
00046 oasys::OptParser parser_;
00047
00048 struct OpenOpts {
00049 u_int16_t version_;
00050 };
00051
00052 OpenOpts opts_;
00053
00054 void init_opts() {
00055 opts_.version_ = DTN_IPC_VERSION;
00056 }
00057
00058 DTNOpenCommand() : TclCommand("dtn_open") {
00059 parser_.addopt(new oasys::UInt16Opt("version", &opts_.version_));
00060 }
00061
00062 int exec(int argc, const char **argv, Tcl_Interp* interp)
00063 {
00064 (void)argc;
00065 (void)argv;
00066 (void)interp;
00067
00068 if (argc < 1 || argc > 2) {
00069 wrong_num_args(argc, argv, 1, 1, 2);
00070 return TCL_ERROR;
00071 }
00072
00073 init_opts();
00074
00075 const char* invalid = 0;
00076 if (! parser_.parse(argc - 1, argv + 1, &invalid)) {
00077 resultf("invalid option '%s'", invalid);
00078 return TCL_ERROR;
00079 }
00080
00081 dtnipc_version = opts_.version_;
00082 dtn_handle_t handle;
00083 int err = dtn_open(&handle);
00084 if (err != DTN_SUCCESS) {
00085 resultf("can't connect to dtn daemon: %s",
00086 dtn_strerror(err));
00087 return TCL_ERROR;
00088 }
00089
00090 int n = State::instance()->handle_num_++;
00091 State::instance()->handles_[n] = handle;
00092
00093 resultf("%d", n);
00094 return TCL_OK;
00095 }
00096 };
00097
00098
00099 class DTNCloseCommand : public oasys::TclCommand {
00100 public:
00101 DTNCloseCommand() : TclCommand("dtn_close") {}
00102 int exec(int argc, const char **argv, Tcl_Interp* interp)
00103 {
00104 (void)argc;
00105 (void)argv;
00106 (void)interp;
00107
00108 if (argc != 2) {
00109 wrong_num_args(argc, argv, 1, 2, 2);
00110 return TCL_ERROR;
00111 }
00112
00113 int n = atoi(argv[1]);
00114 HandleMap::iterator iter = State::instance()->handles_.find(n);
00115 if (iter == State::instance()->handles_.end()) {
00116 resultf("invalid dtn handle %d", n);
00117 return TCL_ERROR;
00118 }
00119
00120 dtn_handle_t h = iter->second;
00121 dtn_close(h);
00122
00123 return TCL_OK;
00124 }
00125 };
00126
00127
00128 oasys::EnumOpt::Case FailureActionCases[] = {
00129 {"drop", DTN_REG_DROP},
00130 {"defer", DTN_REG_DEFER},
00131 {"exec", DTN_REG_EXEC},
00132 {0, 0}
00133 };
00134
00135 class DTNRegisterCommand : public oasys::TclCommand {
00136 public:
00137 oasys::OptParser parser_;
00138
00139 struct RegistrationOpts {
00140 dtn_endpoint_id_t endpoint_;
00141 int failure_action_;
00142 u_int expiration_;
00143 std::string script_;
00144 bool init_passive_;
00145 };
00146
00147 RegistrationOpts opts_;
00148
00149 void init_opts() {
00150 memset(&opts_.endpoint_, 0, sizeof(opts_.endpoint_));
00151 opts_.failure_action_ = DTN_REG_DROP;
00152 opts_.expiration_ = 0;
00153 opts_.script_ = "";
00154 opts_.init_passive_ = false;
00155 }
00156
00157 DTNRegisterCommand() : TclCommand("dtn_register")
00158 {
00159 parser_.addopt(new dtn::APIEndpointIDOpt("endpoint", &opts_.endpoint_));
00160 parser_.addopt(new oasys::EnumOpt("failure_action",
00161 FailureActionCases,
00162 &opts_.failure_action_));
00163 parser_.addopt(new oasys::UIntOpt("expiration", &opts_.expiration_));
00164 parser_.addopt(new oasys::StringOpt("script", &opts_.script_));
00165 parser_.addopt(new oasys::BoolOpt("init_passive",
00166 &opts_.init_passive_));
00167 }
00168
00169 int exec(int argc, const char **argv, Tcl_Interp* interp)
00170 {
00171 (void)argc;
00172 (void)argv;
00173 (void)interp;
00174
00175
00176 if (argc < 4) {
00177 wrong_num_args(argc, argv, 1, 4, INT_MAX);
00178 return TCL_ERROR;
00179 }
00180
00181 int n = atoi(argv[1]);
00182 HandleMap::iterator iter = State::instance()->handles_.find(n);
00183 if (iter == State::instance()->handles_.end()) {
00184 resultf("invalid dtn handle %d", n);
00185 return TCL_ERROR;
00186 }
00187
00188 dtn_handle_t h = iter->second;
00189
00190 init_opts();
00191 const char* invalid = 0;
00192 if (! parser_.parse(argc - 2, argv + 2, &invalid)) {
00193 resultf("invalid option '%s'", invalid);
00194 return TCL_ERROR;
00195 }
00196
00197 if (opts_.endpoint_.uri[0] == 0) {
00198 resultf("must set endpoint id");
00199 return TCL_ERROR;
00200 }
00201
00202 if (opts_.expiration_ == 0) {
00203 resultf("must set expiration");
00204 return TCL_ERROR;
00205 }
00206
00207 dtn_reg_info_t reginfo;
00208 memset(®info, 0, sizeof(reginfo));
00209
00210 dtn_copy_eid(®info.endpoint, &opts_.endpoint_);
00211 reginfo.failure_action =
00212 (dtn_reg_failure_action_t)opts_.failure_action_;
00213 reginfo.expiration = opts_.expiration_;
00214 reginfo.script.script_len = opts_.script_.length();
00215 reginfo.script.script_val = (char*)opts_.script_.c_str();
00216 reginfo.init_passive = opts_.init_passive_;
00217
00218 dtn_reg_id_t regid = 0;
00219
00220 int ret = dtn_register(h, ®info, ®id);
00221 if (ret != DTN_SUCCESS) {
00222 resultf("error in dtn_register: %s",
00223 dtn_strerror(dtn_errno(h)));
00224 return TCL_ERROR;
00225 }
00226
00227 resultf("%u", regid);
00228 return TCL_OK;
00229 }
00230 };
00231
00232
00233 class DTNUnregisterCommand : public oasys::TclCommand {
00234 public:
00235 DTNUnregisterCommand() : TclCommand("dtn_unregister") {}
00236 int exec(int argc, const char **argv, Tcl_Interp* interp)
00237 {
00238 (void)interp;
00239
00240 if (argc != 3) {
00241 wrong_num_args(argc, argv, 1, 3, 3);
00242 return TCL_ERROR;
00243 }
00244
00245 int n = atoi(argv[1]);
00246 HandleMap::iterator iter = State::instance()->handles_.find(n);
00247 if (iter == State::instance()->handles_.end()) {
00248 resultf("invalid dtn handle %d", n);
00249 return TCL_ERROR;
00250 }
00251
00252 dtn_handle_t h = iter->second;
00253
00254 dtn_reg_id_t regid = atoi(argv[2]);
00255
00256 int err = dtn_unregister(h, regid);
00257 if (err != DTN_SUCCESS) {
00258 resultf("error in dtn_unregister: %s",
00259 dtn_strerror(dtn_errno(h)));
00260 return TCL_ERROR;
00261 }
00262
00263 return TCL_OK;
00264 }
00265 };
00266
00267
00268 oasys::EnumOpt::Case PriorityCases[] = {
00269 {"bulk", COS_BULK},
00270 {"normal", COS_NORMAL},
00271 {"expedited", COS_EXPEDITED},
00272 {0, 0}
00273 };
00274
00275 class DTNSendCommand : public oasys::TclCommand {
00276 public:
00277 struct SendOpts {
00278 dtn_endpoint_id_t source_;
00279 dtn_endpoint_id_t dest_;
00280 dtn_endpoint_id_t replyto_;
00281 int priority_;
00282 bool custody_xfer_;
00283 bool receive_rcpt_;
00284 bool custody_rcpt_;
00285 bool forward_rcpt_;
00286 bool delivery_rcpt_;
00287 bool deletion_rcpt_;
00288 u_int expiration_;
00289 char payload_data_[DTN_MAX_BUNDLE_MEM];
00290 size_t payload_data_len_;
00291 char payload_file_[DTN_MAX_PATH_LEN];
00292 size_t payload_file_len_;
00293 u_int block_type_;
00294 u_int block_flags_;
00295 char block_content_[DTN_MAX_BLOCK_LEN];
00296 size_t block_content_len_;
00297 };
00298
00299
00300
00301 oasys::OptParser parser_;
00302 SendOpts opts_;
00303
00304 void init_opts() {
00305 memset(&opts_, 0, sizeof(opts_));
00306 opts_.expiration_ = 5 * 60;
00307 }
00308
00309 DTNSendCommand() : TclCommand("dtn_send")
00310 {
00311 parser_.addopt(new dtn::APIEndpointIDOpt("source", &opts_.source_));
00312 parser_.addopt(new dtn::APIEndpointIDOpt("dest", &opts_.dest_));
00313 parser_.addopt(new dtn::APIEndpointIDOpt("replyto", &opts_.replyto_));
00314 parser_.addopt(new oasys::EnumOpt("priority", PriorityCases,
00315 &opts_.priority_));
00316 parser_.addopt(new oasys::BoolOpt("custody_xfer",
00317 &opts_.custody_xfer_));
00318 parser_.addopt(new oasys::BoolOpt("receive_rcpt",
00319 &opts_.receive_rcpt_));
00320 parser_.addopt(new oasys::BoolOpt("custody_rcpt",
00321 &opts_.custody_rcpt_));
00322 parser_.addopt(new oasys::BoolOpt("forward_rcpt",
00323 &opts_.forward_rcpt_));
00324 parser_.addopt(new oasys::BoolOpt("delivery_rcpt",
00325 &opts_.delivery_rcpt_));
00326 parser_.addopt(new oasys::BoolOpt("deletion_rcpt",
00327 &opts_.deletion_rcpt_));
00328 parser_.addopt(new oasys::UIntOpt("expiration",
00329 &opts_.expiration_));
00330 parser_.addopt(new oasys::CharBufOpt("payload_data",
00331 opts_.payload_data_,
00332 &opts_.payload_data_len_,
00333 sizeof(opts_.payload_data_)));
00334 parser_.addopt(new oasys::CharBufOpt("payload_file",
00335 opts_.payload_file_,
00336 &opts_.payload_file_len_,
00337 sizeof(opts_.payload_file_)));
00338 parser_.addopt(new oasys::UIntOpt("block_type", &opts_.block_type_));
00339 parser_.addopt(new oasys::UIntOpt("block_flags", &opts_.block_flags_));
00340 parser_.addopt(new oasys::CharBufOpt("block_content",
00341 opts_.block_content_,
00342 &opts_.block_content_len_,
00343 sizeof(opts_.block_content_)));
00344 }
00345
00346 int exec(int argc, const char **argv, Tcl_Interp* interp)
00347 {
00348 (void)argc;
00349 (void)argv;
00350 (void)interp;
00351
00352
00353 if (argc < 5) {
00354 wrong_num_args(argc, argv, 1, 5, INT_MAX);
00355 return TCL_ERROR;
00356 }
00357
00358 int n = atoi(argv[1]);
00359 HandleMap::iterator iter = State::instance()->handles_.find(n);
00360 if (iter == State::instance()->handles_.end()) {
00361 resultf("invalid dtn handle %d", n);
00362 return TCL_ERROR;
00363 }
00364
00365 dtn_handle_t h = iter->second;
00366
00367
00368 init_opts();
00369 const char* invalid = 0;
00370 if (! parser_.parse(argc - 2, argv + 2, &invalid)) {
00371 resultf("invalid option '%s'", invalid);
00372 return TCL_ERROR;
00373 }
00374
00375
00376 if (opts_.source_.uri[0] == 0) {
00377 resultf("must set source endpoint id");
00378 return TCL_ERROR;
00379 }
00380 if (opts_.dest_.uri[0] == 0) {
00381 resultf("must set dest endpoint id");
00382 return TCL_ERROR;
00383 }
00384 if (opts_.payload_data_len_ == 0 && opts_.payload_file_len_ == 0) {
00385 resultf("must set payload");
00386 return TCL_ERROR;
00387 }
00388
00389 dtn_bundle_spec_t spec;
00390 memset(&spec, 0, sizeof(spec));
00391 dtn_copy_eid(&spec.source, &opts_.source_);
00392 dtn_copy_eid(&spec.dest, &opts_.dest_);
00393 if (opts_.replyto_.uri[0] != 0) {
00394 dtn_copy_eid(&spec.replyto, &opts_.replyto_);
00395 }
00396 spec.priority = (dtn_bundle_priority_t)opts_.priority_;
00397 if (opts_.custody_xfer_) spec.dopts |= DOPTS_CUSTODY;
00398 if (opts_.receive_rcpt_) spec.dopts |= DOPTS_RECEIVE_RCPT;
00399 if (opts_.custody_rcpt_) spec.dopts |= DOPTS_CUSTODY_RCPT;
00400 if (opts_.forward_rcpt_) spec.dopts |= DOPTS_FORWARD_RCPT;
00401 if (opts_.delivery_rcpt_) spec.dopts |= DOPTS_DELIVERY_RCPT;
00402 if (opts_.deletion_rcpt_) spec.dopts |= DOPTS_DELETE_RCPT;
00403 spec.expiration = opts_.expiration_;
00404
00405 dtn_bundle_payload_t payload;
00406 memset(&payload, 0, sizeof(payload));
00407 if (opts_.payload_data_len_ != 0) {
00408 dtn_set_payload(&payload, DTN_PAYLOAD_MEM,
00409 opts_.payload_data_, opts_.payload_data_len_);
00410 } else {
00411 dtn_set_payload(&payload, DTN_PAYLOAD_FILE,
00412 opts_.payload_file_, opts_.payload_file_len_);
00413
00414 }
00415
00416 dtn_extension_block_t block;
00417 memset(&block, 0, sizeof(block));
00418 if (opts_.block_type_ > 0 && opts_.block_type_ < 255) {
00419 block.type = opts_.block_type_;
00420 if (opts_.block_flags_ < 255) {
00421 block.flags = opts_.block_flags_;
00422 }
00423 block.data.data_len = opts_.block_content_len_;
00424 block.data.data_val = opts_.block_content_;
00425
00426 spec.blocks.blocks_len = 1;
00427 spec.blocks.blocks_val = █
00428 }
00429
00430 dtn_bundle_id_t id;
00431 memset(&id, 0, sizeof(id));
00432
00433 int ret = dtn_send(h, &spec, &payload, &id);
00434 if (ret != DTN_SUCCESS) {
00435 resultf("error in dtn_send: %s",
00436 dtn_strerror(dtn_errno(h)));
00437 return TCL_ERROR;
00438 }
00439
00440 resultf("%s,%u.%u",
00441 id.source.uri, id.creation_ts.secs, id.creation_ts.seqno);
00442 return TCL_OK;
00443 }
00444 };
00445
00446
00447 class DTNBindCommand : public oasys::TclCommand {
00448 public:
00449 DTNBindCommand() : TclCommand("dtn_bind") {}
00450
00451 int exec(int argc, const char **argv, Tcl_Interp* interp)
00452 {
00453 (void)interp;
00454
00455 if (argc != 3) {
00456 wrong_num_args(argc, argv, 1, 3, 3);
00457 return TCL_ERROR;
00458 }
00459
00460 int n = atoi(argv[1]);
00461 HandleMap::iterator iter = State::instance()->handles_.find(n);
00462 if (iter == State::instance()->handles_.end()) {
00463 resultf("invalid dtn handle %d", n);
00464 return TCL_ERROR;
00465 }
00466
00467 dtn_handle_t h = iter->second;
00468
00469 dtn_reg_id_t regid = atoi(argv[2]);
00470
00471 int err = dtn_bind(h, regid);
00472 if (err != DTN_SUCCESS) {
00473 resultf("error in dtn_bind: %s",
00474 dtn_strerror(dtn_errno(h)));
00475 return TCL_ERROR;
00476 }
00477
00478 return TCL_OK;
00479 }
00480 };
00481
00482
00483 class DTNUnbindCommand : public oasys::TclCommand {
00484 public:
00485 DTNUnbindCommand() : TclCommand("dtn_unbind") {}
00486
00487 int exec(int argc, const char **argv, Tcl_Interp* interp)
00488 {
00489 (void)interp;
00490
00491 if (argc != 3) {
00492 wrong_num_args(argc, argv, 1, 3, 3);
00493 return TCL_ERROR;
00494 }
00495
00496 int n = atoi(argv[1]);
00497 HandleMap::iterator iter = State::instance()->handles_.find(n);
00498 if (iter == State::instance()->handles_.end()) {
00499 resultf("invalid dtn handle %d", n);
00500 return TCL_ERROR;
00501 }
00502
00503 dtn_handle_t h = iter->second;
00504
00505 dtn_reg_id_t regid = atoi(argv[2]);
00506
00507 int err = dtn_unbind(h, regid);
00508 if (err != DTN_SUCCESS) {
00509 resultf("error in dtn_unbind: %s",
00510 dtn_strerror(dtn_errno(h)));
00511 return TCL_ERROR;
00512 }
00513
00514 return TCL_OK;
00515 }
00516 };
00517
00518
00519 class DTNRecvCommand : public oasys::TclCommand {
00520 public:
00521 oasys::OptParser parser_;
00522
00523 struct RecvOpts {
00524 bool payload_mem_;
00525 bool payload_file_;
00526 u_int timeout_;
00527 };
00528
00529 RecvOpts opts_;
00530
00531 void init_opts() {
00532 memset(&opts_, 0, sizeof(opts_));
00533 }
00534
00535 DTNRecvCommand() : TclCommand("dtn_recv")
00536 {
00537 parser_.addopt(new oasys::BoolOpt("payload_mem", &opts_.payload_mem_));
00538 parser_.addopt(new oasys::BoolOpt("payload_file", &opts_.payload_file_));
00539 parser_.addopt(new oasys::UIntOpt("timeout", &opts_.timeout_));
00540 }
00541
00542 int exec(int argc, const char **argv, Tcl_Interp* interp)
00543 {
00544 (void)argc;
00545 (void)argv;
00546 (void)interp;
00547
00548
00549 if (argc < 3) {
00550 wrong_num_args(argc, argv, 1, 3, INT_MAX);
00551 return TCL_ERROR;
00552 }
00553
00554 int n = atoi(argv[1]);
00555 HandleMap::iterator iter = State::instance()->handles_.find(n);
00556 if (iter == State::instance()->handles_.end()) {
00557 resultf("invalid dtn handle %d", n);
00558 return TCL_ERROR;
00559 }
00560
00561 dtn_handle_t h = iter->second;
00562
00563 init_opts();
00564
00565 const char* invalid = 0;
00566 if (! parser_.parse(argc - 2, argv + 2, &invalid)) {
00567 resultf("invalid option '%s'", invalid);
00568 return TCL_ERROR;
00569 }
00570
00571 if (opts_.payload_mem_ == false && opts_.payload_file_ == false) {
00572 resultf("must set payload location");
00573 return TCL_ERROR;
00574 }
00575
00576 dtn_bundle_spec_t spec;
00577 memset(&spec, 0, sizeof(spec));
00578
00579 dtn_bundle_payload_t payload;
00580 memset(&payload, 0, sizeof(payload));
00581
00582 int err = dtn_recv(h, &spec,
00583 opts_.payload_mem_ ? DTN_PAYLOAD_MEM : DTN_PAYLOAD_FILE,
00584 &payload, opts_.timeout_);
00585 if (err != DTN_SUCCESS) {
00586 resultf("error in dtn_recv: %s",
00587 dtn_strerror(dtn_errno(h)));
00588 return TCL_ERROR;
00589 }
00590
00591 if (!opts_.payload_mem_) {
00592 char payload_path[PATH_MAX];
00593 memcpy(payload_path, payload.filename.filename_val,
00594 payload.filename.filename_len);
00595 payload_path[payload.filename.filename_len] = 0;
00596
00597 err = unlink(payload_path);
00598 if (err != 0) {
00599 log_err("error unlinking payload file '%s': %s",
00600 payload_path, strerror(errno));
00601 }
00602 }
00603
00604 dtn_free_payload(&payload);
00605
00606
00607
00608 return TCL_OK;
00609 }
00610 };
00611
00612
00613 class ShutdownCommand : public oasys::TclCommand {
00614 public:
00615 ShutdownCommand() : TclCommand("shutdown") {}
00616 static void call_exit(void* clientData);
00617 int exec(int argc, const char **argv, Tcl_Interp* interp);
00618 };
00619
00620 void
00621 ShutdownCommand::call_exit(void* clientData)
00622 {
00623 (void)clientData;
00624 exit(0);
00625 }
00626
00627
00628 int
00629 ShutdownCommand::exec(int argc, const char **argv, Tcl_Interp* interp)
00630 {
00631 (void)argc;
00632 (void)argv;
00633 (void)interp;
00634 Tcl_CreateTimerHandler(0, ShutdownCommand::call_exit, 0);
00635 return TCL_OK;
00636 }
00637
00638
00639 int
00640 main(int argc, char** argv)
00641 {
00642 oasys::TclCommandInterp* interp;
00643 oasys::ConsoleCommand* console_cmd;
00644 std::string conf_file;
00645 bool conf_file_set = false;
00646 bool daemon = false;
00647
00648 oasys::Log::init();
00649
00650 oasys::TclCommandInterp::init("dtn-test");
00651 interp = oasys::TclCommandInterp::instance();
00652
00653 oasys::Getopt opts;
00654 opts.addopt(
00655 new oasys::StringOpt('c', "conf", &conf_file, "<conf>",
00656 "set the configuration file", &conf_file_set));
00657
00658 opts.addopt(
00659 new oasys::BoolOpt('d', "daemon", &daemon,
00660 "run as a daemon"));
00661
00662 int remainder = opts.getopt(argv[0], argc, argv);
00663 if (remainder != argc)
00664 {
00665 fprintf(stderr, "invalid argument '%s'\n", argv[remainder]);
00666 opts.usage("dtn-test");
00667 exit(1);
00668 }
00669
00670 console_cmd = new oasys::ConsoleCommand("dtntest% ");
00671 interp->reg(console_cmd);
00672 interp->reg(new DTNOpenCommand());
00673 interp->reg(new DTNCloseCommand());
00674 interp->reg(new DTNRegisterCommand());
00675 interp->reg(new DTNUnregisterCommand());
00676 interp->reg(new DTNBindCommand());
00677 interp->reg(new DTNUnbindCommand());
00678 interp->reg(new DTNSendCommand());
00679 interp->reg(new DTNRecvCommand());
00680 interp->reg(new ShutdownCommand());
00681
00682 if (conf_file_set) {
00683 interp->exec_file(conf_file.c_str());
00684 }
00685
00686 log_notice_p("/dtn-test", "dtn-test starting up...");
00687
00688 if (console_cmd->port_ != 0) {
00689 log_notice_p("/dtn-test", "starting console on %s:%d",
00690 intoa(console_cmd->addr_), console_cmd->port_);
00691 interp->command_server("dtn-test", console_cmd->addr_, console_cmd->port_);
00692 }
00693
00694 if (daemon || (console_cmd->stdio_ == false)) {
00695 oasys::TclCommandInterp::instance()->event_loop();
00696 } else {
00697 oasys::TclCommandInterp::instance()->
00698 command_loop(console_cmd->prompt_.c_str());
00699 }
00700
00701 log_notice_p("/dtn-test", "dtn-test shutting down...");
00702 delete State::instance();
00703 oasys::TclCommandInterp::shutdown();
00704 oasys::Log::shutdown();
00705 }