00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "conv_layers/ConvergenceLayer.h"
00019 #include "bundling/BundleActions.h"
00020 #include "contacts/ContactManager.h"
00021 #include "bundling/BundleDaemon.h"
00022 #include "routing/RouteTable.h"
00023 #include <oasys/io/NetUtils.h>
00024 #include "contacts/InterfaceTable.h"
00025 #include "conv_layers/TCPConvergenceLayer.h"
00026
00027 #include "TcaRouter.h"
00028
00029 namespace dtn {
00030
00031
00032
00033
00034
00035 static const std::string BL = "tca://localhost/bundlelayer";
00036
00037
00039
00040
00041
00042
00043
00044 static std::string
00045 get_payload_str(const Bundle* b)
00046 {
00047 size_t len = b->payload_.length();
00048 u_char data[len+1];
00049 const u_char* p = b->payload_.read_data(0, len, data);
00050 return (const char*)p;
00051 }
00052
00053
00054
00055 static bool
00056 check_nargs(const TcaControlBundle& cb, uint n_expected)
00057 {
00058 if (cb.args_.size() != n_expected)
00059 {
00060 log_err_p("dtn/tca", "TcaRouter: bundle '%s' contains wrong number "
00061 "of args. %d expected.", cb.str().c_str(), n_expected);
00062 return false;
00063 }
00064 return true;
00065 }
00066
00067
00068
00069 static void
00070 log_bundle(const std::string& comment, const Bundle* b, bool include_payload)
00071 {
00072 (void)comment;
00073 (void)b;
00074
00075 if (include_payload)
00076 log_debug_p("/dtn/tca", "%s [%s] -> [%s] : '%s'", comment.c_str(),
00077 b->source_.str().c_str(), b->dest_.c_str(),
00078 get_payload_str(b).c_str());
00079 else
00080 log_debug_p("/dtn/tca", "%s [%s] -> [%s]", comment.c_str(),
00081 b->source_.str().c_str(), b->dest_.c_str());
00082 }
00083
00084
00085 static void
00086 log_controlbundle(const TcaControlBundle& cb)
00087 {
00088 log_debug_p("/dtn/tca", " code='%s', args=%d",
00089 cb.code_.c_str(), (u_int)cb.args_.size());
00090 for (unsigned int i=0; i<cb.args_.size(); ++i)
00091 {
00092 log_debug_p("/dtn/tca", " '%s'", cb.args_[i].c_str());
00093 }
00094 }
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00108
00109
00110 TcaRouter::TcaRouter(Role role)
00111 : TableBasedRouter("TcaRouter", "TcaRouter")
00112 {
00113 role_ = role;
00114
00115
00116 admin_app_ = BundleDaemon::instance()->local_eid();
00117 admin_app_.set_app("admin");
00118
00119 logpathf("/dtn/tca");
00120
00121 log_info("TcaRouter started: role='%s', admin_app='%s'",
00122 get_role_str().c_str(), admin_app_.c_str());
00123 }
00124
00125
00126 std::string
00127 TcaRouter::get_role_str() const
00128 {
00129 switch (role_)
00130 {
00131 case TCA_MOBILE: return "mobile";
00132 case TCA_ROUTER: return "router";
00133 case TCA_GATEWAY: return "gateway";
00134 default: return "null";
00135 }
00136
00137 }
00138
00139
00140 void
00141 TcaRouter::handle_bundle_received(BundleReceivedEvent* event)
00142 {
00143 Bundle* bundle = event->bundleref_.object();
00144
00145
00146
00147
00148
00149
00150
00151
00152 EndpointID dest = bundle->dest_;
00153
00154 if (dest.scheme_str() == "tca")
00155 {
00156 log_bundle("TcaRouter: tca bundle received", bundle, true);
00157
00158 TcaEndpointID tca_dest(dest);
00159
00160 if (tca_dest.ssp() == "//registry")
00161 {
00162 handle_register(bundle);
00163 }
00164
00165 else if (tca_dest.app() == "admin.coa")
00166 {
00167 handle_coa(bundle);
00168 }
00169
00170 else if (tca_dest.ssp().substr(0,11) == "//anonymous")
00171 {
00172 handle_anonymous_bundle(bundle);
00173 }
00174
00175 else if (tca_dest.ssp() == "//localhost/bundlelayer")
00176 {
00177 handle_bl_control_bundle(bundle);
00178 }
00179
00180 else if (tca_dest.host() != admin_app_.host())
00181 {
00182
00183
00184
00185 handle_tca_unbound_bundle(bundle);
00186 }
00187 }
00188
00189 else
00190 {
00191
00192 fwd_to_matching(bundle);
00193 }
00194 }
00195
00196
00197 void
00198 TcaRouter::handle_bundle_transmitted(BundleTransmittedEvent* event)
00199 {
00200 Bundle* b = event->bundleref_.object();
00201 log_debug("TcaRouter: handle bundle transmitted: *%p", b);
00202
00203 EndpointID dest = b->dest_;
00204
00205 if (dest.scheme_str() == "tca")
00206 {
00207
00208
00209
00210
00211
00212
00213
00214 TcaEndpointID tca_dest(dest);
00215 if (tca_dest.app() == "admin.coa")
00216 {
00217 TcaControlBundle cb(get_payload_str(b));
00218 on_coa_transmitted(b, cb);
00219 }
00220 else if (tca_dest.app() == "admin.ask")
00221 {
00222 TcaControlBundle cb(get_payload_str(b));
00223 on_ask_transmitted(b, cb);
00224 }
00225 else if (tca_dest.app() == "admin")
00226 {
00227 TcaControlBundle cb(get_payload_str(b));
00228 if (cb.code_ == "adv")
00229 {
00230 on_adv_transmitted(b, cb);
00231 }
00232 }
00233 }
00234 }
00235
00236
00237
00238
00239
00240 void
00241 TcaRouter::handle_contact_up(ContactUpEvent* event)
00242 {
00243
00244
00245 TableBasedRouter::handle_contact_up(event);
00246 log_debug("TcaRouter::contact up");
00247 post_bundle(BL, admin_app_, "contact_up");
00248 }
00249
00250
00251 void
00252 TcaRouter::handle_contact_down(ContactDownEvent* event)
00253 {
00254 (void)event;
00255 log_debug("TcaRouter::contact down");
00256 post_bundle(BL, admin_app_, "contact_down");
00257
00258 }
00259
00260
00261 void
00262 TcaRouter::handle_link_available(LinkAvailableEvent* event)
00263 {
00264
00265
00266 TableBasedRouter::handle_link_available(event);
00267 log_debug("TcaRouter::link available");
00268 post_bundle(BL, admin_app_, "link_available");
00269 }
00270
00271
00272 void
00273 TcaRouter::handle_link_unavailable(LinkUnavailableEvent* event)
00274 {
00275 (void)event;
00276 log_debug("TcaRouter::link unavailable");
00277 post_bundle(BL, admin_app_, "link_unavailable");
00278 }
00279
00280
00281 void
00282 TcaRouter::handle_shutdown_request(ShutdownRequest* event)
00283 {
00284 (void)event;
00285 log_debug("TcaRouter::daemon shutdown");
00286 post_bundle(BL, admin_app_, "daemon_shutdown");
00287 }
00288
00289
00290
00291
00292
00293 int
00294 TcaRouter::fwd_to_all(Bundle* bundle)
00295 {
00296 RouteEntryVec matches;
00297 RouteEntryVec::iterator iter;
00298
00299 std::string pattern = "tca://*";
00300 EndpointID tca_all = pattern;
00301
00302 route_table_->get_matching(tca_all, &matches);
00303
00304 int count = 0;
00305 for (iter = matches.begin(); iter != matches.end(); ++iter)
00306 {
00307 log_debug("TcaRouter::fwd_to_all: %s",
00308 (*iter)->dest_pattern_.str().c_str());
00309 fwd_to_nexthop(bundle, *iter);
00310 ++count;
00311 }
00312
00313 log_debug("TcaRouter::fwd_to_all dest='%s': %d matches",
00314 bundle->dest_.c_str(), count);
00315 return count;
00316 }
00317
00318
00319
00320
00321
00322
00323
00324 int
00325 TcaRouter::fwd_to_matching(Bundle* bundle, Link* next_hop)
00326 {
00327 ForwardingRule fwd_rule = get_forwarding_rule(bundle);
00328 return fwd_to_matching_r(bundle, next_hop, fwd_rule);
00329 }
00330
00331
00332
00333
00334
00335
00336 int
00337 TcaRouter::fwd_to_matching_r(Bundle* bundle, Link* next_hop,
00338 ForwardingRule fwd_rule)
00339 {
00340 log_debug("TcaRouter::fwd_to_matching_r: owner='%s'",
00341 bundle->owner_.c_str());
00342 log_debug("TcaRouter::fwd_to_matching_r: fwd_rule=%d", fwd_rule);
00343
00344 if (fwd_rule == FWD_NEVER) return 0;
00345
00346 RouteEntryVec matches;
00347 RouteEntryVec::iterator iter;
00348
00349 route_table_->get_matching(bundle->dest_, &matches);
00350
00351
00352 RouteEntry* default_route = NULL;
00353 RouteEntryVec hard_matches;
00354 for (iter = matches.begin(); iter != matches.end(); ++iter)
00355 {
00356 if ((*iter)->dest_pattern_.str() == "tca://*")
00357 {
00358 default_route = *iter;
00359 }
00360 else
00361 {
00362 hard_matches.push_back(*iter);
00363 }
00364 }
00365
00366 if (fwd_rule == FWD_UDR_EXCLUSIVELY)
00367 {
00368 if (default_route != NULL)
00369 {
00370 fwd_to_nexthop(bundle, default_route);
00371 return 1;
00372 }
00373 }
00374
00375 int count = 0;
00376
00377
00378 if (fwd_rule == FWD_UDR_ALWAYS ||
00379 (fwd_rule == FWD_UDR_IFNECESSARY && hard_matches.size() == 0))
00380 {
00381 if (default_route != NULL)
00382 {
00383 fwd_to_nexthop(bundle, default_route);
00384 ++ count;
00385 }
00386 }
00387
00388
00389 for (iter = hard_matches.begin(); iter != hard_matches.end(); ++iter)
00390 {
00391 if (next_hop == NULL || (next_hop == (*iter)->next_hop_))
00392 {
00393 fwd_to_nexthop(bundle, *iter);
00394 ++count;
00395 }
00396 else
00397 {
00398 log_debug("fwd_to_matching_r dest='%s': "
00399 "ignoring match %s since next_hop link %s set",
00400 bundle->dest_.c_str(), (*iter)->next_hop_->name(),
00401 next_hop->name());
00402 }
00403 }
00404
00405 log_debug("fwd_to_matching_r dest='%s': %d matches",
00406 bundle->dest_.c_str(), count);
00407
00408 return count;
00409 }
00410
00411
00412 bool
00413 TcaRouter::on_coa_transmitted(Bundle* b, const TcaControlBundle& cb)
00414 {
00415 log_debug("TcaRouter: COA bundle transmitted");
00416
00417 TcaWrappedBundle wb(cb);
00418
00419 log_debug(" coa: source=%s, dest=%s",
00420 b->source_.c_str(),
00421 b->dest_.c_str());
00422
00423
00424 std::string coa_sent_payload = "coa_sent:";
00425 coa_sent_payload += b->source_.str();
00426 coa_sent_payload += "\t";
00427 coa_sent_payload += b->dest_.str();
00428 coa_sent_payload += "\t";
00429 coa_sent_payload += cb.args_[0];
00430
00431 log_debug(" coa_sent, payload='%s'", coa_sent_payload.c_str());
00432 post_bundle(BL, admin_app_, coa_sent_payload);
00433
00434 return true;
00435 }
00436
00437
00438 bool
00439 TcaRouter::on_ask_transmitted(Bundle* b, const TcaControlBundle& cb)
00440 {
00441 log_debug("TcaRouter: ASK bundle transmitted");
00442
00443 if (!check_nargs(cb, 1)) return false;
00444
00445
00446 std::string ask_sent= "ask_sent:";
00447 ask_sent += b->source_.str();
00448 ask_sent += "\t";
00449 ask_sent += b->dest_.str();
00450 ask_sent += "\t";
00451 ask_sent += cb.args_[0];
00452
00453 log_debug(" ask sent, payload='%s'", ask_sent.c_str());
00454 post_bundle(BL, admin_app_, ask_sent);
00455
00456 return false;
00457 }
00458
00459
00460 bool
00461 TcaRouter::on_adv_transmitted(Bundle* b, const TcaControlBundle& cb)
00462 {
00463 log_debug("TcaRouter: ADV bundle transmitted");
00464
00465 if (!check_nargs(cb, 2)) return false;
00466
00467
00468 std::string adv_sent= "adv_sent:";
00469 adv_sent += b->source_.str();
00470 adv_sent += "\t";
00471 adv_sent += b->dest_.str();
00472 adv_sent += "\t";
00473 adv_sent += cb.args_[0];
00474 adv_sent += "\t";
00475 adv_sent += cb.args_[1];
00476
00477 log_debug(" adv_sent, payload='%s'", adv_sent.c_str());
00478 post_bundle(BL, admin_app_, adv_sent);
00479
00480 return false;
00481 }
00482
00483
00484 bool
00485 TcaRouter::handle_register(Bundle* b)
00486 {
00487
00488
00489
00490
00491
00492 if (b->source_.str() == admin_app_.str())
00493 {
00494
00495
00496 fwd_to_matching_r(b, NULL, FWD_UDR_EXCLUSIVELY);
00497 }
00498 else
00499 {
00500
00501
00502
00503 TcaControlBundle cb(get_payload_str(b));
00504
00505 TcaWrappedBundle reg_received("reg_received",
00506 b->source_.str(), b->dest_.str());
00507
00508 log_debug("TcaRouter::handle_register:");
00509 log_controlbundle(cb);
00510
00511 if (cb.args_.size() == 2)
00512 {
00513
00514
00515 reg_received.append_arg(cb.args_[0]);
00516 reg_received.append_arg(cb.args_[1]);
00517 }
00518 else
00519 {
00520
00521
00522 reg_received.append_arg(b->source_.str());
00523 reg_received.append_arg("NULL");
00524 }
00525
00526 post_bundle(BL, admin_app_, reg_received.str());
00527 }
00528
00529 return true;
00530 }
00531
00532
00533 bool
00534 TcaRouter::handle_coa(Bundle* b)
00535 {
00536 log_debug("TcaRouter: COA bundle received");
00537
00538
00539 fwd_to_matching_r(b, NULL, FWD_UDR_NEVER);
00540
00541
00542
00543 return true;
00544 }
00545
00546
00547 bool
00548 TcaRouter::handle_anonymous_bundle(Bundle* b)
00549 {
00550
00551
00552
00553
00554 TcaEndpointID dest(b->dest_);
00555
00556 TcaControlBundle cb(get_payload_str(b));
00557
00558 if (cb.code_ == "ask")
00559 {
00560 return handle_ask(b, cb);
00561 }
00562 else
00563 {
00564 log_debug("TcaRouter:: unrecognized anonymous bundle code '%s'",
00565 cb.code_.c_str());
00566 return false;
00567 }
00568 }
00569
00570
00571 bool
00572 TcaRouter::handle_ask(Bundle* b, const TcaControlBundle& cb)
00573 {
00574 if (is_local_source(b))
00575 {
00576
00577
00578 fwd_to_matching_r(b, NULL, FWD_UDR_NEVER);
00579 }
00580 else
00581 {
00582 if (!check_nargs(cb, 1)) return false;
00583
00584
00585 std::string payload = "ask_received:";
00586 payload += b->source_.str();
00587 payload += "\t";
00588 payload += b->dest_.str();
00589 payload += "\t";
00590 payload += cb.args_[0];
00591
00592 post_bundle(BL, admin_app_, payload);
00593 }
00594
00595 return true;
00596 }
00597
00598
00599
00600
00601
00602
00603 bool
00604 TcaRouter::handle_bl_control_bundle(Bundle* b)
00605 {
00606 TcaControlBundle cb(get_payload_str(b));
00607
00608
00609 if (cb.code_ == "ask")
00610 {
00611 return handle_ask(b, cb);
00612 }
00613 else if (cb.code_ == "get_routes")
00614 {
00615 return handle_get_routes(b, cb);
00616 }
00617 else if (cb.code_ == "add_route")
00618 {
00619 return handle_add_route(b, cb);
00620 }
00621 else if (cb.code_ == "del_route")
00622 {
00623 return handle_del_route(b, cb);
00624 }
00625
00626 log_debug("TcaRouter: unknown control bundle type '%s'", cb.code_.c_str());
00627 return false;
00628
00629 }
00630
00631
00632 bool
00633 TcaRouter::handle_bl_ask(Bundle* b, const TcaControlBundle& cb)
00634 {
00635 (void)cb;
00636
00637
00638 return post_bundle(BL, b->source_,
00639 "adv:Don\'t ASK me. You should probably ASK the Control App,"
00640 " not the Bundle Layer.");
00641 }
00642
00643
00644 bool
00645 TcaRouter::handle_get_routes(Bundle* b, const TcaControlBundle& cb)
00646 {
00647 if (!check_nargs(cb, 1)) return false;
00648
00649 log_debug("TcaRouter:: get_routes bundle received. body = '%s'",
00650 cb.args_[0].c_str());
00651
00652 RouteEntryVec matches;
00653 RouteEntryVec::iterator iter;
00654
00655 EndpointIDPattern pattern(cb.args_[0]);
00656 route_table_->get_matching(pattern, &matches);
00657
00658 std::string response = "routes:";
00659 for (iter = matches.begin(); iter != matches.end(); ++iter)
00660 {
00661 response += (*iter)->dest_pattern_.str().c_str();
00662 response += "\t";
00663 }
00664
00665 post_bundle(BL, b->source_, response);
00666
00667 return true;
00668 }
00669
00670
00671 bool
00672 TcaRouter::handle_add_route(Bundle* b, const TcaControlBundle& cb)
00673 {
00674 (void)b;
00675
00676 if (!check_nargs(cb, 2)) return false;
00677
00678 const std::string& pattern = cb.args_[0];
00679 const std::string& link = cb.args_[1];
00680
00681 log_debug("TcaRouter:: add_route bundle received. "
00682 "pattern='%s', link='%s'\n", pattern.c_str(), link.c_str());
00683
00684 if (pattern.length() == 0 || link.length() == 0) return false;
00685
00686
00687
00688 return create_route(pattern, link);
00689 }
00690
00691
00692 bool
00693 TcaRouter::handle_del_route(Bundle* b, const TcaControlBundle& cb)
00694 {
00695 (void)b;
00696
00697 if (!check_nargs(cb, 1)) return false;
00698
00699 log_debug("TcaRouter:: del_route bundle received. body = '%s'",
00700 cb.args_[0].c_str());
00701
00702
00703
00704 route_table_->del_entries(cb.args_[0]);
00705 return true;
00706 }
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718 bool
00719 TcaRouter::handle_tca_unbound_bundle(Bundle* bundle)
00720 {
00721 log_debug("TcaRouter::handle_tca_unbound_bundle...");
00722
00723 int n_matches = fwd_to_matching_r(bundle, NULL, FWD_UDR_IFNECESSARY);
00724
00725 if (n_matches == 0)
00726 {
00727 if (role_ == TCA_ROUTER)
00728 {
00729
00730
00731 log_err("TcaRouter: Error. TCA_ROUTER has no route to dest %s",
00732 bundle->dest_.c_str());
00733 return false;
00734 }
00735 else if (role_ == TCA_GATEWAY)
00736 {
00737
00738
00739
00740
00741 std::string payload = "unb:";
00742 payload += bundle->dest_.str();
00743 post_bundle(BL, admin_app_, payload);
00744 }
00745 }
00746 return true;
00747 }
00748
00749
00750
00751 bool
00752 TcaRouter::is_local_source(Bundle* b)
00753 {
00754 TcaEndpointID src(b->source_);
00755 return src.get_hostid() == admin_app_.get_hostid();
00756 }
00757
00758
00759 TcaRouter::ForwardingRule
00760 TcaRouter::get_forwarding_rule(Bundle* b)
00761 {
00762
00763 if (b->dest_.scheme_str() != "tca") return FWD_UDR_ALWAYS;
00764
00765 TcaEndpointID dest(b->dest_);
00766
00767 if (dest.ssp() == "//registry")
00768 {
00769
00770
00771 if (b->source_.str() == admin_app_.str()) return FWD_UDR_EXCLUSIVELY;
00772 else return FWD_NEVER;
00773 }
00774
00775 else if (dest.app() == "admin.coa")
00776 {
00777
00778
00779
00780 return FWD_UDR_NEVER;
00781 }
00782
00783 else if (dest.ssp().substr(0,11) == "//anonymous")
00784 {
00785
00786
00787
00788
00789 if (is_local_source(b)) return FWD_UDR_NEVER;
00790 else return FWD_NEVER;
00791 }
00792
00793 else if (dest.ssp() == "//localhost/bundlelayer")
00794 {
00795
00796 return FWD_NEVER;
00797 }
00798
00799
00800
00801 else
00802 {
00803 if (dest.host() == admin_app_.host())
00804 {
00805
00806
00807 return FWD_NEVER;
00808 }
00809 else
00810 {
00811
00812
00813 return FWD_UDR_IFNECESSARY;
00814 }
00815 }
00816 }
00817
00818
00819
00820
00821
00822
00823 Link*
00824 TcaRouter::create_link(const std::string& link_addr)
00825 {
00826
00827
00828
00829
00830
00831 EndpointID link_eid(link_addr);
00832 std::string clayer_name = link_eid.scheme_str();
00833 const std::string& ssp = link_eid.ssp();
00834 std::string host = ssp.substr(2, ssp.length());
00835
00836 ContactManager* p_man = BundleDaemon::instance()->contactmgr();
00837
00838
00839 Link* p_link = p_man->find_link(host.c_str());
00840 if (p_link != NULL) return p_link;
00841
00842 ConvergenceLayer* cl = ConvergenceLayer::find_clayer(clayer_name.c_str());
00843 if (!cl) {
00844 log_err("TcaRouter: create_link failed: invalid convergence layer"
00845 " '%s'", clayer_name.c_str());
00846 return NULL;
00847 }
00848
00849 p_link = Link::create_link(host, Link::ONDEMAND, cl, host.c_str(), 0, NULL);
00850 if (!p_link) return NULL;
00851
00852
00853
00854 BundleDaemon::instance()->contactmgr()->add_link(p_link);
00855 return p_link;
00856
00857 }
00858
00859
00860 RouteEntry*
00861 TcaRouter::create_route(const std::string& pattern, Link* p_link)
00862 {
00863
00864 log_debug("TcaRouter::create_route: pattern=%s, p_link=%p",
00865 pattern.c_str(), p_link);
00866
00867 RouteEntry* p_entry = new RouteEntry(pattern, p_link);
00868 p_entry->action_ = ForwardingInfo::COPY_ACTION;
00869
00870 route_table_->add_entry(p_entry);
00871
00872 return p_entry;
00873 }
00874
00875
00876 bool
00877 TcaRouter::create_route(const std::string& pattern,
00878 const std::string& link_addr)
00879 {
00880
00881 Link* p_link = create_link(link_addr);
00882 if (!p_link)
00883 {
00884 log_err("TcaRouter::create_route: create_link failed");
00885 return false;
00886 }
00887
00888
00889 if (!create_route(pattern, p_link))
00890 {
00891 log_err("TcaRouter::create_route: create_route failed");
00892 return false;
00893 }
00894
00895 return true;
00896 }
00897
00898
00899 bool
00900 TcaRouter::post_bundle(const EndpointID& src, const EndpointID& dest,
00901 const std::string& payload)
00902 {
00903
00904 log_debug("TcaRouter::post_bundle: [%s] -> [%s] : '%s'\n",
00905 src.c_str(), dest.c_str(), payload.c_str());
00906
00907
00908 Bundle* b = new Bundle();
00909
00910
00911 if (src.length() == 0)
00912 b->source_ = EndpointID("tca://localhost/bundlelayer");
00913 else
00914 b->source_ = src;
00915
00916 b->dest_ = dest;
00917 b->custodian_ = BundleDaemon::instance()->local_eid();
00918 b->replyto_ = BundleDaemon::instance()->local_eid();
00919
00920 b->payload_.set_data(payload);
00921
00922
00923
00924 b->expiration_ = 3600;
00925
00926
00927
00928
00929 BundleReceivedEvent* p_event = new BundleReceivedEvent(b, EVENTSRC_ADMIN);
00930 BundleDaemon::instance()->post(p_event);
00931
00932 return true;
00933 }
00934
00935
00936
00937 bool
00938 TcaRouter::push_wrapped_bundle(const std::string& code,
00939 const EndpointID& src,
00940 const EndpointID& dest,
00941 const std::string& bsp)
00942 {
00943 std::string payload = code;
00944 payload += ":";
00945 payload += src.str();
00946 payload += "\t";
00947 payload += dest.str();
00948 payload += "\t";
00949 payload += bsp;
00950 return post_bundle(BL, admin_app_, payload);
00951 }
00952
00953
00954
00955
00956 }