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