TclRegistration.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/serialize/TclListSerialize.h>
00019 #include <oasys/util/ScratchBuffer.h>
00020 
00021 #include "TclRegistration.h"
00022 #include "bundling/BundleEvent.h"
00023 #include "bundling/BundleDaemon.h"
00024 #include "bundling/BundleList.h"
00025 #include "bundling/BundleStatusReport.h"
00026 #include "bundling/CustodySignal.h"
00027 #include "storage/GlobalStore.h"
00028 
00029 namespace dtn {
00030 
00031 TclRegistration::TclRegistration(const EndpointIDPattern& endpoint,
00032                                  Tcl_Interp* interp)
00033     
00034     : Registration(GlobalStore::instance()->next_regid(),
00035                    endpoint, Registration::DEFER, 0) // XXX/demmer expiration??
00036 {
00037     logpathf("/dtn/registration/tcl/%d", regid_);
00038     set_active(true);
00039 
00040     log_info("new tcl registration on endpoint %s", endpoint.c_str());
00041 
00042     bundle_list_ = new BlockingBundleList(logpath_);
00043     int fd = bundle_list_->notifier()->read_fd();
00044     notifier_channel_ = Tcl_MakeFileChannel((ClientData)fd, TCL_READABLE);
00045 
00046     if (notifier_channel_ == NULL) {
00047         log_err("can't create tcl file channel: %s",
00048                 strerror(Tcl_GetErrno()));
00049     } else {
00050         log_debug("notifier_channel_ is %p", notifier_channel_);
00051         Tcl_RegisterChannel(interp, notifier_channel_);
00052     }
00053 }
00054 
00055 void
00056 TclRegistration::deliver_bundle(Bundle* bundle)
00057 {
00058     bundle_list_->push_back(bundle);
00059 }
00060 
00061 int
00062 TclRegistration::exec(int argc, const char** argv, Tcl_Interp* interp)
00063 {
00064     oasys::TclCommandInterp* cmdinterp = oasys::TclCommandInterp::instance();
00065     if (argc < 1) {
00066         cmdinterp->wrong_num_args(argc, argv, 0, 1, INT_MAX);
00067         return TCL_ERROR;
00068     }
00069     const char* op = argv[0];
00070 
00071     if (strcmp(op, "get_list_channel") == 0)
00072     {
00073         return get_list_channel(interp);
00074     }
00075     else if (strcmp(op, "get_bundle_data") == 0)
00076     {
00077         return get_bundle_data(interp);
00078     }
00079     else
00080     {
00081         cmdinterp->resultf("invalid operation '%s'", op);
00082         return TCL_ERROR;
00083     }
00084 }
00085 
00086 int
00087 TclRegistration::get_list_channel(Tcl_Interp* interp)
00088 {
00089     (void)interp;
00090     oasys::TclCommandInterp* cmdinterp = oasys::TclCommandInterp::instance();
00091     cmdinterp->set_result(Tcl_GetChannelName(notifier_channel_));
00092     return TCL_OK;
00093 }
00094 
00095 
00096 int
00097 TclRegistration::get_bundle_data(Tcl_Interp* interp)
00098 {
00099     oasys::TclCommandInterp* cmdinterp = oasys::TclCommandInterp::instance();
00100     BundleRef b("TclRegistration::get_bundle_data temporary");
00101     b = bundle_list_->pop_front();
00102     if (b == NULL) {
00103         cmdinterp->set_objresult(Tcl_NewListObj(0, 0));
00104         return TCL_OK; // empty list
00105     }
00106 
00107     Tcl_Obj* result;
00108     int ok = parse_bundle_data(interp, b, &result);
00109     cmdinterp->set_objresult(result);
00110 
00111     if (ok != TCL_OK) {
00112         return ok;
00113     }
00114     
00115     BundleDaemon::post(new BundleDeliveredEvent(b.object(), this));
00116     return TCL_OK;
00117     
00118 }
00119 
00162 int
00163 TclRegistration::parse_bundle_data(Tcl_Interp* interp,
00164                                    const BundleRef& b,
00165                                    Tcl_Obj** result)
00166 {
00167     // Using the tcl based serializer, grab all the serialized
00168     // metadata fields into a new list object
00169     Tcl_Obj* objv = Tcl_NewListObj(0, 0);
00170     oasys::TclListSerialize s(interp, objv,
00171                               oasys::Serialize::CONTEXT_LOCAL,
00172                               0);
00173     b->serialize(&s);
00174 
00175     // read in all the payload data (XXX/demmer this will not be nice
00176     // for big bundles)
00177     size_t payload_len = b->payload_.length();
00178     oasys::ScratchBuffer<u_char*> payload_buf;
00179     const u_char* payload_data = (const u_char*)"";
00180     if (payload_len != 0) {
00181         payload_data = b->payload_.read_data(0, payload_len, 
00182                                              payload_buf.buf(payload_len));
00183     }
00184 
00185     char tmp_buf[128];              // used for sprintf strings
00186 
00187 #define addElement(e)                                                      \
00188     if (Tcl_ListObjAppendElement(interp, objv, (e)) != TCL_OK) {           \
00189         *result = Tcl_NewStringObj("Tcl_ListObjAppendElement failed", -1); \
00190         return TCL_ERROR;                                                  \
00191     }
00192     
00193     // stick in the payload
00194     addElement(Tcl_NewStringObj("payload_len", -1));
00195     addElement(Tcl_NewIntObj(payload_len));
00196     
00197     addElement(Tcl_NewStringObj("payload_data", -1));
00198     addElement(Tcl_NewByteArrayObj(const_cast<u_char*>(payload_data), 
00199                                    payload_len));
00200 
00201     // and a pretty formatted creation timestamp
00202     addElement(Tcl_NewStringObj("creation_ts", -1));
00203     sprintf(tmp_buf, "%d.%d", b->creation_ts_.seconds_, b->creation_ts_.seqno_);
00204     addElement(Tcl_NewStringObj(tmp_buf, -1));
00205 
00206     // If we're not an admin bundle, we're done
00207     if (!b->is_admin_) {
00208         goto done;
00209     }
00210 
00211     // Admin Type:
00212     addElement(Tcl_NewStringObj("admin_type", -1));
00213     BundleProtocol::admin_record_type_t admin_type;
00214     if (!BundleProtocol::get_admin_type(b.object(), &admin_type)) {
00215         goto done;
00216     }
00217 
00218     // Now for each type of admin bundle, first append the string to
00219     // define that type, then all the relevant fields of the type
00220     switch (admin_type) {
00221     case BundleProtocol::ADMIN_STATUS_REPORT:
00222     {
00223         addElement(Tcl_NewStringObj("Status Report", -1));
00224 
00225         BundleStatusReport::data_t sr;
00226         if (!BundleStatusReport::parse_status_report(&sr, payload_data,
00227                                                      payload_len)) {
00228             *result =
00229                 Tcl_NewStringObj("Admin Bundle Status Report parsing failed", -1);
00230             return TCL_ERROR;
00231         }
00232 
00233         // Fragment fields
00234         if (sr.admin_flags_ & BundleProtocol::ADMIN_IS_FRAGMENT) {
00235             addElement(Tcl_NewStringObj("orig_frag_offset", -1));
00236             addElement(Tcl_NewLongObj(sr.orig_frag_offset_));
00237             addElement(Tcl_NewStringObj("orig_frag_length", -1));
00238             addElement(Tcl_NewLongObj(sr.orig_frag_length_));
00239         }
00240 
00241         // Status fields with timestamps:
00242 #define APPEND_TIMESTAMP(_flag, _what, _field)                          \
00243         if (sr.status_flags_ & BundleProtocol::_flag) {                 \
00244             addElement(Tcl_NewStringObj(_what, -1));                    \
00245             sprintf(tmp_buf, "%u.%u",                                   \
00246                     sr._field.seconds_, sr._field.seqno_);              \
00247             addElement(Tcl_NewStringObj(tmp_buf, -1));                  \
00248         }
00249 
00250         APPEND_TIMESTAMP(STATUS_RECEIVED,
00251                          "sr_received_time", receipt_tv_);
00252         APPEND_TIMESTAMP(STATUS_CUSTODY_ACCEPTED,
00253                          "sr_custody_time",      custody_tv_);
00254         APPEND_TIMESTAMP(STATUS_FORWARDED,
00255                          "sr_forwarded_time",    forwarding_tv_);
00256         APPEND_TIMESTAMP(STATUS_DELIVERED,
00257                          "sr_delivered_time",    delivery_tv_);
00258         APPEND_TIMESTAMP(STATUS_DELETED,
00259                          "sr_deleted_time",      deletion_tv_);
00260         APPEND_TIMESTAMP(STATUS_ACKED_BY_APP,
00261                          "sr_acked_by_app_time", acknowledgement_tv_);
00262 #undef APPEND_TIMESTAMP
00263         
00264         // Reason Code:
00265         addElement(Tcl_NewStringObj("sr_reason", -1));
00266         addElement(Tcl_NewStringObj(BundleStatusReport::reason_to_str(sr.reason_code_), -1));
00267         
00268         // Bundle creation timestamp
00269         addElement(Tcl_NewStringObj("orig_creation_ts", -1));
00270         sprintf(tmp_buf, "%u.%u",
00271                 sr.orig_creation_tv_.seconds_,
00272                 sr.orig_creation_tv_.seqno_);
00273         addElement(Tcl_NewStringObj(tmp_buf, -1));
00274 
00275         // Status Report's Source EID:
00276         addElement(Tcl_NewStringObj("orig_source", -1));
00277         addElement(Tcl_NewStringObj(sr.orig_source_eid_.data(),
00278                                     sr.orig_source_eid_.length()));
00279         break;
00280     }
00281 
00282     //-------------------------------------------
00283 
00284     case BundleProtocol::ADMIN_CUSTODY_SIGNAL:
00285     {
00286         addElement(Tcl_NewStringObj("Custody Signal", -1));
00287 
00288         CustodySignal::data_t cs;
00289         if (!CustodySignal::parse_custody_signal(&cs, payload_data,
00290                                                  payload_len))
00291         {
00292             *result = Tcl_NewStringObj("Admin Custody Signal parsing failed", -1);
00293             return TCL_ERROR;
00294         }
00295 
00296         // Fragment fields
00297         if (cs.admin_flags_ & BundleProtocol::ADMIN_IS_FRAGMENT) {
00298             addElement(Tcl_NewStringObj("orig_frag_offset", -1));
00299             addElement(Tcl_NewLongObj(cs.orig_frag_offset_));
00300             addElement(Tcl_NewStringObj("orig_frag_length", -1));
00301             addElement(Tcl_NewLongObj(cs.orig_frag_length_));
00302         }
00303         
00304         addElement(Tcl_NewStringObj("custody_succeeded", -1));
00305         addElement(Tcl_NewBooleanObj(cs.succeeded_));
00306 
00307         addElement(Tcl_NewStringObj("custody_reason", -1));
00308         switch(cs.reason_) {
00309         case BundleProtocol::CUSTODY_NO_ADDTL_INFO:
00310             addElement(Tcl_NewStringObj("No additional information.", -1));
00311             break;
00312             
00313         case BundleProtocol::CUSTODY_REDUNDANT_RECEPTION:
00314             addElement(Tcl_NewStringObj("Redundant bundle reception.", -1));
00315             break;
00316             
00317         case BundleProtocol::CUSTODY_DEPLETED_STORAGE:
00318             addElement(Tcl_NewStringObj("Depleted Storage.", -1));
00319             break;
00320             
00321         case BundleProtocol::CUSTODY_ENDPOINT_ID_UNINTELLIGIBLE:
00322             addElement(Tcl_NewStringObj("Destination endpoint ID unintelligible.", -1));
00323             break;
00324             
00325         case BundleProtocol::CUSTODY_NO_ROUTE_TO_DEST:
00326             addElement(Tcl_NewStringObj("No known route to destination from here", -1));
00327             break;
00328             
00329         case BundleProtocol::CUSTODY_NO_TIMELY_CONTACT:
00330             addElement(Tcl_NewStringObj("No timely contact with next node en route.", -1));
00331             break;
00332             
00333         case BundleProtocol::CUSTODY_BLOCK_UNINTELLIGIBLE:
00334             addElement(Tcl_NewStringObj("Block unintelligible.", -1));
00335             break;
00336             
00337         default:
00338             sprintf(tmp_buf, "Error: Unknown Custody Signal Reason Code 0x%x",
00339                     cs.reason_);
00340             addElement(Tcl_NewStringObj(tmp_buf, -1));
00341             break;
00342         }
00343 
00344         // Custody signal timestamp
00345         addElement(Tcl_NewStringObj("custody_signal_time", -1));
00346         sprintf(tmp_buf, "%u.%u",
00347                 cs.custody_signal_tv_.seconds_,
00348                 cs.custody_signal_tv_.seqno_);
00349         addElement(Tcl_NewStringObj(tmp_buf, -1));
00350         
00351         // Bundle creation timestamp
00352         addElement(Tcl_NewStringObj("orig_creation_ts", -1));
00353         sprintf(tmp_buf, "%u.%u",
00354                 cs.orig_creation_tv_.seconds_,
00355                 cs.orig_creation_tv_.seqno_);
00356         addElement(Tcl_NewStringObj(tmp_buf, -1));
00357 
00358         // Original source eid
00359         addElement(Tcl_NewStringObj("orig_source", -1));
00360         addElement(Tcl_NewStringObj(cs.orig_source_eid_.data(),
00361                                     cs.orig_source_eid_.length()));
00362         break;
00363     }
00364 
00365     //-------------------------------------------
00366 
00367     default:
00368         sprintf(tmp_buf,
00369                 "Error: Unknown Status Report Type 0x%x", admin_type);
00370         addElement(Tcl_NewStringObj(tmp_buf, -1));
00371         break;
00372     }
00373 
00374     // all done
00375  done:
00376     *result = objv;
00377     return TCL_OK;
00378 }
00379 
00380 } // namespace dtn

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