00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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)
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;
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
00168
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
00176
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];
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
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
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
00207 if (!b->is_admin_) {
00208 goto done;
00209 }
00210
00211
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
00219
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
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
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
00265 addElement(Tcl_NewStringObj("sr_reason", -1));
00266 addElement(Tcl_NewStringObj(BundleStatusReport::reason_to_str(sr.reason_code_), -1));
00267
00268
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
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
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
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
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
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
00375 done:
00376 *result = objv;
00377 return TCL_OK;
00378 }
00379
00380 }