00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include <oasys/serialize/TclListSerialize.h>
00040 #include <oasys/util/ScratchBuffer.h>
00041
00042 #include "TclRegistration.h"
00043 #include "bundling/BundleEvent.h"
00044 #include "bundling/BundleDaemon.h"
00045 #include "bundling/BundleList.h"
00046 #include "bundling/BundleStatusReport.h"
00047 #include "bundling/CustodySignal.h"
00048 #include "storage/GlobalStore.h"
00049
00050 namespace dtn {
00051
00052 TclRegistration::TclRegistration(const EndpointIDPattern& endpoint,
00053 Tcl_Interp* interp)
00054
00055 : Registration(GlobalStore::instance()->next_regid(),
00056 endpoint, Registration::DEFER, 0)
00057 {
00058 logpathf("/dtn/registration/tcl/%d", regid_);
00059 set_active(true);
00060
00061 log_info("new tcl registration on endpoint %s", endpoint.c_str());
00062
00063 bundle_list_ = new BlockingBundleList(logpath_);
00064 int fd = bundle_list_->notifier()->read_fd();
00065 notifier_channel_ = Tcl_MakeFileChannel((ClientData)fd, TCL_READABLE);
00066
00067 if (notifier_channel_ == NULL) {
00068 log_err("can't create tcl file channel: %s",
00069 strerror(Tcl_GetErrno()));
00070 } else {
00071 log_debug("notifier_channel_ is %p", notifier_channel_);
00072 Tcl_RegisterChannel(interp, notifier_channel_);
00073 }
00074 }
00075
00076 void
00077 TclRegistration::deliver_bundle(Bundle* bundle)
00078 {
00079 bundle_list_->push_back(bundle);
00080 }
00081
00082 int
00083 TclRegistration::exec(int argc, const char** argv, Tcl_Interp* interp)
00084 {
00085 oasys::TclCommandInterp* cmdinterp = oasys::TclCommandInterp::instance();
00086 if (argc < 1) {
00087 cmdinterp->wrong_num_args(argc, argv, 0, 1, INT_MAX);
00088 return TCL_ERROR;
00089 }
00090 const char* op = argv[0];
00091
00092 if (strcmp(op, "get_list_channel") == 0)
00093 {
00094 return get_list_channel(interp);
00095 }
00096 else if (strcmp(op, "get_bundle_data") == 0)
00097 {
00098 return get_bundle_data(interp);
00099 }
00100 else
00101 {
00102 cmdinterp->resultf("invalid operation '%s'", op);
00103 return TCL_ERROR;
00104 }
00105 }
00106
00107 int
00108 TclRegistration::get_list_channel(Tcl_Interp* interp)
00109 {
00110 (void)interp;
00111 oasys::TclCommandInterp* cmdinterp = oasys::TclCommandInterp::instance();
00112 cmdinterp->set_result(Tcl_GetChannelName(notifier_channel_));
00113 return TCL_OK;
00114 }
00115
00116
00117 int
00118 TclRegistration::get_bundle_data(Tcl_Interp* interp)
00119 {
00120 oasys::TclCommandInterp* cmdinterp = oasys::TclCommandInterp::instance();
00121 BundleRef b("TclRegistration::get_bundle_data temporary");
00122 b = bundle_list_->pop_front();
00123 if (b == NULL) {
00124 cmdinterp->set_objresult(Tcl_NewListObj(0, 0));
00125 return TCL_OK;
00126 }
00127
00128 Tcl_Obj* result;
00129 int ok = parse_bundle_data(interp, b, &result);
00130 cmdinterp->set_objresult(result);
00131
00132 if (ok != TCL_OK) {
00133 return ok;
00134 }
00135
00136 BundleDaemon::post(new BundleDeliveredEvent(b.object(), this));
00137 return TCL_OK;
00138
00139 }
00140
00183 int
00184 TclRegistration::parse_bundle_data(Tcl_Interp* interp,
00185 const BundleRef& b,
00186 Tcl_Obj** result)
00187 {
00188
00189
00190 Tcl_Obj* objv = Tcl_NewListObj(0, 0);
00191 oasys::TclListSerialize s(interp, objv,
00192 oasys::Serialize::CONTEXT_LOCAL,
00193 0);
00194 b->serialize(&s);
00195
00196
00197
00198 size_t payload_len = b->payload_.length();
00199 oasys::ScratchBuffer<u_char*> payload_buf;
00200 const u_char* payload_data = (const u_char*)"";
00201 if (payload_len != 0) {
00202 payload_data = b->payload_.read_data(0, payload_len,
00203 payload_buf.buf(payload_len));
00204 }
00205
00206 char tmp_buf[128];
00207
00208 #define addElement(e) \
00209 if (Tcl_ListObjAppendElement(interp, objv, (e)) != TCL_OK) { \
00210 *result = Tcl_NewStringObj("Tcl_ListObjAppendElement failed", -1); \
00211 return TCL_ERROR; \
00212 }
00213
00214
00215 addElement(Tcl_NewStringObj("payload_len", -1));
00216 addElement(Tcl_NewIntObj(payload_len));
00217
00218 addElement(Tcl_NewStringObj("payload_data", -1));
00219 addElement(Tcl_NewByteArrayObj(const_cast<u_char*>(payload_data),
00220 payload_len));
00221
00222
00223 addElement(Tcl_NewStringObj("creation_ts", -1));
00224 sprintf(tmp_buf, "%d.%d", b->creation_ts_.seconds_, b->creation_ts_.seqno_);
00225 addElement(Tcl_NewStringObj(tmp_buf, -1));
00226
00227
00228 if (!b->is_admin_) {
00229 goto done;
00230 }
00231
00232
00233 addElement(Tcl_NewStringObj("admin_type", -1));
00234 BundleProtocol::admin_record_type_t admin_type;
00235 if (!BundleProtocol::get_admin_type(b.object(), &admin_type)) {
00236 goto done;
00237 }
00238
00239
00240
00241 switch (admin_type) {
00242 case BundleProtocol::ADMIN_STATUS_REPORT:
00243 {
00244 addElement(Tcl_NewStringObj("Status Report", -1));
00245
00246 BundleStatusReport::data_t sr;
00247 if (!BundleStatusReport::parse_status_report(&sr, payload_data,
00248 payload_len)) {
00249 *result =
00250 Tcl_NewStringObj("Admin Bundle Status Report parsing failed", -1);
00251 return TCL_ERROR;
00252 }
00253
00254
00255 if (sr.admin_flags_ & BundleProtocol::ADMIN_IS_FRAGMENT) {
00256 addElement(Tcl_NewStringObj("orig_frag_offset", -1));
00257 addElement(Tcl_NewLongObj(sr.orig_frag_offset_));
00258 addElement(Tcl_NewStringObj("orig_frag_length", -1));
00259 addElement(Tcl_NewLongObj(sr.orig_frag_length_));
00260 }
00261
00262
00263 #define APPEND_TIMESTAMP(_flag, _what, _field) \
00264 if (sr.status_flags_ & BundleProtocol::_flag) { \
00265 addElement(Tcl_NewStringObj(_what, -1)); \
00266 sprintf(tmp_buf, "%u.%u", \
00267 sr._field.seconds_, sr._field.seqno_); \
00268 addElement(Tcl_NewStringObj(tmp_buf, -1)); \
00269 }
00270
00271 APPEND_TIMESTAMP(STATUS_RECEIVED,
00272 "sr_received_time", receipt_tv_);
00273 APPEND_TIMESTAMP(STATUS_CUSTODY_ACCEPTED,
00274 "sr_custody_time", custody_tv_);
00275 APPEND_TIMESTAMP(STATUS_FORWARDED,
00276 "sr_forwarded_time", forwarding_tv_);
00277 APPEND_TIMESTAMP(STATUS_DELIVERED,
00278 "sr_delivered_time", delivery_tv_);
00279 APPEND_TIMESTAMP(STATUS_DELETED,
00280 "sr_deleted_time", deletion_tv_);
00281 APPEND_TIMESTAMP(STATUS_ACKED_BY_APP,
00282 "sr_acked_by_app_time", acknowledgement_tv_);
00283 #undef APPEND_TIMESTAMP
00284
00285
00286 addElement(Tcl_NewStringObj("sr_reason", -1));
00287 switch (sr.reason_code_) {
00288 case BundleProtocol::REASON_NO_ADDTL_INFO:
00289 addElement(Tcl_NewStringObj("No additional information.", -1));
00290 break;
00291
00292 case BundleProtocol::REASON_LIFETIME_EXPIRED:
00293 addElement(Tcl_NewStringObj("Lifetime expired.", -1));
00294 break;
00295
00296 case BundleProtocol::REASON_FORWARDED_UNIDIR_LINK:
00297 addElement(Tcl_NewStringObj("Forwarded Over Unidirectional Link.", -1));
00298 break;
00299
00300 case BundleProtocol::REASON_TRANSMISSION_CANCELLED:
00301 addElement(Tcl_NewStringObj("Transmission cancelled.", -1));
00302 break;
00303
00304 case BundleProtocol::REASON_DEPLETED_STORAGE:
00305 addElement(Tcl_NewStringObj("Depleted storage.", -1));
00306 break;
00307
00308 case BundleProtocol::REASON_ENDPOINT_ID_UNINTELLIGIBLE:
00309 addElement(
00310 Tcl_NewStringObj("Destination endpoint ID unintelligible.", -1));
00311 break;
00312
00313 case BundleProtocol::REASON_NO_ROUTE_TO_DEST:
00314 addElement(
00315 Tcl_NewStringObj("No known route to destination from here.", -1));
00316 break;
00317
00318 case BundleProtocol::REASON_NO_TIMELY_CONTACT:
00319 addElement(
00320 Tcl_NewStringObj("No timely contact with next node on route.", -1));
00321 break;
00322
00323 case BundleProtocol::REASON_BLOCK_UNINTELLIGIBLE:
00324 addElement(
00325 Tcl_NewStringObj("Block unintelligible.", -1));
00326 break;
00327
00328 default:
00329 sprintf(tmp_buf, "Error: Unknown Status Report Reason Code 0x%x",
00330 sr.reason_code_);
00331 addElement(Tcl_NewStringObj(tmp_buf, -1));
00332 break;
00333 }
00334
00335
00336 addElement(Tcl_NewStringObj("orig_creation_ts", -1));
00337 sprintf(tmp_buf, "%u.%u",
00338 sr.orig_creation_tv_.seconds_,
00339 sr.orig_creation_tv_.seqno_);
00340 addElement(Tcl_NewStringObj(tmp_buf, -1));
00341
00342
00343 addElement(Tcl_NewStringObj("orig_source", -1));
00344 addElement(Tcl_NewStringObj(sr.orig_source_eid_.data(),
00345 sr.orig_source_eid_.length()));
00346 break;
00347 }
00348
00349
00350
00351 case BundleProtocol::ADMIN_CUSTODY_SIGNAL:
00352 {
00353 addElement(Tcl_NewStringObj("Custody Signal", -1));
00354
00355 CustodySignal::data_t cs;
00356 if (!CustodySignal::parse_custody_signal(&cs, payload_data,
00357 payload_len))
00358 {
00359 *result = Tcl_NewStringObj("Admin Custody Signal parsing failed", -1);
00360 return TCL_ERROR;
00361 }
00362
00363
00364 if (cs.admin_flags_ & BundleProtocol::ADMIN_IS_FRAGMENT) {
00365 addElement(Tcl_NewStringObj("orig_frag_offset", -1));
00366 addElement(Tcl_NewLongObj(cs.orig_frag_offset_));
00367 addElement(Tcl_NewStringObj("orig_frag_length", -1));
00368 addElement(Tcl_NewLongObj(cs.orig_frag_length_));
00369 }
00370
00371 addElement(Tcl_NewStringObj("custody_succeeded", -1));
00372 addElement(Tcl_NewBooleanObj(cs.succeeded_));
00373
00374 addElement(Tcl_NewStringObj("custody_reason", -1));
00375 switch(cs.reason_) {
00376 case BundleProtocol::CUSTODY_NO_ADDTL_INFO:
00377 addElement(Tcl_NewStringObj("No additional information.", -1));
00378 break;
00379
00380 case BundleProtocol::CUSTODY_REDUNDANT_RECEPTION:
00381 addElement(Tcl_NewStringObj("Redundant bundle reception.", -1));
00382 break;
00383
00384 case BundleProtocol::CUSTODY_DEPLETED_STORAGE:
00385 addElement(Tcl_NewStringObj("Depleted Storage.", -1));
00386 break;
00387
00388 case BundleProtocol::CUSTODY_ENDPOINT_ID_UNINTELLIGIBLE:
00389 addElement(Tcl_NewStringObj("Destination endpoint ID unintelligible.", -1));
00390 break;
00391
00392 case BundleProtocol::CUSTODY_NO_ROUTE_TO_DEST:
00393 addElement(Tcl_NewStringObj("No known route to destination from here", -1));
00394 break;
00395
00396 case BundleProtocol::CUSTODY_NO_TIMELY_CONTACT:
00397 addElement(Tcl_NewStringObj("No timely contact with next node en route.", -1));
00398 break;
00399
00400 case BundleProtocol::CUSTODY_BLOCK_UNINTELLIGIBLE:
00401 addElement(Tcl_NewStringObj("Block unintelligible.", -1));
00402 break;
00403
00404 default:
00405 sprintf(tmp_buf, "Error: Unknown Custody Signal Reason Code 0x%x",
00406 cs.reason_);
00407 addElement(Tcl_NewStringObj(tmp_buf, -1));
00408 break;
00409 }
00410
00411
00412 addElement(Tcl_NewStringObj("custody_signal_time", -1));
00413 sprintf(tmp_buf, "%u.%u",
00414 cs.custody_signal_tv_.seconds_,
00415 cs.custody_signal_tv_.seqno_);
00416 addElement(Tcl_NewStringObj(tmp_buf, -1));
00417
00418
00419 addElement(Tcl_NewStringObj("orig_creation_ts", -1));
00420 sprintf(tmp_buf, "%u.%u",
00421 cs.orig_creation_tv_.seconds_,
00422 cs.orig_creation_tv_.seqno_);
00423 addElement(Tcl_NewStringObj(tmp_buf, -1));
00424
00425
00426 addElement(Tcl_NewStringObj("orig_source", -1));
00427 addElement(Tcl_NewStringObj(cs.orig_source_eid_.data(),
00428 cs.orig_source_eid_.length()));
00429 break;
00430 }
00431
00432
00433
00434 case BundleProtocol::ADMIN_ECHO:
00435 {
00436 addElement(Tcl_NewStringObj("Admin Echo Signal", -1));
00437 break;
00438 }
00439
00440
00441
00442 case BundleProtocol::ADMIN_NULL:
00443 {
00444 addElement(Tcl_NewStringObj("Admin Null Signal", -1));
00445 break;
00446 }
00447
00448 default:
00449 sprintf(tmp_buf,
00450 "Error: Unknown Status Report Type 0x%x", admin_type);
00451 addElement(Tcl_NewStringObj(tmp_buf, -1));
00452 break;
00453 }
00454
00455
00456 done:
00457 *result = objv;
00458 return TCL_OK;
00459 }
00460
00461 }