Java tutorial
/* * This file is part of the Bytewalla Project * More information can be found at "http://www.tslab.ssvl.kth.se/csd/projects/092106/". * * Copyright 2009 Telecommunication Systems Laboratory (TSLab), Royal Institute of Technology, Sweden. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling; import android.database.Cursor; import android.database.sqlite.SQLiteException; import android.util.Log; import android.widget.Toast; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Comparator; import java.util.Date; import java.util.Iterator; import java.util.ListIterator; import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.TimeUnit; import se.kth.ssvl.tslab.bytewalla.androiddtn.DTNManager; import se.kth.ssvl.tslab.bytewalla.androiddtn.DTNService; import se.kth.ssvl.tslab.bytewalla.androiddtn.MultiHopForwarding; import se.kth.ssvl.tslab.bytewalla.androiddtn.R; import se.kth.ssvl.tslab.bytewalla.androiddtn.apps.DTNDiscovery; import se.kth.ssvl.tslab.bytewalla.androiddtn.apps.DTNMessageView; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.BundleProtocol.custody_signal_reason_t; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.BundleProtocol.status_report_reason_t; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleAcceptRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleCancelRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleDeleteRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleDeliveredEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleExpiredEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleFreeEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleInjectRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleInjectedEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleQueryRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleQueuedQueryRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleQueuedReportEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleReceivedEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleReportEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleSendCancelledEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleSendRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.BundleTransmittedEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.CLAParametersQueryRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.CLAParametersReportEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.CLAParamsSetEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.CLASetParamsRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.ContactAttributeChangedEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.ContactDownEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.ContactEvent.reason_t; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.ContactQueryRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.ContactReportEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.ContactUpEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.CustodySignalEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.CustodyTimeoutEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.EIDReachableQueryRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.EIDReachableReportEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.IfaceAttributesQueryRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.IfaceAttributesReportEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.LinkAttributeChangedEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.LinkAttributesQueryRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.LinkAttributesReportEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.LinkAvailableEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.LinkCreatedEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.LinkDeleteRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.LinkDeletedEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.LinkQueryRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.LinkReconfigureRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.LinkReportEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.LinkStateChangeRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.LinkUnavailableEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.NewEIDReachableEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.ReassemblyCompletedEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.RegistrationAddedEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.RegistrationDeleteRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.RegistrationExpiredEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.RegistrationRemovedEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.RouteAddEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.RouteDelEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.RouteQueryRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.RouteReportEvent; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.SetLinkDefaultsRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.ShutdownRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.StatusRequest; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.event_source_t; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.event.event_type_t; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.bundling.exception.BundleListLockNotHoldByCurrentThread; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.common.ServlibEventData; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.common.ServlibEventHandler; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.config.DTNConfiguration; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.contacts.Contact; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.contacts.ContactManager; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.contacts.Interface; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.contacts.Link; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.contacts.LinkSet; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.contacts.NamedAttribute; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.conv_layers.ConvergenceLayer; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.naming.EndpointID; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.naming.EndpointIDPattern; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.reg.AdminRegistration; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.reg.PingRegistration; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.reg.Registration; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.reg.RegistrationList; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.reg.RegistrationTable; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.routing.BundleRouter; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.routing.BundleRouter.router_type_t; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.routing.RoutingException; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.storage.BundleStore; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.storage.MultiHopStorage; import se.kth.ssvl.tslab.bytewalla.androiddtn.servlib.storage.RegistrationStore; import se.kth.ssvl.tslab.bytewalla.androiddtn.systemlib.storage.thread.MsgBlockingQueue; import se.kth.ssvl.tslab.bytewalla.androiddtn.systemlib.util.List; import se.kth.ssvl.tslab.bytewalla.androiddtn.systemlib.util.TimeHelper; /** * main DTNService daemon class to execute Bundle events posted in its queue. * This daemon will dispatch the events to Contact Manager and Router as it sees appropriate. * * @author Rerngvit Yanggratoke (rerngvit@kth.se) */ public class BundleDaemon extends BundleEventHandler implements Runnable { /** * General daemon parameters */ public static class Params { // "Whether or not to accept custody when requested" [DTN2] public boolean accept_custody_; // "Whether or not to delete bundles before they're expired if // all routers / registrations have handled it" [DTN2] public boolean early_deletion_; // "Whether or not injected bundles are held in memory by default" [DTN2] public boolean injected_bundles_in_memory_; // "Whether or not reactive fragmentation is enabled" [DTN2] public boolean reactive_frag_enabled_; // "Whether or not to retry unacked transmissions on reliable CLs." [DTN2] public boolean retry_reliable_unacked_; // "Whether or not to skip routing decisions for and delete duplicate // bundles" [DTN2] public boolean suppress_duplicates_; // "Test hook to permute bundles before delivering to registrations" [DTN2] public boolean test_permuted_delivery_; // / Default constructor Params() { early_deletion_ = true; suppress_duplicates_ = true; accept_custody_ = true; reactive_frag_enabled_ = false; retry_reliable_unacked_ = false; test_permuted_delivery_ = false; injected_bundles_in_memory_ = false; } } /** * Comparator implementation to sort BundleEvent according to the event's priority */ private static class BundleEventPriorityComparator implements Comparator<BundleEvent> { private static BundleEventPriorityComparator instance_; public static BundleEventPriorityComparator getInstance() { if (instance_ == null) { instance_ = new BundleEventPriorityComparator(); } return instance_; } public int compare(BundleEvent event1, BundleEvent event2) { // according the PriorityQueue the lower the output value the closer to the top of the queue if (event1.priority() < event2.priority()) return 1; else if (event1.priority() > event1.priority()) return -1; else return 0; } } /** * "Statistics structure definition" [DTN2] */ protected static class Stats { int deleted_bundles_; int delivered_bundles_; int duplicate_bundles_; int events_processed_; int expired_bundles_; int generated_bundles_; int injected_bundles_; int received_bundles_; int transmitted_bundles_; } public static Params params_; /** * Default Event Queue Capacity */ private final static int event_queue_capacity_ = 100; /** * Singleton implementation instance */ private static BundleDaemon instance_ = null; /** * String TAG for using in Android Logging system */ private final static String TAG = "BundleDaemon"; /** * "indicator that a BundleDaemon shutdown is in progress" [DTN2] */ protected static boolean shutting_down_; /** * Singleton client implementation * @return */ public static BundleDaemon getInstance() { if (instance_ == null) { instance_ = new BundleDaemon(); } return instance_; } public static String localEid() { return getInstance().local_eid().str(); } /** * "Accessor for the BundleDaemon's shutdown status" [DTN2] */ public static boolean shutting_down() { return shutting_down_; } /** * Event ticket for used in blocking execution */ private Integer event_ticket_; /** * Thread for running this daemon */ private Thread thread_; /** * "The active bundle actions handler" [DTN2] */ protected BundleActions actions_; /** * "The administrative registration" [DTN2] */ protected AdminRegistration admin_reg_; /** * "The list of all bundles in the system" [DTN2] */ protected BundleList all_bundles_; /** * "Application-specific shutdown data" [DTN2] */ protected ServlibEventData app_shutdown_data_; /** * "Application-specific shutdown handler" [DTN2] */ protected ServlibEventHandler app_shutdown_proc_; /** * "The contact manager" [DTN2] */ protected ContactManager contactmgr_; /** * "The list of all bundles that we have custody of" [DTN2] */ protected BundleList custody_bundles_; /** * The event queue */ protected PriorityBlockingQueue<BundleEvent> eventq_; /** * "The fragmentation / reassembly manager" [DTN2] */ protected FragmentManager fragmentmgr_; /** * The default EndpointID of this Daemon */ protected EndpointID local_eid_; /** * "The list of all bundles that are still being processed" [DTN2] */ protected BundleList pending_bundles_; /** * "The ping registration" [DTN2] */ protected PingRegistration ping_reg_; /** * "The table of active registrations" [DTN2] */ protected RegistrationTable reg_table_; /** * "The active bundle router" [DTN2] */ protected BundleRouter router_; /** * "Router-specific shutdown data" [DTN2] */ protected ServlibEventData rtr_shutdown_data_; /** * "Router-specific shutdown handler" [DTN2] */ protected ServlibEventHandler rtr_shutdown_proc_; /** * "Stats instance" [DTN2] */ protected Stats stats_; /** * main constructor */ private BundleDaemon() { do_init(); } /** * Return the current actions handler. */ public BundleActions actions() { return actions_; } /** * Accessor for the contact manager. */ public ContactManager contactmgr() { return contactmgr_; } /** * Accessor for the custody bundles list. */ public BundleList custody_bundles() { return custody_bundles_; } /** * Object initialization function */ public void do_init() { BundleProtocol.init_default_processors(); shutting_down_ = false; actions_ = new BundleActions(); contactmgr_ = ContactManager.getInstance(); custody_bundles_ = new BundleList("custody_bundles"); event_ticket_ = new Integer(0); eventq_ = new PriorityBlockingQueue<BundleEvent>(event_queue_capacity_, BundleEventPriorityComparator.getInstance()); fragmentmgr_ = FragmentManager.getInstance(); pending_bundles_ = new BundleList("pending_bundles"); reg_table_ = RegistrationTable.getInstance(); stats_ = new Stats(); params_ = new Params(); } /** * Return the number of events in the queue */ public int event_queue_size() { return eventq_.size(); } /** * Accessor for the fragmentation manager. */ public FragmentManager fragmentmgr() { return fragmentmgr_; } /** * Format the given StringBuffer with the current bundle statistics. */ public void get_bundle_stats(StringBuffer buf) { buf.append(String.format( "%d pending -- " + "%d custody -- " + "%d received -- " + "%d delivered -- " + "%d generated -- " + "%d transmitted -- " + "%d expired -- " + "%d duplicate -- " + "%d deleted -- " + "%d injected", pending_bundles_.size(), custody_bundles_.size(), stats_.received_bundles_, stats_.delivered_bundles_, stats_.generated_bundles_, stats_.transmitted_bundles_, stats_.expired_bundles_, stats_.duplicate_bundles_, stats_.deleted_bundles_, stats_.injected_bundles_ ) ); } /** * Format the given StringBuffer with the current internal statistics value. */ public void get_daemon_stats(StringBuffer buf) { buf.append(String.format( "%d pending_events -- " + "%d processed_events -- ", event_queue_size(), stats_.events_processed_ )); } /** * Format the given StringBuffer with current routing info. */ public void get_routing_state(StringBuffer buf) { router_.get_routing_state(buf); contactmgr_.dump(buf); } /** * Main event handling function. */ public void handle_event(BundleEvent event) { Log.i(TAG, String.format("BundleDaemon:handle_event %s", event.toString())); dispatch_event(event); if (!event.daemon_only()) { // "dispatch the event to the router and also // the contact manager" [DTN2] router_.handle_event(event); contactmgr_.handle_event(event); } event_handlers_completed(event); stats_.events_processed_++; if (event.processed_notifier_ != null) { try { event.processed_notifier_.put(event_ticket_); } catch (InterruptedException e) { Log.e(TAG, "BundleDaemon: handle_event InterruptedException"); } } } /** * Initialzation from configuration object */ public void init(DTNConfiguration config) { local_eid_ = new EndpointID(config.routes_setting().local_eid()); } /** * Return the local endpoint identifier. */ public final EndpointID local_eid() { return local_eid_; } /** * Accessor for the pending bundles list. */ public BundleList pending_bundles() { return pending_bundles_; } /** * Queues the event at the tail of the queue for processing by the daemon * thread. */ public void post(BundleEvent event) { post_event(event, true); } /** * Post the given event and wait for it to be processed by the daemon thread * or for the given timeout to elapse. */ public boolean post_and_wait(BundleEvent event, MsgBlockingQueue<Integer> notifier, int timeout, boolean at_back) { assert (event .processed_notifier() == null) : "BundleDeamon:post_and_wait, post_and_wait() event.process_notifier_ is not null"; event.processed_notifier_ = notifier; if (at_back) { post(event); } else { post_at_head(event); } // ticket use for blocking and notifying queue Integer ticket = null; assert (ticket == null); if (timeout == -1) { // Indefinite timeout here // Block until we get the ticket try { ticket = notifier.take(); } catch (InterruptedException e) { } return true; } else { // Use input timeout value here try { ticket = notifier.poll(timeout, TimeUnit.SECONDS); } catch (InterruptedException e) { Log.e(TAG, "BundleDeamon, InterruptedException, post_and_wait case Finite timeout"); return false; } return true; } } /** * Queues the event at the head of the queue for processing by the daemon * thread. */ public void post_at_head(BundleEvent event) { post_event(event, false); } /** * Post event at the front or back of the queue according to at_back parameter * @param the BundleEvent to be posted * @param at_back true if it will be at the end of the queue, false if it will be at the front of the queue */ public void post_event(BundleEvent event, boolean at_back) { Log.d(TAG, String.format("posting event (%s) with type %s (at %s)", event.toString(), event.type().toString(), at_back ? "back" : "head")); event.set_posted_time(Calendar.getInstance().getTime()); ; if (!at_back) { // if it's not at back , set the priority to higher than the head of the queue if (eventq_.size() > 0) { int highest_priority = eventq_.peek().priority(); event.set_priority(highest_priority + 1); } } eventq_.put(event); } /** * Accessor for the registration table. */ public final RegistrationTable reg_table() { return reg_table_; } /** * Reset all internal stats. */ public void reset_stats() { stats_ = new Stats(); contactmgr_.get_lock().lock(); try { LinkSet links = contactmgr_.links(); Iterator<Link> itr = links.iterator(); while (itr.hasNext()) { Link link = itr.next(); link.reset_stats(); } } finally { contactmgr_.get_lock().unlock(); } } /** * Returns the current bundle router. */ public BundleRouter router() { assert (router_ != null) : "BundleDaemon router_ is null"; return router_; } /** * "Main thread function that dispatches events." [DTN2] */ public void run() { try { // Create router according to config in the configuration process router_ = BundleRouter.create_router(); load_registrations(); load_bundles(); while (true) { if (shutting_down_) { Log.d(TAG, "BundleDaemon: shutting down"); break; } BundleEvent event; try { event = eventq_.take(); handle_event(event); } catch (InterruptedException e) { Log.e(TAG, "Event Handle Interuptted Exception"); } // } Log.d(TAG, "BundleDaemon: at the end of run() of Daemon"); } catch (RoutingException e1) { Log.e(TAG, "BundleDeamon:run(), UnknownRouterType "); } } /** * "Set an application-specific shutdown handler." [DTN2] */ public void set_app_shutdown(ServlibEventHandler proc, ServlibEventData data) { app_shutdown_proc_ = proc; app_shutdown_data_ = data; } /** * Set the local endpoint id. */ public void set_local_eid(final String eid_str) { local_eid_.assign(eid_str); } /** * Returns the current bundle router. */ public void set_router(BundleRouter router) { router_ = router; } /** * "Set a router-specific shutdown handler." [DTN2] */ public void set_rtr_shutdown(ServlibEventHandler proc, ServlibEventData data) { rtr_shutdown_proc_ = proc; rtr_shutdown_data_ = data; } /** * Start the Bundle Daemon by executing a new thread */ public void start() { shutting_down_ = false; thread_ = new Thread(this); thread_.start(); } /** * Test function for getting this class event Queue * @return */ public PriorityBlockingQueue<BundleEvent> test_get_eventq() { return eventq_; } /** * "Take custody for the given bundle, sending the appropriate signal to the * current custodian." [DTN2] */ protected void accept_custody(Bundle bundle) { Log.i(TAG, String.format("accept_custody bundle id %d", bundle.bundleid())); if (bundle.local_custody()) { Log.e(TAG, String.format("accept_custody( bundle id %d): already have local custody", bundle.bundleid())); return; } if (bundle.custodian().equals(local_eid_)) { Log.e(TAG, String.format("send_custody_signal(%d): " + "current custodian is already local_eid", bundle.bundleid())); return; } // "send a custody acceptance signal to the current custodian (if // it is someone, and not the null eid)" [DTN2] if (!bundle.custodian().equals(EndpointID.NULL_EID())) { generate_custody_signal(bundle, true, BundleProtocol.custody_signal_reason_t.CUSTODY_NO_ADDTL_INFO); } // "now we mark the bundle to indicate that we have custody and add // it to the custody bundles list" [DTN2] bundle.custodian().assign(local_eid_); bundle.set_local_custody(true); bundle.set_complete(true); actions_.store_update(bundle); custody_bundles_.push_back(bundle); // "finally, if the bundle requested custody acknowledgments, // deliver them now" [DTN2] if (bundle.custody_rcpt()) { generate_status_report(bundle, BundleStatusReport.flag_t.STATUS_CUSTODY_ACCEPTED, BundleProtocol.status_report_reason_t.REASON_NO_ADDTL_INFO); } } /** * "Add the bundle to the pending list and (optionally) the persistent store, * and set up the expiration timer for it." [DTN2] * * @return true "if the bundle is legal to be delivered and/or forwarded, * false if it's already expired" [DTN2] */ protected boolean add_to_pending(Bundle bundle, boolean add_to_store) { Log.d(TAG, String.format("adding bundle id %d to pending list", bundle.bundleid())); pending_bundles_.push_back(bundle); if (add_to_store) { bundle.set_complete(true); actions_.store_update(bundle); } // "schedule the bundle expiration timer" [DTN2] Calendar expiration_calendar = Calendar.getInstance(); expiration_calendar.setTimeInMillis(System.currentTimeMillis() + bundle.expiration() * 1000); Calendar now_Calendar = Calendar.getInstance(); long when = TimeHelper.seconds_from_ref(expiration_calendar) - TimeHelper.seconds_from_ref(now_Calendar); boolean ok_to_route = true; bundle.set_expiration_timer(new ExpirationTimer(bundle)); if (expiration_calendar.getTime().after(now_Calendar.getTime())) { Log.d(TAG, String.format(TAG, "scheduling expiration for bundle id %d at %d.%d " + "(in %d seconds)", bundle.bundleid(), TimeHelper.seconds_from_ref(expiration_calendar), expiration_calendar.get(Calendar.MILLISECOND), when)); bundle.expiration_timer().schedule_at(expiration_calendar.getTime()); } else { Log.w(TAG, String.format("scheduling IMMEDIATE expiration for bundle id %d: " + "[expiration %d, creation time %d.%d, offset %d, now %d.%d], Expire Time = %s", bundle.bundleid(), bundle.expiration(), bundle.creation_ts().seconds(), bundle.creation_ts().seqno(), BundleTimestamp.TIMEVAL_CONVERSION, TimeHelper.seconds_from_ref(now_Calendar), now_Calendar.get(Calendar.MILLISECOND), now_Calendar.getTime().toString())); bundle.expiration_timer().schedule_at(now_Calendar.getTime()); ok_to_route = false; } return ok_to_route; } /** * "Cancel any pending custody timers for the bundle." [DTN2] */ protected void cancel_custody_timers(Bundle bundle) { bundle.get_lock().lock(); try { Iterator<CustodyTimer> iter = bundle.custody_timers().iterator(); while (iter.hasNext()) { CustodyTimer timer = iter.next(); timer.cancel(); } bundle.custody_timers().clear(); } finally { bundle.get_lock().unlock(); } } /** * "Check the registration table and optionally deliver the bundle to any * that match." [DTN2] * * @return "whether or not any matching registrations were found or if the * bundle is destined for the local node" [DTN2] */ protected boolean check_local_delivery(Bundle bundle, boolean deliver) { Log.d(TAG, String.format("checking for matching registrations for bundle id %d", bundle.bundleid())); RegistrationList matches = new RegistrationList(); reg_table_.get_matching(bundle.dest(), matches); if (deliver) { assert (!bundle.is_fragment()) : "BundleDaemon:check_local_delivery, bundle is fragmented"; Iterator<Registration> iter = matches.iterator(); while (iter.hasNext()) { Registration registration = iter.next(); deliver_to_registration(bundle, registration); } } return (matches.size() > 0) || bundle.dest().subsume(local_eid_); } /** * "Delete (rather than silently discard) a bundle, e.g., an expired bundle. * Releases custody of the bundle, removes fragmentation state for the * bundle if necessary, removes the bundle from the pending list, and sends * a bundle deletion status report if necessary." [DTN2] */ protected boolean delete_bundle(final Bundle bundle, status_report_reason_t reason) { if (bundle == null) Log.e(TAG, " bundle in delete_bundle is null "); ++stats_.deleted_bundles_; // "send a bundle deletion status report if we have custody or the // bundle's deletion status report request flag is set and a reason // for deletion is provided" [DTN2] boolean send_status = (bundle.local_custody() || (bundle.deletion_rcpt() && reason != BundleProtocol.status_report_reason_t.REASON_NO_ADDTL_INFO)); // "check if we have custody, if so, remove it" [DTN2] if (bundle.local_custody()) { release_custody(bundle); } // "check if bundle is a fragment, if so, remove any fragmentation state" [DTN2] if (bundle.is_fragment()) { fragmentmgr_.delete_fragment(bundle); } // "notify the router that it's time to delete the bundle" [DTN2] router_.delete_bundle(bundle); // "delete the bundle from the pending list" [DTN2] Log.d(TAG, String.format("pending_bundles size %d", pending_bundles_.size())); boolean erased = true; if (bundle.is_queued_on(pending_bundles_)) { erased = delete_from_pending(bundle); } if (erased && send_status) { generate_status_report(bundle, BundleStatusReport.flag_t.STATUS_DELETED, reason); } // "cancel the bundle on all links where it is queued or in flight" [DTN2] Date now = Calendar.getInstance().getTime(); contactmgr_.get_lock().lock(); try { Iterator<Link> itr = contactmgr_.links().iterator(); while (itr.hasNext()) { Link link = itr.next(); if (link.queue().contains(bundle) || link.inflight().contains(bundle)) { actions_.cancel_bundle(bundle, link); } } Log.d(TAG, String.format("BundleDaemon: canceling deleted bundle on all links took %d ms", TimeHelper.elapsed_ms(now))); BundleDaemon.getInstance().post_at_head(new BundleFreeEvent(bundle)); return erased; } finally { contactmgr_.get_lock().unlock(); } } /** * "Remove the bundle from the pending list and data store, and cancel the * expiration timer." [DTN2] */ protected boolean delete_from_pending(final Bundle bundle) { Log.d(TAG, String.format("removing bundle %d from pending list", bundle.bundleid())); // "first try to cancel the expiration timer if it's still around" [DTN2] if (bundle.expiration_timer() != null) { Log.d(TAG, String.format("cancelling expiration timer for bundle id %d", bundle.bundleid())); bundle.expiration_timer().cancel(); if (!bundle.expiration_timer().cancelled()) { Log.e(TAG, String.format("unexpected error cancelling expiration timer " + "for bundle %d", bundle.bundleid())); } bundle.set_expiration_timer(null); } Log.d(TAG, String.format("pending_bundles size %d", pending_bundles_.size())); boolean erased = pending_bundles_.erase(bundle, false); if (!erased) { Log.e(TAG, "unexpected error removing bundle from pending list"); } return erased; } /** * "Deliver the bundle to the given registration" [DTN2] */ protected void deliver_to_registration(Bundle bundle, Registration registration) { assert (!bundle.is_fragment()) : "BundleDaemon:deliver_to_registration, bundle is fragmented!"; ForwardingInfo.state_t state = bundle.fwdlog().get_latest_entry_state(registration); if (state != ForwardingInfo.state_t.NONE) { assert (state == ForwardingInfo.state_t.DELIVERED) : "BundleDaemon:deliver_to_registration, state is not None but is not Delivered as well!"; Log.d(TAG, String.format( "not delivering bundle id %d to registration %d (%s) " + "since already delivered", bundle.bundleid(), registration.regid(), registration.endpoint().toString())); return; } Log.d(TAG, String.format("delivering bundle id %d to registration %d (%s)", bundle.bundleid(), registration.regid(), registration.endpoint().toString())); if (registration.deliver_if_not_duplicate(bundle)) { bundle.fwdlog().add_entry(registration, ForwardingInfo.action_t.FORWARD_ACTION, ForwardingInfo.state_t.DELIVERED); } else { Log.i(TAG, String.format("suppressing duplicate delivery of bundle %d " + "to registration %d (%s)", bundle.bundleid(), registration.regid(), registration.endpoint().toString())); } } /** * "Routine executing after the every completion of the Bundle Event" [DTN2] * @param event */ protected void event_handlers_completed(BundleEvent event) { Log.d(TAG, String.format("Event Handler Complete for (%s) %s", event.toString(), event.type().toString())); /** * "Once bundle reception, transmission or delivery has been processed by * the router, check to see if it's still needed, otherwise we delete * it." [DTN2] */ Bundle bundle = null; if (event.type() == event_type_t.BUNDLE_TRANSMITTED) { bundle = ((BundleTransmittedEvent) event).bundle(); } if (event.type() == event_type_t.BUNDLE_DELIVERED) { bundle = ((BundleDeliveredEvent) event).bundle(); } if (bundle != null) { try_to_delete(bundle); } /** * "Once the bundle expired event has been processed, the bundle * shouldn't exist on any more lists." [DTN2] */ if (event.type() == event_type_t.BUNDLE_EXPIRED) { bundle = ((BundleExpiredEvent) event).bundle(); int num_mappings = bundle.num_mappings(); if (num_mappings != 0) { Log.w(TAG, String.format( "BundleDaemon:event_handlers_completed, expired bundle %s still has %d mappings ", bundle, num_mappings)); } } } /** * "Check if there are any bundles in the pending queue that match the source * id, timestamp, and fragmentation offset/length fields." [DTN2] */ protected Bundle find_duplicate(Bundle b) { pending_bundles_.get_lock().lock(); try { Log.d(TAG, String.format("pending_bundles size %d", pending_bundles_.size())); Bundle found = null; ListIterator<Bundle> iter = pending_bundles_.begin(); while (iter.hasNext()) { Bundle b2 = iter.next(); if ((b.source().equals(b2.source())) && (b.creation_ts().seconds() == b2.creation_ts().seconds()) && (b.creation_ts().seqno() == b2.creation_ts().seqno()) && (b.is_fragment() == b2.is_fragment()) && (b.frag_offset() == b2.frag_offset()) && /* (b.orig_length() == b2.orig_length()) && */ (b.payload().length() == b2.payload().length())) { // b is a duplicate of b2 Log.d(TAG, "BUNDLE DUPLICATE: newly received bundle ( id = " + b2.bundleid() + " ) is a duplicate of bundle id " + b.bundleid()); found = b2; if (params_.suppress_duplicates_ || b2.local_custody()) break; } } return found; } catch (BundleListLockNotHoldByCurrentThread e) { Log.e(TAG, "BundleDaemon:find_duplicate, BundleList Lock Not Hold by current Thread Exception"); return null; } finally { pending_bundles_.get_lock().unlock(); } } /** * "Generate a custody signal to be sent to the current custodian." [DTN2] */ protected void generate_custody_signal(Bundle bundle, boolean succeeded, custody_signal_reason_t reason) { if (bundle.local_custody()) { Log.e(TAG, String.format("send_custody_signal(bundle id %d): already have local custody", bundle.bundleid())); return; } if (bundle.custodian().equals(EndpointID.NULL_EID())) { Log.e(TAG, String.format("send_custody_signal(bundle id %d): current custodian is NULL_EID", bundle.bundleid())); return; } Bundle signal = CustodySignal.create_custody_signal(bundle, local_eid_, succeeded, reason); BundleReceivedEvent e = new BundleReceivedEvent(signal, event_source_t.EVENTSRC_ADMIN); handle_event(e); } /** * "Locally generate a status report for the given bundle." [DTN2] */ protected void generate_status_report(Bundle orig_bundle, BundleStatusReport.flag_t flag, status_report_reason_t reason) { Log.d(TAG, String.format("generating return receipt status report, " + "flag = %s, reason = %s", flag.toString(), reason.toString())); Bundle report = BundleStatusReport.create_status_report(orig_bundle, local_eid_, flag.getCode(), reason); BundleReceivedEvent e = new BundleReceivedEvent(report, event_source_t.EVENTSRC_ADMIN); handle_event(e); } protected void handle_bundle_accept(BundleAcceptRequest request) { boolean[] result_value = request.result(); result_value[0] = router_.accept_bundle(request.bundle(), request.reason()); String reason_string = request.reason()[0] != null ? request.reason()[0].toString() : "no reason"; Log.i(TAG, String.format("BUNDLE_ACCEPT_REQUEST: bundle %d %s (reason %s)", request.bundle().bundleid(), result_value[0] ? "accepted" : "not accepted", reason_string)); } protected void handle_bundle_cancel(BundleCancelRequest event) { Bundle bundle = event.bundle(); if (bundle == null) { Log.e(TAG, "NULL bundle object in BundleCancelRequest"); return; } // "If the request has a link name, we are just canceling the send on // that link." [DTN2] if (!event.link().name_str().equals("")) { Link link = contactmgr_.find_link(event.link().name_str()); if (link == null) { Log.e(TAG, String.format("BUNDLE_CANCEL no link with name %s", event.link().name_str())); return; } Log.i(TAG, String.format("BUNDLE_CANCEL bundle %d on link %s", bundle.bundleid(), event.link().name())); Log.d(TAG, " handle_bundle_cancel"); if (bundle == null) { Log.e(TAG, "bundle is null in handle cancel bundle"); } actions_.cancel_bundle(bundle, link); } // "If the request does not have a link name, the bundle itself has been // canceled (probably by an application)." [DTN2] else { delete_bundle(bundle, BundleProtocol.status_report_reason_t.REASON_NO_ADDTL_INFO); } } protected void handle_bundle_cancelled(BundleSendCancelledEvent event) { Bundle bundle = event.bundle(); Link link = event.link(); Log.i(TAG, String.format("BUNDLE_CANCELLED id:%d -> %s (%s)", bundle.bundleid(), link.name(), link.nexthop())); Log.d(TAG, String.format("trying to find xmit blocks for bundle id:%d on link %s", bundle.bundleid(), link.name())); BlockInfoVec blocks = bundle.xmit_link_block_set().find_blocks(link); // "Because a CL is running in another thread or process (External CLs), // we cannot prevent all redundant transmit/cancel/transmit_failed // messages. If an event about a bundle bound for particular link is // posted after another, which it might contradict, the BundleDaemon // need not reprocess the event. The router (DP) might, however, be // interested in the new status of the send." [DTN2] if (blocks == null) { Log.i(TAG, String.format( "received a redundant/conflicting bundle_cancelled event " + "about bundle id:%d -> %s (%s)", bundle.bundleid(), link.name(), link.nexthop() )); return; } /* * "The bundle should no longer be on the link queue or on the inflight * queue if it was cancelled." [DTN2] */ if (link.queue().contains(bundle)) { Log.w(TAG, String.format("cancelled bundle id:%d still on link %s queue", bundle.bundleid(), link.name())); } /* * "The bundle should no longer be on the link queue or on the inflight * queue if it was cancelled." [DTN2] */ if (link.inflight().contains(bundle)) { Log.w(TAG, String.format("cancelled bundle id:%d still on link %s inflight list", bundle.bundleid(), link.name())); } /* * "Update statistics. Note that the link's queued length must always be * decremented by the full formatted size of the bundle." [DTN2] */ link.stats().set_bundles_cancelled(link.stats().bundles_cancelled() + 1); /* * "Remove the formatted block info from the bundle since we don't need * it any more." [DTN2] */ Log.d(TAG, String.format("trying to delete xmit blocks for bundle id:%d on link %s", bundle.bundleid(), link.name())); BundleProtocol.delete_blocks(bundle, link); blocks = null; /* * "Update the forwarding log." [DTN2] */ Log.d(TAG, String.format( "trying to update the forwarding log for " + "bundle id:%d on link %s to state CANCELLED", bundle.bundleid(), link.name())); bundle.fwdlog().update(link, ForwardingInfo.state_t.CANCELLED); } protected void handle_bundle_delete(BundleDeleteRequest request) { if (request.bundle() != null) { Log.i(TAG, String.format("BUNDLE_DELETE: bundle %d (reason %s)", request.bundle().bundleid(), request.reason().toString())); delete_bundle(request.bundle(), request.reason()); } } protected void handle_bundle_delivered(BundleDeliveredEvent event) { stats_.delivered_bundles_++; /* * "The bundle was delivered to a registration." [DTN2] */ Bundle bundle = event.bundle(); Log.i(TAG, String.format("BUNDLE_DELIVERED id:%d (%d bytes) . regid %d (%s)", bundle.bundleid(), bundle.payload().length(), event.registration().regid(), event.registration().endpoint().toString())); /* * "Generate the delivery status report if requested." [DTN2] */ if (bundle.delivery_rcpt()) { generate_status_report(bundle, BundleStatusReport.flag_t.STATUS_DELIVERED, BundleProtocol.status_report_reason_t.REASON_NO_ADDTL_INFO); } /* * "If this is a custodial bundle and it was delivered, we either release * custody (if we have it), or send a custody signal to the current * custodian indicating that the bundle was successfully delivered, * unless there is no current custodian (the eid is still dtn:none).| [DTN2] */ if (bundle.custody_requested()) { if (bundle.local_custody()) { release_custody(bundle); } else if (bundle.custodian().equals(EndpointID.NULL_EID())) { Log.i(TAG, String.format("custodial bundle %d delivered before custody accepted", bundle.bundleid())); } else { generate_custody_signal(bundle, true, BundleProtocol.custody_signal_reason_t.CUSTODY_NO_ADDTL_INFO); } } } protected void handle_bundle_expired(BundleExpiredEvent event) { stats_.expired_bundles_++; Bundle bundle = event.bundle(); Log.i(TAG, String.format("BUNDLE_EXPIRED bundle ID %d", bundle.bundleid())); delete_bundle(bundle, BundleProtocol.status_report_reason_t.REASON_LIFETIME_EXPIRED); } protected void handle_bundle_free(BundleFreeEvent event) { Bundle bundle = event.bundle(); event.set_bundle(null); bundle.get_lock().lock(); try { Log.d(TAG, "removing freed bundle from data store"); actions_.store_del(bundle); Log.d(TAG, "deleting freed bundle"); } finally { bundle.get_lock().unlock(); } } protected void handle_bundle_inject(BundleInjectRequest event) { EndpointID src = event.src(); EndpointID dest = event.dest(); if ((!src.valid()) || (!dest.valid())) return; // "The bundle's source EID must be either dtn:none or an EID // registered at this node." [DTN2] RegistrationTable reg_table = BundleDaemon.getInstance().reg_table(); String base_reg_str = src.uri().getScheme() + "://" + src.uri().getHost(); Registration reg = reg_table.get(new EndpointIDPattern(base_reg_str)); if (reg == null && src.equals(EndpointID.NULL_EID())) { Log.e(TAG, String.format("this node is not a member of the injected bundle's source " + "EID (%s)", src.toString())); return; } // "The new bundle is placed on the pending queue but not // in durable storage (no call to BundleActions::inject_bundle)" [DTN2] Bundle bundle = new Bundle(params_.injected_bundles_in_memory_ ? BundlePayload.location_t.MEMORY : BundlePayload.location_t.DISK); bundle.source().assign(src); bundle.dest().assign(dest); if (!bundle.replyto().assign(event.replyto())) bundle.replyto().assign(EndpointID.NULL_EID()); if (!bundle.custodian().assign(event.custodian())) bundle.custodian().assign(EndpointID.NULL_EID()); // "bundle COS defaults to COS_BULK" [DTN2] bundle.set_priority(event.priority_values()); // "bundle expiration on remote dtn nodes // defaults to 5 minutes" [DTN2] if (event.expiration() == 0) bundle.set_expiration(300); else bundle.set_expiration(event.expiration()); // "set the payload then removing original" [DTN2] bundle.payload().replace_with_file(event.payload_file()); Log.d(TAG, String.format("bundle payload size after replace_with_file(): %d", bundle.payload().length())); File event_payload_file = event.payload_file(); event_payload_file.delete(); /* * "Deliver the bundle to any local registrations that it matches, unless * it's generated by the router or is a bundle fragment. Delivery of * bundle fragments is deferred until after re-assembly." [DTN2] */ boolean is_local = check_local_delivery(bundle, !bundle.is_fragment()); /* * "Re-assemble bundle fragments that are destined to the local node." [DTN2] */ if (bundle.is_fragment() && is_local) { Log.d(TAG, String.format("deferring delivery of injected bundle %d " + "since bundle is a fragment", bundle.bundleid())); fragmentmgr_.process_for_reassembly(bundle); } // "The injected bundle is no longer sent automatically. It is // instead added to the pending queue so that it can be resent // or sent on multiple links. // If add_to_pending returns false, the bundle has already expired" [DTN2] if (add_to_pending(bundle, false)) BundleDaemon.getInstance().post(new BundleInjectedEvent(bundle, event.request_id())); ++stats_.injected_bundles_; } protected void handle_bundle_injected(BundleInjectedEvent event) { } protected void handle_bundle_query(BundleQueryRequest event) { BundleDaemon.getInstance().post_at_head(new BundleReportEvent()); } protected void handle_bundle_queued_query(BundleQueuedQueryRequest request) { Link link = request.link(); assert (link != null) : "BundleDaemon:handle_bundle_queued_query, link is null"; assert (link.clayer() != null) : "BundleDaemon:handle_bundle_queued_query, CLayer is null"; Log.e(TAG, String.format( "BundleDaemon::handle_bundle_queued_query: " + "query %s, checking if bundle %d is queued on link %s", request.query_id(), request.bundle().bundleid(), link.name())); boolean is_queued = request.bundle().is_queued_on(link.queue()); post(new BundleQueuedReportEvent(request.query_id(), is_queued)); } protected void handle_bundle_queued_report(BundleQueuedReportEvent event) { Log.e(TAG, String.format("BundleDaemon::handle_bundle_queued_report: query %s, %s", event.query_id(), event.is_queued() ? "true" : "false")); } protected void handle_bundle_received(BundleReceivedEvent event) { Bundle bundle = event.bundle(); String notify_msg = ""; String ID = local_eid().toString() + "/"; // Log.v(TAG, "daemon_bundle_id" + (int) bundle.bundleid()); // Log.v(TAG,"daemon_source" + bundle.source().toString()); // Log.v(TAG,"daemon_destination" + bundle.custodian().toString()); // Toast.makeText(,"local : "+local_eid().toString()+"\nDest : "+bundle.act_dest().toString(),Toast.LENGTH_SHORT).show(); // Log.d(TAG, " time ID " + bundle.creation_ts().seconds()); // Log.d(TAG, " custodian ID " + ID); // Log.d(TAG, " LOCAL ID " + local_eid().toString()); Log.d(TAG, " handle bundle received from " + event.source() + ", id = " + bundle.bundleid()); // "update statistics and store an appropriate event descriptor" [DTN2] String source_str = ""; switch (event.source()) { case EVENTSRC_PEER: stats_.received_bundles_++; // MultiHopStorage.getInstance().impt_sqlite_().get_records("bundle","id>0","id"); String output = ""; byte[] result = new byte[bundle.payload().length()]; RandomAccessFile file_handle = null; try { file_handle = new RandomAccessFile(bundle.payload().file(), "r"); file_handle.read(result); output = new String(result, "US-ASCII"); } catch (UnsupportedEncodingException e) { Log.e(TAG, e.getMessage()); } catch (FileNotFoundException e) { Log.e(TAG, e.getMessage()); } catch (IOException e) { Log.e(TAG, e.getMessage()); } finally { try { file_handle.close(); } catch (IOException e) { Log.e(TAG, e.getMessage()); } } if (bundle.custodian() != null && !bundle.custodian().equals(EndpointID.NULL_EID())) { //String encrypted = bundle.custodian().toString(); //String [] both = encrypted.split("\n"); //bundle.set_custodian(); //String custodian = both[0]; //if(!custodian.equals(ID)) { if (!bundle.custodian().toString().equals(ID)) { //String msg = both[1]; //bundle.set_owner(msg); notify_msg += "Guest "; // if this was my bundle that i have sent but some one sent me, discard it if (bundle.source().toString().equals(BundleDaemon.getInstance().local_eid().toString())) return; // ArrayList<String> items = new ArrayList<String>(Arrays.asList(output.split(" ,"))); output = items.get(0); bundle.set_bundleid((Integer.parseInt(items.get(1)))); // Checking if already sent to actual destination if (MultiHopStorage .getInstance().impt_sqlite_().get_records("Forwards", "bundle_id = " + bundle.bundleid() + " and destination = '" + bundle.custodian().toString() + "'", "id") .size() > 0) { return; } // check if this bundle already exists in my database, discard it if (MultiHopStorage.getInstance().impt_sqlite_() .get_records("bundle", "bundle_id = " + bundle.bundleid() + " and source = '" + bundle.source() + "'" + " and destination = '" + bundle.custodian().toString() + "'", "id") .size() > 0) { return; } else { // so its a new bundle destined to some node , i am the intermediate one. // add this bundle to db after adding current alive nodes to forward list to indicate that // bundle is already been sent to these nodes // LinkSet EntriesList = ContactManager.getInstance().links(); Iterator<String> i = DTNDiscovery.getNodes().iterator(); // Link.set_link_counter(0); while (i.hasNext()) { // Link element = i.next(); String Eid = i.next(); MultiHopStorage.getInstance().add(bundle.bundleid(), Eid + "/"); // here it is adding in forwards table } MultiHopStorage.getInstance().add(bundle, output); } } else if (!bundle.source().toString().contains("prophet")) { if (output.contains(" ,")) { ArrayList<String> items = new ArrayList<String>(Arrays.asList(output.split(" ,"))); output = items.get(0); } MultiHopStorage.getInstance().add_messages(bundle.source().toString() + "/", output); // DTNMessageView.update(); } } // else Toast.makeText(DTNManager.getInstance().getApplicationContext(),"From " + bundle.source().toString(),Toast.LENGTH_LONG).show(); Log.d("RECIVINGS", "forwarded From " + bundle.source().toString()); DTNManager.getInstance().notify_user(notify_msg + "DTN Bundle Received", "From " + bundle.source().toString()); break; case EVENTSRC_APP: stats_.received_bundles_++; source_str = " (from app)"; break; case EVENTSRC_STORE: source_str = " (from data store)"; break; case EVENTSRC_ADMIN: stats_.generated_bundles_++; source_str = " (generated)"; break; case EVENTSRC_FRAGMENTATION: stats_.generated_bundles_++; source_str = " (from fragmentation)"; break; case EVENTSRC_ROUTER: stats_.generated_bundles_++; source_str = " (from router)"; break; default: Log.e(TAG, "Bundle Daemon: handle_bundle_received"); } StringBuffer buf = new StringBuffer(); bundle.format(buf); Log.i(TAG, String.format("BUNDLE_RECEIVED %s bundle id (%d) prevhop %s (%d bytes recvd)", source_str, bundle.bundleid(), event.prevhop().toString(), event.bytes_received())); // log the reception in the bundle's forwarding log if (event.source() == event_source_t.EVENTSRC_PEER && event.link() != null) { bundle.fwdlog().add_entry(event.link(), ForwardingInfo.action_t.FORWARD_ACTION, ForwardingInfo.state_t.RECEIVED); } else if (event.source() == event_source_t.EVENTSRC_APP) { if (event.registration() != null) { bundle.fwdlog().add_entry(event.registration(), ForwardingInfo.action_t.FORWARD_ACTION, ForwardingInfo.state_t.RECEIVED); } } // "log a warning if the bundle doesn't have any expiration time or // has a creation time that's in the future. in either case, we // proceed as normal" [DTN2] if (bundle.expiration() == 0) { Log.w(TAG, String.format("bundle id %d arrived with zero expiration time", bundle.bundleid())); } long now = TimeHelper.current_seconds_from_ref(); if ((bundle.creation_ts().seconds() > now) && (bundle.creation_ts().seconds() - now > 30000)) { Log.w(TAG, String.format("bundle id %d arrived with creation time in the future " + "(%d > %d)", bundle.bundleid(), bundle.creation_ts().seconds(), now)); } /* * "If a previous hop block wasn't included, but we know the remote * endpoint id of the link where the bundle arrived, assign the prevhop_ * field in the bundle so it's available for routing." [DTN2] */ if (event.source() == event_source_t.EVENTSRC_PEER) { if (bundle.prevhop() == null || bundle.prevhop().uri() == null) { bundle.set_prevhop(new EndpointID(EndpointID.NULL_EID())); } if (bundle.prevhop().is_null()) { bundle.prevhop().assign(event.prevhop()); } if (!bundle.prevhop().equals(event.prevhop())) { Log.w(TAG, String.format( "previous hop mismatch: prevhop header contains '%s' but " + "convergence layer indicates prevhop is '%s'", bundle.prevhop().toString(), event.prevhop().toString())); } } /* * "validate a bundle, including all bundle blocks, received from a peer" [DTN2] */ if (event.source() == event_source_t.EVENTSRC_PEER) { /* * "Check all BlockProcessors to validate the bundle. Initialize the * value in case the Bundle Protocol didn't give reason" [DTN2] */ status_report_reason_t[] reception_reason = new status_report_reason_t[1]; reception_reason[0] = status_report_reason_t.REASON_NO_ADDTL_INFO; status_report_reason_t[] deletion_reason = new status_report_reason_t[1]; deletion_reason[0] = status_report_reason_t.REASON_NO_ADDTL_INFO; boolean valid = BundleProtocol.validate(bundle, reception_reason, deletion_reason); /* * "Send the reception receipt if requested within the primary block * or some other error occurs that requires a reception status * report but may or may not require deleting the whole bundle." [DTN2] */ if (bundle.receive_rcpt() || reception_reason[0] != BundleProtocol.status_report_reason_t.REASON_NO_ADDTL_INFO) { generate_status_report(bundle, BundleStatusReport.flag_t.STATUS_RECEIVED, reception_reason[0]); } /* * "If the bundle is valid, probe the router to see if it wants to * accept the bundle." [DTN2] */ boolean accept_bundle = false; if (valid) { BundleProtocol.status_report_reason_t[] reason = new BundleProtocol.status_report_reason_t[1]; // "initialize the value in case the router didn't set the value // reason for us" [DTN2] reason[0] = status_report_reason_t.REASON_NO_ADDTL_INFO; accept_bundle = router_.accept_bundle(bundle, reason); deletion_reason[0] = reason[0]; } /* * "Delete a bundle if a validation error was encountered or the * router doesn't want to accept the bundle, in both cases not * giving the reception event to the router." [DTN2] */ if (!accept_bundle) { delete_bundle(bundle, deletion_reason[0]); event.set_daemon_only(true); return; } } /* * "Check if the bundle is a duplicate, i.e. shares a source id, * timestamp, and fragmentation information with some other bundle in * the system." [DTN2] */ Bundle duplicate = find_duplicate(bundle); if (duplicate != null) { Log.i(TAG, String.format("got duplicate bundle: %s . %s creation timestamp %d.%d", bundle.source().toString(), bundle.dest().toString(), bundle.creation_ts().seconds(), bundle.creation_ts().seqno())); stats_.duplicate_bundles_++; if (bundle.custody_requested() && duplicate.local_custody()) { generate_custody_signal(bundle, false, BundleProtocol.custody_signal_reason_t.CUSTODY_REDUNDANT_RECEPTION); } if (params_.suppress_duplicates_) { // "since we don't want the bundle to be processed by the rest // of the system, we mark the event as daemon_only (meaning it // won't be forwarded to routers) and return, which should // eventually remove all references on the bundle and then it // will be deleted" [DTN2] event.set_daemon_only(true); return; } // "The BP says that the "dispatch pending" retention constraint // must be removed from this bundle if there is a duplicate we // currently have custody of. This would cause the bundle to have // no retention constraints and it now "may" be discarded. Assuming // this means it is supposed to be discarded, we have to suppress // a duplicate in this situation regardless of the parameter // setting. We would then be relying on the custody transfer timer // to cause a new forwarding attempt in the case of routing loops // instead of the receipt of a duplicate, so in theory we can indeed // suppress this bundle. It may not be strictly required to do so, // in which case we can remove the following block." [DTN2] if (bundle.custody_requested() && duplicate.local_custody()) { event.set_daemon_only(true); return; } } /* * "Add the bundle to the master pending queue and the data store (unless * the bundle was just reread from the data store on startup) * * Note that if add_to_pending returns false, the bundle has already * expired so we immediately return instead of trying to deliver and/or * forward the bundle. Otherwise there's a chance that expired bundles * will persist in the network." [DTN2] */ boolean ok_to_route = add_to_pending(bundle, (event.source() != event_source_t.EVENTSRC_STORE)); if (!ok_to_route) { event.set_daemon_only(true); return; } /* * "If the bundle is a custody bundle and we're configured to take * custody, then do so. In case the event was delivered due to a reload * from the data store, then if we have local custody, make sure it's * added to the custody bundles list." [DTN2] */ if (bundle.custody_requested() && params_.accept_custody_ && (duplicate == null || !duplicate.local_custody())) { if (event.source() != event_source_t.EVENTSRC_STORE) { accept_custody(bundle); } else if (bundle.local_custody()) { custody_bundles_.push_back(bundle); } } /* * "If this bundle is a duplicate and it has not been suppressed, we can * assume the bundle it duplicates has already been delivered or added * to the fragment manager if required, so do not do so again. We can * bounce out now. Comments/jmmikkel If the extension blocks differ and * we care to do something with them, we can't bounce out quite yet." [DTN2] */ if (duplicate != null) { // We have to delete the Bundle here delete_bundle(bundle, status_report_reason_t.REASON_NO_ADDTL_INFO); return; } /* * "Check if this is a complete (non-fragment) bundle that obsoletes any * fragments that we know about." [DTN2] */ if (!bundle.is_fragment() && DTNService.context().getResources() .getString(R.string.DTNEnableProactiveFragmentation).equals("true")) { fragmentmgr_.delete_obsoleted_fragments(bundle); } /* * "Deliver the bundle to any local registrations that it matches, unless * it's generated by the router or is a bundle fragment. Delivery of * bundle fragments is deferred until after re-assembly." [DTN2] */ boolean is_local = check_local_delivery(bundle, (event.source() != event_source_t.EVENTSRC_ROUTER) && (bundle.is_fragment() == false)); /* * "Re-assemble bundle fragments that are destined to the local node." [DTN2] */ if (bundle.is_fragment() && is_local) { Log.d(TAG, String.format("deferring delivery of bundle %d " + "since bundle is a fragment", bundle.bundleid())); fragmentmgr_.process_for_reassembly(bundle); } /* * "Finally, bounce out so the router(s) can do something further with * the bundle in response to the event." [DTN2] */ } protected void handle_bundle_report(BundleReportEvent event) { } protected void handle_bundle_send(BundleSendRequest event) { Link link = contactmgr_.find_link(event.link().name()); if (link == null) { Log.e(TAG, String.format("Cannot send bundle on unknown link %s", event.link().name())); return; } Bundle bundle = event.bundle(); if (bundle == null) { Log.e(TAG, "NULL bundle object in BundleSendRequest"); return; } actions_.queue_bundle(bundle, link, event.action(), CustodyTimerSpec.getDefaultInstance()); } protected void handle_bundle_transmitted(BundleTransmittedEvent event) { Bundle bundle = event.bundle(); Link link = event.link(); assert (link != null) : "BundleDaemon:handle_bundle_transmitted, link is null"; Log.d(TAG, String.format("trying to find xmit blocks for bundle id:%d on link %s", bundle.bundleid(), link.name())); BlockInfoVec blocks = bundle.xmit_link_block_set().find_blocks(link); if (blocks == null) { Log.i(TAG, String.format( "received a redundant/conflicting bundle_transmit event about " + "bundle id:%d . %s (%s)", bundle.bundleid(), link.name(), link.nexthop())); return; } /* * "Update statistics and remove the bundle from the link inflight queue. * Note that the link's queued length statistics must always be * decremented by the full formatted size of the bundle, yet the * transmitted length is only the amount reported by the event." [DTN2] */ int total_len = BundleProtocol.total_length(blocks); stats_.transmitted_bundles_++; link.stats().set_bundles_transmitted(link.stats().bundles_transmitted() + 1); link.stats().set_bytes_transmitted(link.stats().bytes_transmitted() + event.bytes_sent()); // "remove the bundle from the link's in flight queue" [DTN2] if (link.del_from_inflight(event.bundle(), total_len)) { Log.d(TAG, String.format("removed bundle id:%d from link %s inflight queue", bundle.bundleid(), link.name())); } else { Log.w(TAG, String.format("bundle id:%d not on link %s inflight queue", bundle.bundleid(), link.name())); } // "verify that the bundle is not on the link's to-be-sent queue" [DTN2] if (link.del_from_queue(event.bundle(), total_len)) { Log.w(TAG, String.format("bundle id:%d unexpectedly on link %s queue in transmitted event", bundle.bundleid(), link.name())); } Log.i(TAG, String.format("BUNDLE_TRANSMITTED id:%d (%d bytes_sent/%d reliable) . %s (%s)", bundle.bundleid(), event.bytes_sent(), event.reliably_sent(), link.name(), link.nexthop())); /* * "If we're configured to wait for reliable transmission, then check the * special case where we transmitted some or all a bundle but nothing * was acked. In this case, we create a transmission failed event in the * forwarding log and don't do any of the rest of the processing below. * * Note also the special care taken to handle a zero-length bundle. * XXX/demmer this should all go away when the lengths include both * the header length and the payload length (in which case it's never * zero). * * XXX/demmer a better thing to do (maybe) would be to record the * lengths in the forwarding log as part of the transmitted entry."[DTN2] */ if (params_.retry_reliable_unacked_ && link.is_reliable() && (event.bytes_sent() != event.reliably_sent()) && (event.reliably_sent() == 0)) { bundle.fwdlog().update(link, ForwardingInfo.state_t.TRANSMIT_FAILED); Log.d(TAG, String.format("trying to delete xmit blocks for bundle id:%d on link %s", bundle.bundleid(), link.name())); BundleProtocol.delete_blocks(bundle, link); Log.d(TAG, "XXX/demmer fixme transmitted special case"); return; } /* * "Grab the latest forwarding log state so we can find the custody timer * information (if any)." [DTN2] */ boolean[] found = new boolean[1]; ForwardingInfo fwdinfo = bundle.fwdlog().get_latest_entry(link, found); if (!found[0]) { StringBuffer buf = new StringBuffer(); bundle.fwdlog().dump(buf); Log.d(TAG, buf.toString()); } if (fwdinfo.state() != ForwardingInfo.state_t.QUEUED) { Log.e(TAG, String.format("Bundle ID %d fwdinfo state %s != expected QUEUED", bundle.bundleid(), fwdinfo.state().toString())); } /* * "Update the forwarding log indicating that the bundle is no longer in * flight."[DTN2] */ Log.d(TAG, String.format("updating forwarding log entry on bundle id %d for link %s to TRANSMITTED", bundle.bundleid(), link.name())); bundle.fwdlog().update(link, ForwardingInfo.state_t.TRANSMITTED); DTNManager.getInstance().notify_user("DTN Bundle Transmitted", "To " + bundle.dest().toString()); /* * "Remove the formatted block info from the bundle since we don't need * it any more." [DTN2] */ Log.d(TAG, String.format("trying to delete xmit blocks for bundle id:%d on link %s", bundle.bundleid(), link.name())); BundleProtocol.delete_blocks(bundle, link); blocks = null; /* * "Generate the forwarding status report if requested" [DTN2] */ if (bundle.forward_rcpt()) { generate_status_report(bundle, BundleStatusReport.flag_t.STATUS_FORWARDED, BundleProtocol.status_report_reason_t.REASON_NO_ADDTL_INFO); } /* * "Schedule a custody timer if we have custody.} [DTN2 */ if (bundle.local_custody()) { bundle.custody_timers() .add(new CustodyTimer(fwdinfo.timestamp(), fwdinfo.custody_spec(), bundle, link)); } } protected void handle_cla_parameters_query(CLAParametersQueryRequest request) { assert (request.cla() != null) : "BundleDaemon:handle_cla_parameters_query, CLayer is null"; Log.e(TAG, String.format("BundleDaemon::handle_cla_parameters_query: " + "query %s, convergence layer %s", request.query_id(), request.cla().name())); request.cla().query_cla_parameters(request.query_id(), request.parameter_names()); } protected void handle_cla_parameters_report(CLAParametersReportEvent event) { Log.e(TAG, String.format("Bundledaemon::handle_cla_parameters_report: query %s", event.query_id())); } protected void handle_cla_params_set(CLAParamsSetEvent event) { } protected void handle_cla_set_params(CLASetParamsRequest request) { assert (request.cla() != null) : "BundleDaemon:handle_cla_set_params, cla is null"; request.cla().set_cla_parameters(request.parameters()); } protected void handle_contact_attribute_changed(ContactAttributeChangedEvent event) { } protected void handle_contact_down(ContactDownEvent event) { Contact contact = event.contact(); Link link = contact.link(); assert (link != null); Log.i(TAG, String.format("CONTACT_DOWN %s (%s) (contact %s)", link.name(), event.reason().getCaption(), contact.toString())); // update the link stats , in seconds link.stats().set_uptime(link.stats().uptime() + (TimeHelper.elapsed_ms(contact.start_time()) / 1000)); //// DELETING XXX NODE // Log.i(TAG, String.format("LINK_DELETE %s", link.name())); // if (!link.isdeleted()) { // contactmgr_.del_link(link, false, reason_t.NO_INFO); // } //contactmgr_.de } protected void handle_contact_query(ContactQueryRequest event) { post_at_head(new ContactReportEvent()); } protected void handle_contact_report(ContactReportEvent event) { } private void forwardMultiHop(String link) { try { // Cursor cursor = MultiHopStorage.getInstance().impt_sqlite_().get_records("bundle", "destination = '" + link+"/"+"'"); Cursor cursor = MultiHopStorage.getInstance().impt_sqlite_().get_records("bundle", null); if (link.charAt(link.length() - 1) != '/') link += "/"; String expiredBundlesId = ""; int currentTime = (int) TimeHelper.current_seconds_from_ref(); int bundle_id_col = cursor.getColumnIndex("bundle_id"); int bundle_source_col = cursor.getColumnIndex("source"); int bundle_destination_col = cursor.getColumnIndex("destination"); int bundle_message_col = cursor.getColumnIndex("msg"); //int bundle_life_col = cursor.getColumnIndex("life"); if (cursor != null) { if (cursor.moveToFirst()) { do { String message = cursor.getString(bundle_message_col); String dest = cursor.getString(bundle_destination_col); String bundle_id = cursor.getString(bundle_id_col); String bundle_source = cursor.getString(bundle_source_col); // int life = cursor.getInt(bundle_life_col); // if(currentTime >= life) // { // if(expiredBundlesId.length()!=0) // expiredBundlesId+= " or "; // expiredBundlesId+="bundle_id ="+bundle_id; // } if (MultiHopStorage.getInstance().impt_sqlite_() .get_records("Forwards", "bundle_id = " + bundle_id + " and destination = '" + link + "'", "id") .size() == 0) { //String message = cursor.getString(bundle_message_col); //Toast.makeText(,"MSG FOR : " +dest+" | "+message,Toast.LENGTH_LONG).show(); Log.d(TAG, "MSG FOR : " + dest + " | " + message); //list.add(cursor.getInt(idColumn)); if (dest != link && !message.contains(" ,")) message = message + " ," + bundle_id; // m.sendMessage(message,dest); // MultiHopForwarding.pendings.add(new BasicNameValuePair(dest, message)); MultiHopStorage.getInstance().add(Integer.parseInt(bundle_id), link); android.os.Bundle b = new android.os.Bundle(); b.putString("dest", link); b.putString("id", bundle_id); b.putString("msg", message); b.putString("act", dest); b.putString("source", bundle_source); MultiHopForwarding.pendings.add(b); //Delete Msg From Pending Bundles if (dest.equals(link)) MultiHopStorage.getInstance().del(cursor.getInt(bundle_id_col)); } } while (cursor.moveToNext()); MultiHopForwarding m = new MultiHopForwarding(DTNManager.getInstance().getApplicationContext()); //m.unbindDTNService(); } } else { Log.d(TAG, "Row not found!"); } cursor.close(); // MultiHopStorage.getInstance().delete(expiredBundlesId); } catch (IndexOutOfBoundsException e) { Log.e(TAG, "Id Already deleted"); } catch (SQLiteException e) { Log.e(TAG, "Coundn't run the query"); } catch (Exception e) { Log.e(TAG, "General Exception"); } } protected void handle_contact_up(ContactUpEvent event) { Contact contact = event.contact(); Link link = contact.link(); assert (link != null); forwardMultiHop(link.remote_eid().toString()); if (link.isdeleted()) { Log.e(TAG, String.format( "BundleDaemon::handle_contact_up: " + "cannot bring contact up on deleted link %s", link.name())); event.set_daemon_only(true); return; } Log.d("TAG", "Link ID" + link.remote_eid()); // "ignore stale notifications that an old contact is up" [DTN2] contactmgr_.get_lock().lock(); try { //XXX/ this was false so the contact status was not set to true if (link.contact() != contact) { Log.i(TAG, String.format("CONTACT_UP %s (contact %s) being ignored (old contact)", link.name(), contact.toString())); return; } Log.i(TAG, String.format("CONTACT_UP %s (contact %s)", link.name(), contact.toString())); link.set_state(Link.state_t.OPEN); link.stats_.set_contacts(link.stats_.contacts() + 1); } finally { contactmgr_.get_lock().unlock(); } } protected void handle_custody_signal(CustodySignalEvent event) { Log.i(TAG, String.format("CUSTODY_SIGNAL: %s %d.%d %s (%s)", event.data().orig_source_eid().toString(), event.data().orig_creation_tv().seconds(), event.data().orig_creation_tv().seqno(), event.data().succeeded() ? "succeeded" : "failed", event.data().reason().getCaption())); GbofId gbof_id = new GbofId(); gbof_id.source_.assign(event.data().orig_source_eid()); gbof_id.creation_ts_ = event.data().orig_creation_tv(); gbof_id.is_fragment_ = (event.data().admin_flags() & BundleProtocol.admin_record_flags_t.ADMIN_IS_FRAGMENT.getCode()) > 0; gbof_id.frag_length_ = gbof_id.is_fragment() ? event.data().orig_frag_length() : 0; gbof_id.frag_offset_ = gbof_id.is_fragment_ ? event.data().orig_frag_offset() : 0; Bundle orig_bundle = custody_bundles_.find(gbof_id); if (orig_bundle == null) { Log.w(TAG, String.format("received custody signal for bundle %s %d.%d " + "but don't have custody", event.data().orig_source_eid().toString(), event.data().orig_creation_tv().seconds(), event.data().orig_creation_tv().seqno())); return; } // "release custody if either the signal succeded or if it // (paradoxically) failed due to duplicate transmission" [DTN2] boolean release = event.data().succeeded(); if ((event.data().succeeded() == false) && (event.data().reason() == BundleProtocol.custody_signal_reason_t.CUSTODY_REDUNDANT_RECEPTION)) { Log.i(TAG, String.format("releasing custody for bundle %s %d.%d " + "due to redundant reception", event.data().orig_source_eid().toString(), event.data().orig_creation_tv().seconds(), event.data().orig_creation_tv().seqno())); release = true; } if (release) { release_custody(orig_bundle); try_to_delete(orig_bundle); } } protected void handle_custody_timeout(CustodyTimeoutEvent event) { Bundle bundle = event.bundle(); Link link = event.link(); assert (link != null) : "BundleDaemon, handle_custody_timeout link is null"; Log.i(TAG, String.format("CUSTODY_TIMEOUT bundle %d, on link %s", bundle.bundleid(), link.name())); // "remove and delete the expired timer from the bundle" [DTN2] bundle.get_lock().lock(); try { boolean found = false; CustodyTimer timer = null; Iterator<CustodyTimer> iter = bundle.custody_timers().iterator(); while (iter.hasNext()) { timer = iter.next(); if (timer.link().equals(link)) { if (timer.pending()) { Log.e("multiple pending custody timers for link %s", link.nexthop()); continue; } found = true; bundle.custody_timers().remove(timer); break; } } if (!found) { Log.e(TAG, String.format("custody timeout for bundle %d on link %s: timer not found in bundle list", bundle.bundleid(), link.name())); return; } assert (!timer.cancelled()) : "Bundled Timer:handle_custody_timout, timer is cancelled"; if (!pending_bundles_.contains(bundle)) { Log.e(TAG, String.format("custody timeout for bundle %d, on link %s: bundle not in pending list", bundle.bundleid(), link.name())); } // "modify the TRANSMITTED entry in the forwarding log to indicate // that we got a custody timeout. then when the routers go through // to figure out whether the bundle needs to be re-sent, the // TRANSMITTED entry is no longer in there" [DTN2] boolean ok = bundle.fwdlog().update(link, ForwardingInfo.state_t.CUSTODY_TIMEOUT); if (!ok) { Log.e(TAG, String.format("custody timeout can't find ForwardingLog entry for link %s", link.name())); } } finally { bundle.get_lock().unlock(); } // "now fall through to let the router handle the event, typically // triggering a retransmission to the link in the event" [DTN2] } protected void handle_eid_reachable_query(EIDReachableQueryRequest request) { Interface iface = request.iface(); assert (iface != null) : "BundleDaemon:handle_eid_reachable_query, iface is null"; assert (iface.clayer() != null) : "BundleDaemon:handle_eid_reachable_query, clayer is null"; Log.e(TAG, String.format( "BundleDaemon::handle_eid_reachable_query: query %s, " + "checking if endpoint %s is reachable via interface %s", request.query_id(), request.endpoint().toString(), iface.name())); iface.clayer().is_eid_reachable(request.query_id(), iface, request.endpoint()); } protected void handle_eid_reachable_report(EIDReachableReportEvent event) { Log.e(TAG, String.format("BundleDaemon::handle_eid_reachable_report: query %s, %s", event.query_id(), event.is_reachable() ? "true" : "false")); } protected void handle_iface_attributes_query(IfaceAttributesQueryRequest request) { Interface iface = request.iface(); assert (iface != null) : "BundleDaemon:handle_iface_attributes_query, iface is null"; assert (iface.clayer() != null) : "BundleDaemon:handle_iface_attributes_query, clayer is null"; Log.e(TAG, String.format("BundleDaemon::handle_iface_attributes_query: " + "query %s, interface %s", request.query_id(), iface.name())); iface.clayer().query_iface_attributes(request.query_id(), iface, request.attribute_names()); } protected void handle_iface_attributes_report(IfaceAttributesReportEvent event) { Log.e(TAG, String.format("BundleDaemon::handle_iface_attributes_report: query %s", event.query_id().toString())); } protected void handle_link_attribute_changed(LinkAttributeChangedEvent event) { Link link = event.link(); if (link.isdeleted()) { Log.e(TAG, String.format("BundleDaemon::handle_link_attribute_changed: " + "link %s deleted", link.name())); event.set_daemon_only(true); return; } // "Update any state as necessary" [DTN2] Iterator<NamedAttribute> iter = event.attributes().iterator(); while (iter.hasNext()) { NamedAttribute atr = iter.next(); if (atr.name().equals("nexthop")) { link.set_nexthop(atr.string_val()); } else if (atr.name() == "how_reliable") { link.stats().set_reliability(atr.int_val()); } else if (atr.name() == "how_available") { link.stats().set_availability(atr.int_val()); } } Log.i("LINK_ATTRIB_CHANGED %s", link.name()); } protected void handle_link_attributes_query(LinkAttributesQueryRequest request) { Link link = request.link(); assert (link != null) : "BundleDaemon:handle_link_attributes_query, link is null"; assert (link.clayer() != null) : "BundleDaemon:handle_link_attributes_query, CLayer is null"; Log.e(TAG, String.format("BundleDaemon::handle_link_attributes_query: query %s, link %s", request.query_id(), link.name())); link.clayer().query_link_attributes(request.query_id(), link, request.attribute_names()); } protected void handle_link_attributes_report(LinkAttributesReportEvent event) { Log.e(TAG, String.format("BundleDaemon::handle_link_attributes_report: query %s", event.query_id())); } protected void handle_link_available(LinkAvailableEvent event) { Link link = event.link(); assert (link != null); assert (link.isNotUnavailable()); if (link.isdeleted()) { Log.w(TAG, String.format("BundleDaemon::handle_link_available: " + "link %s already deleted", link.name())); event.set_daemon_only(true); return; } Log.i(TAG, String.format("LINK_AVAILABLE %s", link.name())); } protected void handle_link_created(LinkCreatedEvent event) { Link link = event.link(); assert (link != null); if (link.isdeleted()) { Log.w("BundleDaemon::handle_link_created: " + "link %s deleted prior to full creation", link.name()); event.set_daemon_only(true); return; } Log.i(TAG, String.format("LINK_CREATED %s", link.name())); } protected void handle_link_delete(LinkDeleteRequest request) { Link link = request.link(); assert (link != null); Log.i(TAG, String.format("LINK_DELETE %s", link.name())); if (!link.isdeleted()) { contactmgr_.del_link(link, false, reason_t.NO_INFO); } } protected void handle_link_deleted(LinkDeletedEvent event) { Link link = event.link(); assert (link != null); Log.i(TAG, String.format("LINK_DELETED %s", link.name())); } protected void handle_link_query(LinkQueryRequest event) { post_at_head(new LinkReportEvent()); } protected void handle_link_reconfigure(LinkReconfigureRequest request) { Link link = request.link(); assert (link != null); link.reconfigure_link(request.parameters()); Log.i(TAG, String.format("LINK_RECONFIGURE %s", link.name())); } protected void handle_link_report(LinkReportEvent event) { } protected void handle_link_state_change_request(LinkStateChangeRequest request) { Link link = request.link(); if (link == null) { Log.w(TAG, "LINK_STATE_CHANGE_REQUEST received invalid link"); return; } Link.state_t new_state = request.state(); Link.state_t old_state = request.old_state(); reason_t reason = request.reason(); Log.d(TAG, "HANDLE link state change request from " + old_state.toString() + " to " + new_state.toString()); if (link.isdeleted() && new_state != Link.state_t.CLOSED) { Log.w(TAG, String.format( "BundleDaemon::handle_link_state_change_request: " + "link %s already deleted; cannot change link state to %s", link.name(), new_state.toString())); return; } if (request.contact() != null && link.contact() != null) if (!link.contact().equals(request.contact())) { Log.w(TAG, String.format( "stale LINK_STATE_CHANGE_REQUEST [%s -> %s] (%s) for " + "link %s: contact %s != current contact %s", old_state.toString(), new_state.toString(), reason.toString(), link.name(), request.contact().toString(), link.contact().toString())); return; } Log.i(TAG, String.format("LINK_STATE_CHANGE_REQUEST [%s -> %s] (%s) for link %s", old_state.toString(), new_state.toString(), reason.toString(), link.name())); // "avoid a race condition caused by opening a partially closed link" [DTN2] contactmgr_.get_lock().lock(); try { switch (new_state) { case UNAVAILABLE: if (link.state() != Link.state_t.AVAILABLE) { Log.e(TAG, String.format( "LINK_STATE_CHANGE_REQUEST %s: " + "tried to set state UNAVAILABLE in state %s", link.name(), link.state().toString())); return; } link.set_state(new_state); post_at_head(new LinkUnavailableEvent(link, reason)); break; case AVAILABLE: if (link.state() == Link.state_t.UNAVAILABLE) { link.set_state(Link.state_t.AVAILABLE); } else { Log.e(TAG, String.format( "LINK_STATE_CHANGE_REQUEST %s: " + "tried to set state AVAILABLE in state %s", link.name(), link.state().toString())); return; } post_at_head(new LinkAvailableEvent(link, reason)); break; case OPENING: case OPEN: // force the link to be available, since someone really wants it // open if (link.state() == Link.state_t.UNAVAILABLE) { link.set_state(Link.state_t.AVAILABLE); } actions_.open_link(link); break; case CLOSED: // If the link is open (not OPENING), we need a ContactDownEvent if (link.isopen()) { assert (link.contact() != null); post_at_head(new ContactDownEvent(link.contact(), reason)); } // close the link actions_.close_link(link); if (!link.isdeleted()) { Log.d(TAG, "posting link unavailable event for link " + link.name()); link.set_state(Link.state_t.UNAVAILABLE); post_at_head(new LinkUnavailableEvent(link, reason)); } break; default: Log.e(TAG, String.format("unhandled state %s", new_state.toString())); } } finally { contactmgr_.get_lock().unlock(); } } protected void handle_link_unavailable(LinkUnavailableEvent event) { Link link = event.link(); assert (link != null); assert (!link.isNotUnavailable()); Log.i("LINK UNAVAILABLE %s", link.name()); } protected void handle_new_eid_reachable(NewEIDReachableEvent event) { } protected void handle_reassembly_completed(ReassemblyCompletedEvent event) { Log.i(TAG, String.format("REASSEMBLY_COMPLETED bundle id %d", event.bundle().bundleid())); // "remove all the fragments from the pending list" [DTN2] event.fragments().get_lock().lock(); try { ListIterator<Bundle> itr = event.fragments().begin(); while (itr.hasNext()) { Bundle fragment = itr.next(); delete_bundle(fragment, BundleProtocol.status_report_reason_t.REASON_NO_ADDTL_INFO); } } catch (BundleListLockNotHoldByCurrentThread e) { Log.e(TAG, "BundleDaemon:handle_reassembly_completed, get iterator of fragments while not getting lock"); } finally { event.fragments().get_lock().unlock(); } // "post a new event for the newly reassembled bundle" [DTN2] post_at_head(new BundleReceivedEvent(event.bundle(), event_source_t.EVENTSRC_FRAGMENTATION)); } protected void handle_registration_added(RegistrationAddedEvent event) { Registration registration = event.registration(); Log.i(TAG, String.format("REGISTRATION_ADDED %d %s", registration.regid(), registration.endpoint().toString())); if (!reg_table_.add(registration, (event.source() == event_source_t.EVENTSRC_APP) ? true : false)) { Log.e(TAG, String.format("error adding registration %d to table", registration.regid())); } pending_bundles_.get_lock().lock(); try { ListIterator<Bundle> iter = pending_bundles_.begin(); while (iter.hasNext()) { Bundle bundle = iter.next(); if (!bundle.is_fragment() && registration.endpoint().match(bundle.dest())) { deliver_to_registration(bundle, registration); } } } catch (BundleListLockNotHoldByCurrentThread e) { Log.e(TAG, "BundleDaemon:handle_registration_added, get pending bundles iterator while not getting lock"); } finally { pending_bundles_.get_lock().unlock(); } } protected void handle_registration_delete(RegistrationDeleteRequest request) { Log.i(TAG, String.format("REGISTRATION_DELETE %d", request.registration().regid())); } protected void handle_registration_expired(RegistrationExpiredEvent event) { Registration registration = event.registration(); if (reg_table_.get(registration.regid()) == null) { // this shouldn't ever happen Log.e(TAG, String.format("REGISTRATION_EXPIRED -- dead regid %d", registration.regid())); return; } registration.set_expired(true); if (registration.active()) { // "if the registration is currently active (i.e. has a // binding), we wait for the binding to clear, which will then // clean up the registration"" [DTN2] Log.i(TAG, String.format("REGISTRATION_EXPIRED %d -- deferred until binding clears", registration.regid())); } else { // "otherwise remove the registration from the table" [DTN2] Log.i(TAG, String.format("REGISTRATION_EXPIRED %d", registration.regid())); reg_table_.del(registration.regid()); post_at_head(new RegistrationDeleteRequest(registration)); } } protected void handle_registration_removed(RegistrationRemovedEvent event) { Registration registration = event.registration(); Log.i(TAG, String.format("REGISTRATION_REMOVED %d %s", registration.regid(), registration.endpoint().toString())); if (!reg_table_.del(registration.regid())) { Log.e(TAG, String.format("error removing registration %d from table", registration.regid())); return; } post(new RegistrationDeleteRequest(registration)); } protected void handle_route_add(RouteAddEvent event) { Log.i(TAG, String.format("ROUTE_ADD %s", event.entry())); } protected void handle_route_del(RouteDelEvent event) { Log.i(TAG, String.format("ROUTE_DEL %s", event.dest().toString())); } protected void handle_route_query(RouteQueryRequest event) { post_at_head(new RouteReportEvent()); } protected void handle_route_report(RouteReportEvent event) { } protected void handle_set_link_defaults(SetLinkDefaultsRequest event) { } protected void handle_shutdown_request(ShutdownRequest event) { // "Signal the main to bail out" [DTN2] shutting_down_ = true; Log.i(TAG, "BundleDeamon: Received Shutdown Request"); contactmgr_.get_lock().lock(); try { LinkSet links = contactmgr_.links(); Iterator<Link> itr = links.iterator(); while (itr.hasNext()) { Link link = itr.next(); Log.d(TAG, String.format("Shutdown: checking whether link is opened before closing link %s \n", link.name())); //XXX/KLA this one was false if (link.isopen()) { Log.d(TAG, String.format("Shutdown: closing link %s \n", link.name())); link.close(); } } // "Shutdown all actively registered convergence layers." [DTN2] ConvergenceLayer.shutdown_clayers(); // "call the rtr shutdown procedure" [DTN2] if (rtr_shutdown_proc_ != null) { rtr_shutdown_proc_.action(rtr_shutdown_data_); } // "call the app shutdown procedure" [DTN2] if (app_shutdown_proc_ != null) { app_shutdown_proc_.action(app_shutdown_data_); } thread_ = null; eventq_.clear(); // "fall through -- the DTNServer will close and flush all the data // stores" [DTN2] instance_ = null; } finally { contactmgr_.get_lock().unlock(); } } protected void handle_status_request(StatusRequest event) { Log.i(TAG, "Received status request"); } /** * "Initialize and load in stored bundles." [DTN2] */ protected void load_bundles() { Iterator<Bundle> iter = BundleStore.getInstance().new_iterator(); Log.i(TAG, "BundleDaemon loading bundles from data store"); List<Bundle> tobe_deleted_bundles = new List<Bundle>(); while (iter.hasNext()) { Bundle bundle = iter.next(); // "if the bundle payload file is missing, we need to kill the // bundle, but we can't do so while holding the durable // iterator or it may deadlock, so cleanup is deferred" [DTN2] if (bundle.payload().location() != BundlePayload.location_t.DISK) { Log.e(TAG, String.format("error loading payload for bundle %d from data store", bundle.bundleid())); tobe_deleted_bundles.add(bundle); continue; } BundleProtocol.reload_post_process(bundle); BundleReceivedEvent event = new BundleReceivedEvent(bundle, event_source_t.EVENTSRC_STORE); post_event(event, true); //handle_event(event); } Iterator<Bundle> delete_itr = tobe_deleted_bundles.iterator(); while (delete_itr.hasNext()) { Bundle bundle = delete_itr.next(); actions_.store_del(bundle); } } /** * "Initialize and load in the registrations." [DTN2] */ protected void load_registrations() { admin_reg_ = new AdminRegistration(); { RegistrationAddedEvent event = new RegistrationAddedEvent(admin_reg_, event_source_t.EVENTSRC_ADMIN); admin_reg_.endpoint().assign(local_eid_); handle_event(event); } EndpointID ping_eid = new EndpointID(local_eid()); boolean ok = ping_eid.append_service_tag("ping"); if (!ok) { Log.e(TAG, String.format("local eid (%s) scheme must be able to append service tags", local_eid().toString())); } ping_reg_ = new PingRegistration(ping_eid); { RegistrationAddedEvent event = new RegistrationAddedEvent(ping_reg_, event_source_t.EVENTSRC_ADMIN); handle_event(event); } EndpointID prophet_eid = new EndpointID(local_eid()); ok = prophet_eid.append_service_tag("prophet"); if (!ok) { Log.e(TAG, String.format("prophet local eid (%s) scheme must be able to append service tags", local_eid().toString())); } if (BundleRouter.config().type() == router_type_t.PROPHET_BUNDLE_ROUTER) { RegistrationAddedEvent event = new RegistrationAddedEvent(router_.getProphetRegistration(), event_source_t.EVENTSRC_ADMIN); handle_event(event); } Iterator<Registration> iter = RegistrationStore.getInstance().new_iterator(); while (iter.hasNext()) { Registration reg = iter.next(); if (reg == null) { Log.e(TAG, String.format("error loading registration from data store")); continue; } RegistrationAddedEvent event = new RegistrationAddedEvent(reg, event_source_t.EVENTSRC_STORE); handle_event(event); } } /** * "Release custody of the given bundle, sending the appropriate signal to * the current custodian." [DTN2] */ protected void release_custody(Bundle bundle) { Log.i(TAG, String.format("release_custody bundle id %d", bundle.bundleid())); if (!bundle.local_custody()) { Log.e(TAG, String.format("release_custody(bundle id %d): don't have local custody", bundle.bundleid())); return; } cancel_custody_timers(bundle); bundle.custodian().assign(EndpointID.NULL_EID()); bundle.set_local_custody(false); bundle.set_complete(true); actions_.store_update(bundle); custody_bundles_.erase(bundle, false); } /** * "Check if we should delete this bundle, called just after arrival, once * it's been transmitted or delivered at least once, or when we release * custody." [DTN2] */ protected boolean try_to_delete(final Bundle bundle) { /* * "Check to see if we should remove the bundle from the system. * * If we're not configured for early deletion, this never does anything. * Otherwise it relies on the router saying that the bundle can be * deleted." [DTN2] */ Log.d(TAG, String.format("pending_bundles size %d", pending_bundles_.size())); if (!bundle.is_queued_on(pending_bundles_)) { if (bundle.expired()) { Log.d(TAG, String.format("try_to_delete( bundle id %d): bundle already expired", bundle.bundleid())); return false; } Log.e(TAG, String.format("try_to_delete( bundle id %d): bundle not in pending list!", bundle.bundleid())); return false; } if (!params_.early_deletion_) { Log.d(TAG, String.format("try_to_delete( bundle id %d): not deleting because " + "early deletion disabled", bundle.bundleid())); return false; } if (!router_.can_delete_bundle(bundle)) { Log.d(TAG, String.format( "try_to_delete( bundle id %d): not deleting because " + "router wants to keep bundle", bundle.bundleid())); return false; } return delete_bundle(bundle, BundleProtocol.status_report_reason_t.REASON_NO_ADDTL_INFO); } }