/** "Remove matching deferred transmission entries." [DTN2] */ void remove_from_deferred(final Bundle bundle, int actions) { ContactManager cm = BundleDaemon.getInstance().contactmgr(); cm.get_lock().lock(); try { final LinkSet links = cm.links(); Iterator<Link> iter = links.iterator(); while (iter.hasNext()) { Link link = iter.next(); // "a bundle might be deleted immediately after being loaded // from storage, meaning that remove_from_deferred is called // before the deferred list is created (since the link isn't // fully set up yet). so just skip the link if there's no // router info, and therefore no deferred list" [DTN2] if (link.router_info() == null) { continue; } DeferredList deferred = deferred_list(link); ForwardingInfo info = deferred.find(bundle); if (info != null) { if ((info.action().getCode() & actions) > 0) { Log.d( TAG, String.format("removing bundle %s from link %s deferred list", bundle, link)); deferred.del(bundle); } } } } finally { cm.get_lock().unlock(); } }
/** * "Called when the next hop link is available for transmission (i.e. either when it first arrives * and the contact is brought up or when a bundle is completed and it's no longer busy). * * <p>Loops through the bundle list and calls fwd_to_matching on all bundles." [DTN2] */ protected void check_next_hop(Link next_hop) { // "if the link isn't open, there's nothing to do now" [DTN2] if (!next_hop.isopen()) { Log.d( TAG, String.format( "check_next_hop %s -> %s: link not open...", next_hop.name(), next_hop.nexthop())); return; } // "if the link queue doesn't have space (based on the low water // mark) don't do anything" [DTN2] if (!next_hop.queue_has_space()) { Log.d( TAG, String.format( "check_next_hop %s -> %s: no space in queue...", next_hop.name(), next_hop.nexthop())); return; } Log.d( TAG, String.format( "check_next_hop %s -> %s: checking deferred bundle list...", next_hop.name(), next_hop.nexthop())); // "because the loop below will remove the current bundle from // the deferred list, invalidating any iterators pointing to its // position, make sure to advance the iterator before processing // the current bundle" [DTN2] DeferredList deferred = deferred_list(next_hop); deferred.list().get_lock().lock(); try { Iterator<Bundle> iter = deferred.list().begin(); while (iter.hasNext()) { if (next_hop.queue_is_full()) { Log.d( TAG, String.format( "check_next_hop %s: link queue is full, stopping loop", next_hop.name())); break; } Bundle bundle = iter.next(); ForwardingInfo info = deferred.find(bundle); assert info != null : "TableBasedRouter: check_next_hop, ForwardingInfo regarding Bundle is null"; // "if should_fwd returns false, then the bundle was either // already transmitted or is in flight on another node. since // it's possible that one of the other transmissions will // fail, we leave it on the deferred list for now, relying on // the transmitted handlers to clean up the state" [DTN2] if (!this.should_fwd(bundle, next_hop, info.action())) { Log.d(TAG, String.format("check_next_hop: not forwarding to link %s", next_hop.name())); continue; } // "if the link is available and not open, open it" [DTN2] if (next_hop.isNotUnavailable() && (!next_hop.isopen()) && (!next_hop.isopening())) { Log.d( TAG, String.format( "check_next_hop: " + "opening %s because a message is intended for it", next_hop.name())); actions_.open_link(next_hop); } // "remove the bundle from the deferred list" [DTN2] Log.d( TAG, String.format( "check_next_hop: sending bundle %d to %s", bundle.bundleid(), next_hop.name())); iter.remove(); actions_.queue_bundle(bundle, next_hop, info.action(), info.custody_spec()); } } catch (BundleListLockNotHoldByCurrentThread e) { Log.e(TAG, "Table Based Router " + e.toString()); } finally { deferred.list().get_lock().unlock(); } }