00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <oasys/util/HexDumpBuffer.h>
00019 #include <oasys/util/StringBuffer.h>
00020 #include <oasys/util/OptParser.h>
00021
00022 #include "BundleCommand.h"
00023 #include "CompletionNotifier.h"
00024 #include "bundling/Bundle.h"
00025 #include "bundling/BundleEvent.h"
00026 #include "bundling/BundleDaemon.h"
00027 #include "reg/TclRegistration.h"
00028
00029 namespace dtn {
00030
00031 BundleCommand::BundleCommand()
00032 : TclCommand("bundle")
00033 {
00034 add_to_help("inject <src> <dst> <payload> <opt1=val1> .. <optN=valN>",
00035 "valid options:\n"
00036 " custody_xfer\n"
00037 " receive_rcpt\n"
00038 " custody_rcpt\n"
00039 " forward_rcpt\n"
00040 " delivery_rcpt\n"
00041 " deletion_rcpt\n"
00042 " expiration=integer\n"
00043 " length=integer\n");
00044 add_to_help("stats", "get statistics on the bundles");
00045 add_to_help("daemon_stats", "daemon stats");
00046 add_to_help("reset_stats", "reset currently maintained statistics");
00047 add_to_help("list", "list all of the bundles in the system");
00048 add_to_help("info <id>", "get info on a specific bundle");
00049 add_to_help("dump <id>", "dump a specific bundle");
00050 add_to_help("dump_tcl <id>", "dump a bundle as a tcl list");
00051 add_to_help("dump_ascii <id>", "dump the bundle in ascii");
00052 add_to_help("expire <id>", "force a specific bundle to expire");
00053 }
00054
00055 BundleCommand::InjectOpts::InjectOpts()
00056 : custody_xfer_(false),
00057 receive_rcpt_(false),
00058 custody_rcpt_(false),
00059 forward_rcpt_(false),
00060 delivery_rcpt_(false),
00061 deletion_rcpt_(false),
00062 expiration_(60),
00063 length_(0),
00064 replyto_("")
00065 {}
00066
00067 bool
00068 BundleCommand::parse_inject_options(InjectOpts* options,
00069 int objc, Tcl_Obj** objv,
00070 const char** invalidp)
00071 {
00072
00073 if (objc < 6) {
00074 return true;
00075 }
00076
00077 oasys::OptParser p;
00078
00079 p.addopt(new oasys::BoolOpt("custody_xfer", &options->custody_xfer_));
00080 p.addopt(new oasys::BoolOpt("receive_rcpt", &options->receive_rcpt_));
00081 p.addopt(new oasys::BoolOpt("custody_rcpt", &options->custody_rcpt_));
00082 p.addopt(new oasys::BoolOpt("forward_rcpt", &options->forward_rcpt_));
00083 p.addopt(new oasys::BoolOpt("delivery_rcpt", &options->delivery_rcpt_));
00084 p.addopt(new oasys::BoolOpt("deletion_rcpt", &options->deletion_rcpt_));
00085 p.addopt(new oasys::UIntOpt("expiration", &options->expiration_));
00086 p.addopt(new oasys::UIntOpt("length", &options->length_));
00087 p.addopt(new oasys::StringOpt("replyto", &options->replyto_));
00088
00089 for (int i=5; i<objc; i++) {
00090 int len;
00091 const char* option_name = Tcl_GetStringFromObj(objv[i], &len);
00092 if (! p.parse_opt(option_name, len)) {
00093 *invalidp = option_name;
00094 return false;
00095 }
00096 }
00097 return true;
00098 }
00099
00100 int
00101 BundleCommand::exec(int objc, Tcl_Obj** objv, Tcl_Interp* interp)
00102 {
00103
00104 if (objc < 2) {
00105 wrong_num_args(objc, objv, 1, 2, INT_MAX);
00106 return TCL_ERROR;
00107 }
00108
00109 const char* cmd = Tcl_GetStringFromObj(objv[1], 0);
00110
00111 if (strcmp(cmd, "inject") == 0) {
00112
00113 if (objc < 5) {
00114 wrong_num_args(objc, objv, 2, 5, INT_MAX);
00115 return TCL_ERROR;
00116 }
00117
00118 Bundle* b = new Bundle();
00119 b->source_.assign(Tcl_GetStringFromObj(objv[2], 0));
00120 b->replyto_.assign(Tcl_GetStringFromObj(objv[2], 0));
00121 b->custodian_.assign(EndpointID::NULL_EID());
00122 b->dest_.assign(Tcl_GetStringFromObj(objv[3], 0));
00123
00124 int payload_len;
00125 u_char* payload_data = Tcl_GetByteArrayFromObj(objv[4], &payload_len);
00126
00127
00128 InjectOpts options;
00129 const char* invalid;
00130 if (!parse_inject_options(&options, objc, objv, &invalid)) {
00131 resultf("error parsing bundle inject options: invalid option '%s'",
00132 invalid);
00133 return TCL_ERROR;
00134 }
00135
00136 b->custody_requested_ = options.custody_xfer_;
00137 b->receive_rcpt_ = options.receive_rcpt_;
00138 b->custody_rcpt_ = options.custody_rcpt_;
00139 b->forward_rcpt_ = options.forward_rcpt_;
00140 b->delivery_rcpt_ = options.delivery_rcpt_;
00141 b->deletion_rcpt_ = options.deletion_rcpt_;
00142 b->expiration_ = options.expiration_;
00143
00144 if (options.length_ != 0) {
00145
00146
00147 b->payload_.set_length(options.length_);
00148 if (payload_len != 0) {
00149 b->payload_.write_data(payload_data, payload_len, 0);
00150 }
00151
00152
00153
00154
00155 u_char byte = 0;
00156 b->payload_.write_data(&byte, options.length_ - 1, 1);
00157
00158 payload_len = options.length_;
00159 } else {
00160
00161 b->payload_.set_data(payload_data, payload_len);
00162 }
00163
00164 if (options.replyto_ != "") {
00165 b->replyto_.assign(options.replyto_.c_str());
00166 }
00167
00168 oasys::StringBuffer error;
00169 if (!b->validate(&error)) {
00170 resultf("bundle validation failed: %s", error.data());
00171 return TCL_ERROR;
00172 }
00173
00174 log_debug("inject %d byte bundle %s->%s", payload_len,
00175 b->source_.c_str(), b->dest_.c_str());
00176
00177 BundleDaemon::post(new BundleReceivedEvent(b, EVENTSRC_APP));
00178
00179
00180
00181 resultf("%u.%u", b->creation_ts_.seconds_, b->creation_ts_.seqno_);
00182 return TCL_OK;
00183
00184 } else if (!strcmp(cmd, "stats")) {
00185 oasys::StringBuffer buf("Bundle Statistics: ");
00186 BundleDaemon::instance()->get_bundle_stats(&buf);
00187 set_result(buf.c_str());
00188 return TCL_OK;
00189
00190 } else if (!strcmp(cmd, "daemon_stats")) {
00191 oasys::StringBuffer buf("Bundle Daemon Statistics: ");
00192 BundleDaemon::instance()->get_daemon_stats(&buf);
00193 set_result(buf.c_str());
00194 return TCL_OK;
00195 } else if (!strcmp(cmd, "daemon_status")) {
00196 BundleDaemon::post_and_wait(new StatusRequest(),
00197 CompletionNotifier::notifier());
00198 set_result("DTN daemon ok");
00199 return TCL_OK;
00200 } else if (!strcmp(cmd, "reset_stats")) {
00201 BundleDaemon::instance()->reset_stats();
00202 return TCL_OK;
00203
00204 } else if (!strcmp(cmd, "list")) {
00205 Bundle* b;
00206 BundleList::const_iterator iter;
00207 oasys::StringBuffer buf;
00208 BundleList* pending =
00209 BundleDaemon::instance()->pending_bundles();
00210
00211 oasys::ScopeLock l(pending->lock(), "BundleCommand::exec");
00212 buf.appendf("Currently Pending Bundles (%zu): \n", pending->size());
00213
00214 for (iter = pending->begin(); iter != pending->end(); ++iter) {
00215 b = *iter;
00216 buf.appendf("\t%-3d: %s -> %s length %zu\n",
00217 b->bundleid_,
00218 b->source_.c_str(),
00219 b->dest_.c_str(),
00220 b->payload_.length());
00221 }
00222
00223 set_result(buf.c_str());
00224
00225 return TCL_OK;
00226
00227 } else if (!strcmp(cmd, "info") ||
00228 !strcmp(cmd, "dump") ||
00229 !strcmp(cmd, "dump_tcl") ||
00230 !strcmp(cmd, "dump_ascii") ||
00231 !strcmp(cmd, "expire"))
00232 {
00233
00234 if (objc != 3) {
00235 wrong_num_args(objc, objv, 2, 3, 3);
00236 return TCL_ERROR;
00237 }
00238
00239 int bundleid;
00240 if (Tcl_GetIntFromObj(interp, objv[2], &bundleid) != TCL_OK) {
00241 resultf("invalid bundle id %s",
00242 Tcl_GetStringFromObj(objv[2], 0));
00243 return TCL_ERROR;
00244 }
00245
00246 BundleList* pending =
00247 BundleDaemon::instance()->pending_bundles();
00248
00249 BundleRef bundle = pending->find(bundleid);
00250
00251 if (bundle == NULL) {
00252 resultf("no bundle with id %d", bundleid);
00253 return TCL_ERROR;
00254 }
00255
00256 if (strcmp(cmd, "info") == 0) {
00257 oasys::StringBuffer buf;
00258 bundle->format_verbose(&buf);
00259 buf.append("\n");
00260 bundle->fwdlog_.dump(&buf);
00261 set_result(buf.c_str());
00262
00263 } else if (strcmp(cmd, "dump_tcl") == 0) {
00264 Tcl_Obj* result = NULL;
00265 int ok =
00266 TclRegistration::parse_bundle_data(interp, bundle, &result);
00267
00268 set_objresult(result);
00269 return ok;
00270
00271 } else if (strcmp(cmd, "dump_ascii") == 0) {
00272 size_t len = bundle->payload_.length();
00273 oasys::HexDumpBuffer buf(len);
00274 const u_char* bp =
00275 bundle->payload_.read_data(0, len, (u_char*)buf.data());
00276
00277 buf.append((const char*)bp, len);
00278 if (!strcmp(cmd, "dump")) {
00279 buf.hexify();
00280 }
00281 set_result(buf.c_str());
00282
00283 } else if (strcmp(cmd, "expire") == 0) {
00284 BundleDaemon::instance()->post_at_head(
00285 new BundleExpiredEvent(bundle.object()));
00286 return TCL_OK;
00287 }
00288
00289 return TCL_OK;
00290
00291 } else {
00292 resultf("unknown bundle subcommand %s", cmd);
00293 return TCL_ERROR;
00294 }
00295 }
00296
00297
00298 }