ExternalRouter.cc

Go to the documentation of this file.
00001 /*
00002  * License Agreement
00003  * 
00004  * NOTICE
00005  * This software (or technical data) was produced for the U. S.
00006  * Government under contract W15P7T-05-C-F600, and is
00007  * subject to the Rights in Data-General Clause 52.227-14 (JUNE 1987)
00008  * 
00009  * Copyright (C) 2006. The MITRE Corporation (http://www.mitre.org/).
00010  * All Rights Reserved.
00011  * 
00012  * Redistribution and use in source and binary forms, with or without
00013  * modification, are permitted provided that the following conditions
00014  * are met:
00015  * 
00016  * * Redistributions of source code must retain the above copyright
00017  * notice, this list of conditions and the following disclaimer.
00018  * 
00019  * * Redistributions in binary form must reproduce the above copyright
00020  * notice, this list of conditions and the following disclaimer in the
00021  * documentation and/or other materials provided with the distribution.
00022  * 
00023  * * The US Government will not be charged any license fee and/or
00024  * royalties related to this software.
00025  * 
00026  * * Neither name of The MITRE Corporation; nor the names of its
00027  * contributors may be used to endorse or promote products derived from
00028  * this software without specific prior written permission.
00029  * 
00030  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00031  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00032  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00033  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
00034  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00035  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00036  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00037  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00038  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
00039  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00040  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00041  */
00042 
00043 #include <config.h>
00044 #ifdef XERCES_C_ENABLED
00045 
00046 #include <iostream>
00047 #include <map>
00048 #include <sys/ioctl.h>
00049 #include <tcl.h>
00050 #include <string.h>
00051 #include <netinet/in.h>
00052 
00053 #include "ExternalRouter.h"
00054 #include "bundling/BundleDaemon.h"
00055 #include "bundling/BundleActions.h"
00056 #include "contacts/ContactManager.h"
00057 #include "reg/RegistrationTable.h"
00058 
00059 #include <oasys/io/UDPClient.h>
00060 #include <oasys/tclcmd/TclCommand.h>
00061 #include <oasys/io/IO.h>
00062 
00063 namespace dtn {
00064 
00065 ExternalRouter::ExternalRouter()
00066     : BundleRouter("ExternalRouter", "external")
00067 {
00068     log_notice("Initializing ExternalRouter");
00069 }
00070 
00071 ExternalRouter::~ExternalRouter()
00072 {
00073     delete srv_;
00074     delete hello_;
00075     delete reg_;
00076     delete route_table_;
00077 }
00078 
00079 // Initialize inner classes
00080 void
00081 ExternalRouter::initialize()
00082 {
00083     // Create the static route table
00084     route_table_ = new RouteTable("external");
00085 
00086     // Register as a client app with the forwarder
00087     reg_ = new ERRegistration(this);
00088 
00089     // Create a hello timer
00090     hello_ = new HelloTimer(this);
00091 
00092     // Register the global shutdown function
00093     BundleDaemon::instance()->set_rtr_shutdown(
00094         external_rtr_shutdown, (void *) 0);
00095 
00096     // Start module server thread
00097     srv_ = new ModuleServer();
00098     srv_->start();
00099 
00100     if (ExternalRouter::client_validation) {
00101         oasys::StringBuffer alert_with_ns(
00102             "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
00103             "<dtn eid=\"%s\" hello_interval=\"%i\" alert=\"justBooted\" "
00104             "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
00105             "xsi:noNamespaceSchemaLocation=\"file://%s\"/>",
00106             BundleDaemon::instance()->local_eid().c_str(),
00107             ExternalRouter::hello_interval,
00108             ExternalRouter::schema.c_str());
00109 
00110         srv_->eventq->push_back(
00111             new std::string(alert_with_ns.c_str()));
00112     } else {
00113         oasys::StringBuffer alert(
00114             "<dtn eid=\"%s\" hello_interval=\"%i\" alert=\"justBooted\"/>",
00115             BundleDaemon::instance()->local_eid().c_str(),
00116             ExternalRouter::hello_interval);
00117 
00118         srv_->eventq->push_back(
00119             new std::string(alert.c_str()));
00120     }
00121 
00122     hello_->schedule_in(ExternalRouter::hello_interval * 1000);
00123 }
00124 
00125 // Format the given StringBuffer with static routing info
00126 void
00127 ExternalRouter::get_routing_state(oasys::StringBuffer* buf)
00128 {
00129     EndpointIDVector long_eids;
00130     buf->appendf("Static route table for %s router(s):\n", name_.c_str());
00131     route_table_->dump(buf, &long_eids);
00132 
00133     if (long_eids.size() > 0) {
00134         buf->appendf("\nLong Endpoint IDs referenced above:\n");
00135         for (u_int i = 0; i < long_eids.size(); ++i) {
00136             buf->appendf("\t[%d]: %s\n", i, long_eids[i].c_str());
00137         }
00138         buf->appendf("\n");
00139     }
00140     
00141     buf->append("\nClass of Service (COS) bits:\n"
00142                 "\tB: Bulk  N: Normal  E: Expedited\n\n");
00143 }
00144 
00145 // Builds a static route XML report
00146 void
00147 ExternalRouter::build_route_report(oasys::SerializeAction *a)
00148 {
00149     oasys::ScopeLock l(route_table_->lock(),
00150         "ExternalRouter::build_route_report");
00151 
00152     const RouteEntryVec *re = route_table_->route_table();
00153     RouteEntryVec::const_iterator i;
00154 
00155     a->begin_action();
00156 
00157     for(i = re->begin(); i != re->end(); ++i) {
00158         a->process("route_entry", *i);
00159     }
00160 
00161     a->end_action();
00162 }
00163 
00164 // Serialize events and UDP multicast to external routers
00165 void
00166 ExternalRouter::handle_event(BundleEvent *event)
00167 {
00168     static oasys::StringBuffer front_matter(
00169         "<dtn eid=\"%s\">",
00170         BundleDaemon::instance()->local_eid().c_str());
00171 
00172     static oasys::StringBuffer front_matter_with_ns(
00173         "<?xml version=\"1.0\" encoding=\"UTF-8\"?><dtn eid=\"%s\" "
00174         "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
00175         "xsi:noNamespaceSchemaLocation=\"file://%s\">",
00176         BundleDaemon::instance()->local_eid().c_str(),
00177         ExternalRouter::schema.c_str());
00178 
00179     // Preprocess events based upon type
00180     if ((event->type_ == BUNDLE_DELIVERED) ||
00181         (event->type_ == LINK_CREATE) ||
00182         (event->type_ == REASSEMBLY_COMPLETED)) {
00183         // Filter out events not supported by the external router interface
00184         return;
00185     } else if (event->type_ == BUNDLE_RECEIVED) {
00186         // Filter out notification of bundles already
00187         // delivered to registrations
00188         BundleReceivedEvent *bre = dynamic_cast< BundleReceivedEvent * >(event);
00189         if (bre->bundleref_->owner_ == "daemon") return;
00190     } else if (event->type_ == ROUTE_ADD) {
00191         // Add this route to our static routing table
00192         RouteAddEvent *rae = dynamic_cast< RouteAddEvent * >(event);
00193         route_table_->add_entry(rae->entry_);
00194     } else if (event->type_ == ROUTE_DEL) {
00195         // Delete this route from our static routing table
00196         RouteDelEvent *rae = dynamic_cast< RouteDelEvent * >(event);
00197         route_table_->del_entries(rae->dest_);
00198     } else if (event->type_ == BUNDLE_TRANSMITTED) {
00199         // Do not pass transmit events for deleted contacts
00200         BundleTransmittedEvent *event = dynamic_cast< BundleTransmittedEvent * >(event);
00201         if(event->contact_ == NULL)
00202         {
00203             return;
00204         }
00205     } else if (event->type_ == BUNDLE_TRANSMIT_FAILED) {
00206         // Do not pass transmit failed events for deleted contacts
00207         BundleTransmitFailedEvent *event = dynamic_cast< BundleTransmitFailedEvent * >(event);
00208         if(event->contact_ == NULL)
00209         {
00210             return;
00211         }
00212     }
00213 
00214     // serialize the event
00215     oasys::StringBuffer event_buf;
00216 
00217     if (ExternalRouter::client_validation)
00218         event_buf.append(front_matter_with_ns.c_str());
00219     else
00220         event_buf.append(front_matter.c_str());
00221 
00222     oasys::XMLMarshal event_a(event_buf.expandable_buf(),
00223         event_to_str(event->type_, true));
00224 
00225     if (event->type_ == ROUTE_REPORT)
00226         // handle route report serialization locally
00227         build_route_report(&event_a);
00228     else
00229         event_a.action(event);
00230 
00231     event_buf.append("</dtn>");
00232 
00233     // give the serialized event to the ModuleServer thread
00234     log_debug("ExternalRouter::handle_event (%s) sending:\n %s\n",
00235         event_to_str(event->type_), event_buf.c_str());
00236     srv_->eventq->push_back(new std::string(event_buf.c_str()));
00237 }
00238 
00239 void
00240 ExternalRouter::shutdown()
00241 {
00242     // Send an alert that we're going away
00243     if (ExternalRouter::client_validation) {
00244         oasys::StringBuffer alert_with_ns(
00245             "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
00246             "<dtn eid=\"%s\" alert=\"shuttingDown\" "
00247             "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
00248             "xsi:noNamespaceSchemaLocation=\"file://%s\"/>",
00249             BundleDaemon::instance()->local_eid().c_str(),
00250             ExternalRouter::schema.c_str());
00251 
00252         srv_->eventq->push_back(
00253             new std::string(alert_with_ns.c_str()));
00254     } else {
00255         oasys::StringBuffer alert(
00256             "<dtn eid=\"%s\" alert=\"shuttingDown\"/>",
00257             BundleDaemon::instance()->local_eid().c_str());
00258 
00259         srv_->eventq->push_back(
00260             new std::string(alert.c_str()));
00261     }
00262 }
00263 
00264 ExternalRouter::ModuleServer::ModuleServer()
00265     : IOHandlerBase(new oasys::Notifier("/router/external/moduleserver")),
00266       Thread("/router/external/moduleserver"),
00267       parser_(ExternalRouter::server_validation,
00268               ExternalRouter::schema.c_str()),
00269       lock_(new oasys::SpinLock())
00270 {
00271     // router interface and external routers must be able to bind
00272     // to the same port
00273     const int on = 1;
00274     setsockopt(fd(), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
00275     bind(htonl(INADDR_ANY), ExternalRouter::server_port);
00276 
00277     // join the "all routers" multicast group
00278     ip_mreq mreq;
00279     mreq.imr_multiaddr.s_addr = htonl(INADDR_ALLRTRS_GROUP);
00280     mreq.imr_interface.s_addr = htonl(INADDR_ANY);
00281     setsockopt(fd(), IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
00282 
00283     // source messages from the loopback interface
00284     in_addr src_if;
00285     src_if.s_addr = htonl(INADDR_LOOPBACK);
00286     setsockopt(fd(), IPPROTO_IP, IP_MULTICAST_IF, &src_if, sizeof(src_if));
00287 
00288     // we always delete the thread object when we exit
00289     Thread::set_flag(Thread::DELETE_ON_EXIT);
00290 
00291     set_logfd(false);
00292 
00293     eventq = new oasys::MsgQueue< std::string * >(logpath_, lock_);
00294 }
00295 
00296 ExternalRouter::ModuleServer::~ModuleServer()
00297 {
00298     // free all pending events
00299     std::string *event;
00300     while (eventq->try_pop(&event))
00301         delete event;
00302 
00303     delete eventq;
00304 }
00305 
00306 // ModuleServer main loop
00307 void
00308 ExternalRouter::ModuleServer::run() 
00309 {
00310     // block on input from the socket and
00311     // on input from the bundle event list
00312     struct pollfd pollfds[2];
00313 
00314     struct pollfd* event_poll = &pollfds[0];
00315     event_poll->fd = eventq->read_fd();
00316     event_poll->events = POLLIN;
00317 
00318     struct pollfd* sock_poll = &pollfds[1];
00319     sock_poll->fd = fd();
00320     sock_poll->events = POLLIN;
00321 
00322     while (1) {
00323         if (should_stop()) return;
00324 
00325         // block waiting...
00326         int ret = oasys::IO::poll_multiple(pollfds, 2, -1,
00327             get_notifier());
00328 
00329         if (ret == oasys::IOINTR) {
00330             log_debug("module server interrupted");
00331             set_should_stop();
00332             continue;
00333         }
00334 
00335         if (ret == oasys::IOERROR) {
00336             log_debug("module server error");
00337             set_should_stop();
00338             continue;
00339         }
00340 
00341         // check for an event
00342         if (event_poll->revents & POLLIN) {
00343             std::string *event;
00344             if (eventq->try_pop(&event)) {
00345                 ASSERT(event != NULL)
00346                 sendto(const_cast< char * >(event->c_str()),
00347                     event->size(), 0,
00348                     htonl(INADDR_ALLRTRS_GROUP),
00349                     ExternalRouter::server_port);
00350                 delete event;
00351             }
00352         }
00353 
00354         if (sock_poll->revents & POLLIN) {
00355             char buf[MAX_UDP_PACKET];
00356             in_addr_t raddr;
00357             u_int16_t rport;
00358             int bytes;
00359 
00360             bytes = recvfrom(buf, MAX_UDP_PACKET, 0, &raddr, &rport);
00361             buf[bytes] = '\0';
00362 
00363             process_action(buf);
00364         }
00365     }
00366 }
00367 
00368 // Handle a message from an external router
00369 void
00370 ExternalRouter::ModuleServer::process_action(const char *payload)
00371 {
00372     // clear any error condition before next parse
00373     parser_.reset_error();
00374 
00375     // parse the xml payload received
00376     const char *event_tag = parser_.parse(payload);
00377 
00378     // was the message valid?
00379     if (parser_.error()) {
00380         log_debug("received invalid message");
00381         return;
00382     }
00383 
00384     // traverse the XML document, instantiating events
00385     do {
00386         BundleEvent *action = instantiate(event_tag);
00387     
00388         if (! action) continue;
00389 
00390         // unmarshal the action
00391         parser_.action(action);
00392     
00393         // place the action on the global event queue
00394         BundleDaemon::post(action);
00395     } while ((event_tag = parser_.parse()) != 0);
00396 }
00397 
00398 // Instantiate BundleEvents recognized by the
00399 // external router interface
00400 BundleEvent *
00401 ExternalRouter::ModuleServer::instantiate(const char *event_tag) {
00402     std::string action(event_tag);
00403 
00404     if (action.find("send_bundle_request") != std::string::npos)
00405         return new BundleSendRequest();
00406     else if (action.find("cancel_bundle_request") != std::string::npos)
00407         return new BundleCancelRequest();
00408     else if (action.find("inject_bundle_request") != std::string::npos)
00409         return new BundleInjectRequest();
00410     else if (action.find("open_link_request") != std::string::npos)
00411         return new LinkStateChangeRequest(oasys::Builder::builder(),
00412                                           Link::OPENING, ContactEvent::NO_INFO);
00413     else if (action.find("create_link_request") != std::string::npos)
00414         return new LinkCreateRequest();
00415     else if (action.find("link_query") != std::string::npos)
00416         return new LinkQueryRequest();
00417     else if (action.find("contact_query") != std::string::npos)
00418         return new ContactQueryRequest();
00419     else if (action.find("bundle_query") != std::string::npos)
00420         return new BundleQueryRequest();
00421     else if (action.find("route_query") != std::string::npos)
00422         return new RouteQueryRequest();
00423 
00424     return 0;
00425 }
00426 
00427 ExternalRouter::HelloTimer::HelloTimer(ExternalRouter *router)
00428     : router_(router)
00429 {
00430 }
00431 
00432 ExternalRouter::HelloTimer::~HelloTimer()
00433 {
00434     cancel();
00435 }
00436 
00437 // Timeout callback for the hello timer
00438 void
00439 ExternalRouter::HelloTimer::timeout(const struct timeval &)
00440 {
00441     static oasys::StringBuffer hello(
00442         "<dtn eid=\"%s\" hello_interval=\"%i\"/>",
00443         BundleDaemon::instance()->local_eid().c_str(),
00444         ExternalRouter::hello_interval);
00445 
00446     static oasys::StringBuffer hello_with_ns(
00447         "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
00448         "<dtn eid=\"%s\" hello_interval=\"%i\" "
00449         "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
00450         "xsi:noNamespaceSchemaLocation=\"file://%s\"/>",
00451         BundleDaemon::instance()->local_eid().c_str(),
00452         ExternalRouter::hello_interval,
00453         ExternalRouter::schema.c_str());
00454 
00455     // throw the hello message onto the ModuleServer queue
00456     if (ExternalRouter::client_validation)
00457         router_->srv_->eventq->push_back(new std::string(hello_with_ns.c_str()));
00458     else
00459         router_->srv_->eventq->push_back(new std::string(hello.c_str()));
00460 
00461     schedule_in(ExternalRouter::hello_interval * 1000);
00462 }
00463 
00464 ExternalRouter::ERRegistration::ERRegistration(ExternalRouter *router)
00465     : Registration(Registration::EXTERNALROUTER_REGID,
00466                     EndpointID(BundleDaemon::instance()->local_eid().str() +
00467                         EXTERNAL_ROUTER_SERVICE_TAG),
00468                     Registration::DEFER, 0),
00469       router_(router)
00470 {
00471     logpathf("/reg/admin");
00472 
00473     BundleDaemon::post(new RegistrationAddedEvent(this, EVENTSRC_ADMIN));
00474 }
00475 
00476 // deliver a bundle to external routers
00477 void
00478 ExternalRouter::ERRegistration::deliver_bundle(Bundle *bundle)
00479 {
00480     BundleDeliveryEvent *delivery =
00481         new BundleDeliveryEvent(bundle, EVENTSRC_PEER);
00482 
00483     router_->handle_event(delivery);
00484     delete delivery;
00485 
00486     BundleDaemon::post(new BundleDeliveredEvent(bundle, this));
00487 }
00488 
00489 // Global shutdown callback function
00490 void external_rtr_shutdown(void *)
00491 {
00492     BundleDaemon::instance()->router()->shutdown();
00493 }
00494 
00495 // Initialize ExternalRouter parameters
00496 u_int16_t ExternalRouter::server_port = 8001;
00497 u_int16_t ExternalRouter::hello_interval = 30;
00498 std::string ExternalRouter::schema = "/etc/dtn.router.xsd";
00499 bool ExternalRouter::server_validation = true;
00500 bool ExternalRouter::client_validation = false;
00501 
00502 } // namespace dtn
00503 #endif // XERCES_C_ENABLED

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