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