BundleCommand.cc

Go to the documentation of this file.
00001 /*
00002  * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By
00003  * downloading, copying, installing or using the software you agree to
00004  * this license. If you do not agree to this license, do not download,
00005  * install, copy or use the software.
00006  * 
00007  * Intel Open Source License 
00008  * 
00009  * Copyright (c) 2004 Intel Corporation. All rights reserved. 
00010  * 
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions are
00013  * met:
00014  * 
00015  *   Redistributions of source code must retain the above copyright
00016  *   notice, this list of conditions and the following disclaimer.
00017  * 
00018  *   Redistributions in binary form must reproduce the above copyright
00019  *   notice, this list of conditions and the following disclaimer in the
00020  *   documentation and/or other materials provided with the distribution.
00021  * 
00022  *   Neither the name of the Intel Corporation nor the names of its
00023  *   contributors may be used to endorse or promote products derived from
00024  *   this software without specific prior written permission.
00025  *  
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00027  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00028  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00029  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
00030  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00032  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00033  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00034  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00035  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00036  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037  */
00038 
00039 #include <oasys/util/HexDumpBuffer.h>
00040 #include <oasys/util/StringBuffer.h>
00041 #include <oasys/util/OptParser.h>
00042 
00043 #include "BundleCommand.h"
00044 #include "CompletionNotifier.h"
00045 #include "bundling/Bundle.h"
00046 #include "bundling/BundleEvent.h"
00047 #include "bundling/BundleDaemon.h"
00048 #include "reg/TclRegistration.h"
00049 
00050 namespace dtn {
00051 
00052 BundleCommand::BundleCommand()
00053     : TclCommand("bundle") 
00054 {
00055     add_to_help("inject <src> <dst> <payload> <opt1=val1> .. <optN=valN>",
00056                 "valid options:\n"
00057                 "            custody_xfer\n"
00058                 "            receive_rcpt\n"
00059                 "            custody_rcpt\n"
00060                 "            forward_rcpt\n"
00061                 "            delivery_rcpt\n"
00062                 "            deletion_rcpt\n"
00063                 "            expiration=integer\n"
00064                 "            length=integer\n");
00065     add_to_help("stats", "get statistics on the bundles");
00066     add_to_help("daemon_stats", "daemon stats");
00067     add_to_help("reset_stats", "reset currently maintained statistics");
00068     add_to_help("list", "list all of the bundles in the system");
00069     add_to_help("info <id>", "get info on a specific bundle");
00070     add_to_help("dump <id>", "dump a specific bundle");
00071     add_to_help("dump_tcl <id>", "dump a bundle as a tcl list");
00072     add_to_help("dump_ascii <id>", "dump the bundle in ascii");
00073 }
00074 
00075 BundleCommand::InjectOpts::InjectOpts()
00076     : custody_xfer_(false),
00077       receive_rcpt_(false), 
00078       custody_rcpt_(false), 
00079       forward_rcpt_(false), 
00080       delivery_rcpt_(false), 
00081       deletion_rcpt_(false), 
00082       expiration_(60),  // bundle TTL
00083       length_(0),  // bundle payload length
00084       replyto_("")
00085 {}
00086     
00087 bool
00088 BundleCommand::parse_inject_options(InjectOpts* options,
00089                                     int objc, Tcl_Obj** objv,
00090                                     const char** invalidp)
00091 {
00092     // no options specified:
00093     if (objc < 6) {
00094         return true;
00095     }
00096     
00097     oasys::OptParser p;
00098 
00099     p.addopt(new oasys::BoolOpt("custody_xfer",  &options->custody_xfer_));
00100     p.addopt(new oasys::BoolOpt("receive_rcpt",  &options->receive_rcpt_));
00101     p.addopt(new oasys::BoolOpt("custody_rcpt",  &options->custody_rcpt_));
00102     p.addopt(new oasys::BoolOpt("forward_rcpt",  &options->forward_rcpt_));
00103     p.addopt(new oasys::BoolOpt("delivery_rcpt", &options->delivery_rcpt_));
00104     p.addopt(new oasys::BoolOpt("deletion_rcpt", &options->deletion_rcpt_));
00105     p.addopt(new oasys::UIntOpt("expiration",    &options->expiration_));
00106     p.addopt(new oasys::UIntOpt("length",        &options->length_));
00107     p.addopt(new oasys::StringOpt("replyto",     &options->replyto_));
00108 
00109     for (int i=5; i<objc; i++) {
00110         int len;
00111         const char* option_name = Tcl_GetStringFromObj(objv[i], &len);
00112         if (! p.parse_opt(option_name, len)) {
00113             *invalidp = option_name;
00114             return false;
00115         }
00116     }
00117     return true;
00118 }
00119 
00120 int
00121 BundleCommand::exec(int objc, Tcl_Obj** objv, Tcl_Interp* interp)
00122 {
00123     // need a subcommand
00124     if (objc < 2) {
00125         wrong_num_args(objc, objv, 1, 2, INT_MAX);
00126         return TCL_ERROR;
00127     }
00128 
00129     const char* cmd = Tcl_GetStringFromObj(objv[1], 0);
00130 
00131     if (strcmp(cmd, "inject") == 0) {
00132         // bundle inject <source> <dest> <payload> <param1<=value1?>?> ... <paramN<=valueN?>?>
00133         if (objc < 5) {
00134             wrong_num_args(objc, objv, 2, 5, INT_MAX);
00135             return TCL_ERROR;
00136         }
00137         
00138         Bundle* b = new Bundle();
00139         b->source_.assign(Tcl_GetStringFromObj(objv[2], 0));
00140         b->replyto_.assign(Tcl_GetStringFromObj(objv[2], 0));
00141         b->custodian_.assign(EndpointID::NULL_EID());
00142         b->dest_.assign(Tcl_GetStringFromObj(objv[3], 0));
00143         
00144         int payload_len;
00145         u_char* payload_data = Tcl_GetByteArrayFromObj(objv[4], &payload_len);
00146 
00147         // now process any optional parameters:
00148         InjectOpts options;
00149         const char* invalid;
00150         if (!parse_inject_options(&options, objc, objv, &invalid)) {
00151             resultf("error parsing bundle inject options: invalid option '%s'",
00152                     invalid);
00153             return TCL_ERROR;
00154         }
00155 
00156         b->custody_requested_ = options.custody_xfer_;
00157         b->receive_rcpt_      = options.receive_rcpt_;
00158         b->custody_rcpt_      = options.custody_rcpt_;
00159         b->forward_rcpt_      = options.forward_rcpt_;
00160         b->delivery_rcpt_     = options.delivery_rcpt_;
00161         b->deletion_rcpt_     = options.deletion_rcpt_;
00162         b->expiration_        = options.expiration_;
00163 
00164         if (options.length_ != 0) {
00165             // explicit length but some of the data may just be left
00166             // as garbage. 
00167             b->payload_.set_length(options.length_);
00168             if (payload_len != 0) {
00169                 b->payload_.append_data(payload_data, payload_len);
00170             }
00171 
00172             // make sure to write a byte at the end of the payload to
00173             // properly fool the BundlePayload into thinking that we
00174             // actually got all the data
00175             u_char byte = 0;
00176             b->payload_.write_data(&byte, options.length_ - 1, 1);
00177             b->payload_.close_file();
00178             
00179             payload_len = options.length_;
00180         } else {
00181             // use the object length
00182             b->payload_.set_data(payload_data, payload_len);
00183         }
00184         
00185         if (options.replyto_ != "") {
00186             b->replyto_.assign(options.replyto_.c_str());
00187         }
00188 
00189         oasys::StringBuffer error;
00190         if (!b->validate(&error)) {
00191             resultf("bundle validation failed: %s", error.data());
00192             return TCL_ERROR;
00193         }
00194         
00195         log_debug("inject %d byte bundle %s->%s", payload_len,
00196                   b->source_.c_str(), b->dest_.c_str());
00197 
00198         BundleDaemon::post(new BundleReceivedEvent(b, EVENTSRC_APP, payload_len));
00199 
00200         // return the creation timestamp (can use with source EID to
00201         // create a globally unique bundle identifier
00202         resultf("%u.%u", b->creation_ts_.seconds_, b->creation_ts_.seqno_);
00203         return TCL_OK;
00204         
00205     } else if (!strcmp(cmd, "stats")) {
00206         oasys::StringBuffer buf("Bundle Statistics: ");
00207         BundleDaemon::instance()->get_bundle_stats(&buf);
00208         set_result(buf.c_str());
00209         return TCL_OK;
00210 
00211     } else if (!strcmp(cmd, "daemon_stats")) {
00212         oasys::StringBuffer buf("Bundle Daemon Statistics: ");
00213         BundleDaemon::instance()->get_daemon_stats(&buf);
00214         set_result(buf.c_str());
00215         return TCL_OK;
00216     } else if (!strcmp(cmd, "daemon_status")) {
00217         BundleDaemon::post_and_wait(new StatusRequest(),
00218                                     CompletionNotifier::notifier());
00219         set_result("DTN daemon ok");
00220         return TCL_OK;
00221     } else if (!strcmp(cmd, "reset_stats")) {
00222         BundleDaemon::instance()->reset_stats();
00223         return TCL_OK;
00224         
00225     } else if (!strcmp(cmd, "list")) {
00226         Bundle* b;
00227         BundleList::const_iterator iter;
00228         oasys::StringBuffer buf;
00229         BundleList* pending =
00230             BundleDaemon::instance()->pending_bundles();
00231         
00232         oasys::ScopeLock l(pending->lock(), "BundleCommand::exec");
00233         buf.appendf("Currently Pending Bundles (%zu): \n", pending->size());
00234     
00235         for (iter = pending->begin(); iter != pending->end(); ++iter) {
00236             b = *iter;
00237             buf.appendf("\t%-3d: %s -> %s length %zu\n",
00238                         b->bundleid_,
00239                         b->source_.c_str(),
00240                         b->dest_.c_str(),
00241                         b->payload_.length());
00242         }
00243         
00244         set_result(buf.c_str());
00245         
00246         return TCL_OK;
00247         
00248     } else if (!strcmp(cmd, "info") ||
00249                !strcmp(cmd, "dump") ||
00250                !strcmp(cmd, "dump_tcl") ||
00251                !strcmp(cmd, "dump_ascii"))
00252     {
00253         // bundle [info|dump|dump_ascii] <id>
00254         if (objc != 3) {
00255             wrong_num_args(objc, objv, 2, 3, 3);
00256             return TCL_ERROR;
00257         }
00258 
00259         int bundleid;
00260         if (Tcl_GetIntFromObj(interp, objv[2], &bundleid) != TCL_OK) {
00261             resultf("invalid bundle id %s",
00262                     Tcl_GetStringFromObj(objv[2], 0));
00263             return TCL_ERROR;
00264         }
00265 
00266         BundleList* pending =
00267             BundleDaemon::instance()->pending_bundles();
00268         
00269         BundleRef bundle = pending->find(bundleid);
00270 
00271         if (bundle == NULL) {
00272             resultf("no bundle with id %d", bundleid);
00273             return TCL_ERROR;
00274         }
00275 
00276         if (strcmp(cmd, "info") == 0) {
00277             oasys::StringBuffer buf;
00278             bundle->format_verbose(&buf);
00279             buf.append("\n");
00280             bundle->fwdlog_.dump(&buf);
00281             set_result(buf.c_str());
00282 
00283         } else if (strcmp(cmd, "dump_tcl") == 0) {
00284             Tcl_Obj* result = NULL;
00285             int ok =
00286                 TclRegistration::parse_bundle_data(interp, bundle, &result);
00287             
00288             set_objresult(result);
00289             return ok;
00290             
00291         } else {
00292             size_t len = bundle->payload_.length();
00293             oasys::HexDumpBuffer buf(len);
00294             const u_char* bp =
00295                 bundle->payload_.read_data(0, len, (u_char*)buf.data());
00296             
00297             // XXX/demmer inefficient
00298             buf.append((const char*)bp, len);
00299             if (!strcmp(cmd, "dump")) {
00300                 buf.hexify();
00301             }
00302             set_result(buf.c_str());
00303         }
00304         
00305         return TCL_OK;
00306 
00307     } else {
00308         resultf("unknown bundle subcommand %s", cmd);
00309         return TCL_ERROR;
00310     }
00311 }
00312 
00313 
00314 } // namespace dtn

Generated on Fri Dec 22 14:47:57 2006 for DTN Reference Implementation by  doxygen 1.5.1