BundleCommand.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2004-2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
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),  // bundle TTL
00063       length_(0),  // bundle payload length
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     // no options specified:
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     // need a subcommand
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         // bundle inject <source> <dest> <payload> <param1<=value1?>?> ... <paramN<=valueN?>?>
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         // now process any optional parameters:
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             // explicit length but some of the data may just be left
00146             // as garbage. 
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             // make sure to write a byte at the end of the payload to
00153             // properly fool the BundlePayload into thinking that we
00154             // actually got all the data
00155             u_char byte = 0;
00156             b->payload_.write_data(&byte, options.length_ - 1, 1);
00157             
00158             payload_len = options.length_;
00159         } else {
00160             // use the object length
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         // return the creation timestamp (can use with source EID to
00180         // create a globally unique bundle identifier
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         // bundle [info|dump|dump_ascii|expire] <id>
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 } // namespace dtn

Generated on Thu Jun 7 12:54:25 2007 for DTN Reference Implementation by  doxygen 1.5.1