
net.named_data.jndn.Node Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jndn-android-with-async-io Show documentation
Show all versions of jndn-android-with-async-io Show documentation
jNDN is a new implementation of a Named Data Networking client library written in Java. It is wire format compatible with the new NDN-TLV encoding, with NDNx and PARC's CCNx.
/**
* Copyright (C) 2014-2017 Regents of the University of California.
* @author: Jeff Thompson
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
* A copy of the GNU Lesser General Public License is in the file COPYING.
*/
package net.named_data.jndn;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.named_data.jndn.encoding.ElementListener;
import net.named_data.jndn.encoding.EncodingException;
import net.named_data.jndn.encoding.TlvWireFormat;
import net.named_data.jndn.encoding.WireFormat;
import net.named_data.jndn.encoding.tlv.Tlv;
import net.named_data.jndn.encoding.tlv.TlvDecoder;
import net.named_data.jndn.impl.DelayedCallTable;
import net.named_data.jndn.impl.InterestFilterTable;
import net.named_data.jndn.impl.PendingInterestTable;
import net.named_data.jndn.impl.RegisteredPrefixTable;
import net.named_data.jndn.lp.LpPacket;
import net.named_data.jndn.security.KeyChain;
import net.named_data.jndn.security.SecurityException;
import net.named_data.jndn.transport.Transport;
import net.named_data.jndn.util.Blob;
import net.named_data.jndn.util.CommandInterestGenerator;
import net.named_data.jndn.util.Common;
/**
* The Node class implements internal functionality for the Face class.
*/
public class Node implements ElementListener {
/**
* Create a new Node for communication with an NDN hub with the given
* Transport object and connectionInfo.
* @param transport A Transport object used for communication.
* @param connectionInfo A Transport.ConnectionInfo to be used to connect to
* the transport.
*/
public Node(Transport transport, Transport.ConnectionInfo connectionInfo)
{
transport_ = transport;
connectionInfo_ = connectionInfo;
}
/**
* Send the Interest through the transport, read the entire response and call
* onData, onTimeout or onNetworkNack as described below.
* @param pendingInterestId The getNextEntryId() for the pending interest ID
* which Face got so it could return it to the caller.
* @param interestCopy The Interest which is NOT copied for this internal Node
* method. The Face expressInterest is responsible for making a copy for Node
* to use.
* @param onData When a matching data packet is received, this calls
* onData.onData(interest, data) where interest is the interest given to
* expressInterest and data is the received Data object.
* @param onTimeout If the interest times out according to the interest
* lifetime, this calls onTimeout.onTimeout(interest) where interest is the
* interest given to expressInterest. If onTimeout is null, this does not use
* it.
* @param onNetworkNack When a network Nack packet for the interest is
* received and onNetworkNack is not null, this calls
* onNetworkNack.onNetworkNack(interest, networkNack) and does not call
* onTimeout. However, if a network Nack is received and onNetworkNack is null,
* do nothing and wait for the interest to time out.
* @param wireFormat A WireFormat object used to encode the message.
* @param face The face which has the callLater method, used for interest
* timeouts. The callLater method may be overridden in a subclass of Face.
* @throws IOException For I/O error in sending the interest.
* @throws Error If the encoded interest size exceeds getMaxNdnPacketSize().
*/
public final void
expressInterest
(final long pendingInterestId, final Interest interestCopy, final OnData onData,
final OnTimeout onTimeout, final OnNetworkNack onNetworkNack,
final WireFormat wireFormat, final Face face)
throws IOException
{
// Set the nonce in our copy of the Interest so it is saved in the PIT.
interestCopy.setNonce(nonceTemplate_);
interestCopy.refreshNonce();
if (connectStatus_ == ConnectStatus.CONNECT_COMPLETE) {
// We are connected. Simply send the interest without synchronizing.
expressInterestHelper
(pendingInterestId, interestCopy, onData, onTimeout, onNetworkNack,
wireFormat, face);
return;
}
// Wile connecting, use onConnectedCallbacks_ to synchronize
// onConnectedCallbacks_ as well as connectStatus_.
synchronized(onConnectedCallbacks_) {
// TODO: Properly check if we are already connected to the expected host.
if (!transport_.isAsync()) {
// The simple case: Just do a blocking connect and express.
transport_.connect(connectionInfo_, this, null);
expressInterestHelper
(pendingInterestId, interestCopy, onData, onTimeout, onNetworkNack,
wireFormat, face);
// Make future calls to expressInterest send directly to the Transport.
connectStatus_ = ConnectStatus.CONNECT_COMPLETE;
return;
}
// Handle the async case.
if (connectStatus_ == ConnectStatus.UNCONNECTED) {
connectStatus_ = ConnectStatus.CONNECT_REQUESTED;
// expressInterestHelper will be called by onConnected.
onConnectedCallbacks_.add(new Runnable() {
public void run() {
try {
expressInterestHelper
(pendingInterestId, interestCopy, onData, onTimeout,
onNetworkNack, wireFormat, face);
} catch (IOException ex) {
logger_.log(Level.SEVERE, null, ex);
}
}
});
Runnable onConnected = new Runnable() {
public void run() {
// This is called on a separate thread from the surrounding code
// when connected, so synchronize again.
synchronized(onConnectedCallbacks_) {
// Call each callback added while the connection was opening.
for (int i = 0; i < onConnectedCallbacks_.size(); ++i)
((Runnable)onConnectedCallbacks_.get(i)).run();
onConnectedCallbacks_.clear();
// Make future calls to expressInterest send directly to the
// Transport.
connectStatus_ = ConnectStatus.CONNECT_COMPLETE;
}
}
};
transport_.connect(connectionInfo_, this, onConnected);
}
else if (connectStatus_ == ConnectStatus.CONNECT_REQUESTED) {
// Still connecting. add to the interests to express by onConnected.
onConnectedCallbacks_.add(new Runnable() {
public void run() {
try {
expressInterestHelper
(pendingInterestId, interestCopy, onData, onTimeout,
onNetworkNack, wireFormat, face);
} catch (IOException ex) {
logger_.log(Level.SEVERE, null, ex);
}
}
});
}
else if (connectStatus_ == ConnectStatus.CONNECT_COMPLETE)
// We have to repeat this check for CONNECT_COMPLETE in case the
// onConnected callback was called while we were waiting to enter this
// synchronized block.
expressInterestHelper
(pendingInterestId, interestCopy, onData, onTimeout, onNetworkNack,
wireFormat, face);
else
// Don't expect this to happen.
throw new Error
("Node: Unrecognized _connectStatus " + connectStatus_);
}
}
/**
* Remove the pending interest entry with the pendingInterestId from the
* pending interest table. This does not affect another pending interest with
* a different pendingInterestId, even if it has the same interest name.
* If there is no entry with the pendingInterestId, do nothing.
* @param pendingInterestId The ID returned from expressInterest.
*/
public final void
removePendingInterest(long pendingInterestId)
{
pendingInterestTable_.removePendingInterest(pendingInterestId);
}
/**
* Append a timestamp component and a random value component to interest's
* name. Then use the keyChain and certificateName to sign the interest. If
* the interest lifetime is not set, this sets it.
* @param interest The interest whose name is append with components.
* @param keyChain The KeyChain object for signing interests.
* @param certificateName The certificate name for signing interests.
* @param wireFormat A WireFormat object used to encode the SignatureInfo and
* to encode interest name for signing.
* @throws SecurityException If cannot find the private key for the
* certificateName.
*/
void
makeCommandInterest
(Interest interest, KeyChain keyChain, Name certificateName,
WireFormat wireFormat) throws SecurityException
{
commandInterestGenerator_.generate
(interest, keyChain, certificateName, wireFormat);
}
/**
* Register prefix with the connected NDN hub and call onInterest when a
* matching interest is received. To register a prefix with NFD, you must
* first call setCommandSigningInfo.
* @param registeredPrefixId The getNextEntryId() for the registered prefix ID
* which Face got so it could return it to the caller.
* @param prefix A Name for the prefix to register. This copies the Name.
* @param onInterest If not null, this creates an interest filter from prefix
* so that when an Interest is received which matches the filter, this calls
* onInterest.onInterest(prefix, interest, face, interestFilterId, filter).
* If onInterest is null, it is ignored and you must call setInterestFilter.
* @param onRegisterFailed This calls onRegisterFailed.onRegisterFailed(prefix)
* if failed to retrieve the connected hub's ID or failed to register the
* prefix.
* @param onRegisterSuccess This calls
* onRegisterSuccess.onRegisterSuccess(prefix, registeredPrefixId) when this
* receives a success message from the forwarder. If onRegisterSuccess is null,
* this does not use it.
* @param flags The flags for finer control of which interests are forwarded
* to the application.
* @param wireFormat A WireFormat object used to encode the message.
* @param commandKeyChain The KeyChain object for signing interests.
* @param commandCertificateName The certificate name for signing interests.
* @param face The face which is passed to the onInterest callback. If
* onInterest is null, this is ignored.
* @throws IOException For I/O error in sending the registration request.
* @throws SecurityException If signing a command interest for NFD and cannot
* find the private key for the certificateName.
*/
public final void
registerPrefix
(long registeredPrefixId, Name prefix, OnInterestCallback onInterest,
OnRegisterFailed onRegisterFailed, OnRegisterSuccess onRegisterSuccess,
ForwardingFlags flags, WireFormat wireFormat, KeyChain commandKeyChain,
Name commandCertificateName, Face face) throws IOException, SecurityException
{
nfdRegisterPrefix
(registeredPrefixId, new Name(prefix), onInterest, onRegisterFailed,
onRegisterSuccess, flags, commandKeyChain, commandCertificateName,
wireFormat, face);
}
/**
* Remove the registered prefix entry with the registeredPrefixId from the
* registered prefix table. This does not affect another registered prefix with
* a different registeredPrefixId, even if it has the same prefix name. If an
* interest filter was automatically created by registerPrefix, also remove it.
* If there is no entry with the registeredPrefixId, do nothing.
* @param registeredPrefixId The ID returned from registerPrefix.
*/
public final void
removeRegisteredPrefix(long registeredPrefixId)
{
registeredPrefixTable_.removeRegisteredPrefix(registeredPrefixId);
}
/**
* Add an entry to the local interest filter table to call the onInterest
* callback for a matching incoming Interest. This method only modifies the
* library's local callback table and does not register the prefix with the
* forwarder. It will always succeed. To register a prefix with the forwarder,
* use registerPrefix.
* @param interestFilterId The getNextEntryId() for the interest filter ID
* which Face got so it could return it to the caller.
* @param filter The InterestFilter with a prefix and optional regex filter
* used to match the name of an incoming Interest. This makes a copy of filter.
* @param onInterest When an Interest is received which matches the filter,
* this calls
* onInterest.onInterest(prefix, interest, face, interestFilterId, filter).
* @param face The face which is passed to the onInterest callback.
*/
public final void
setInterestFilter
(long interestFilterId, InterestFilter filter, OnInterestCallback onInterest,
Face face)
{
interestFilterTable_.setInterestFilter
(interestFilterId, new InterestFilter(filter), onInterest, face);
}
/**
* Remove the interest filter entry which has the interestFilterId from the
* interest filter table. This does not affect another interest filter with
* a different interestFilterId, even if it has the same prefix name.
* If there is no entry with the interestFilterId, do nothing.
* @param interestFilterId The ID returned from setInterestFilter.
*/
public final void
unsetInterestFilter(long interestFilterId)
{
interestFilterTable_.unsetInterestFilter(interestFilterId);
}
/**
* The OnInterestCallback calls this to put a Data packet which
* satisfies an Interest.
* @param data The Data packet which satisfies the interest.
* @param wireFormat A WireFormat object used to encode the Data packet.
* @throws Error If the encoded Data packet size exceeds getMaxNdnPacketSize().
*/
public final void
putData(Data data, WireFormat wireFormat) throws IOException
{
Blob encoding = data.wireEncode(wireFormat);
if (encoding.size() > getMaxNdnPacketSize())
throw new Error
("The encoded Data packet size exceeds the maximum limit getMaxNdnPacketSize()");
transport_.send(encoding.buf());
}
/**
* Send the encoded packet out through the transport.
* @param encoding The array of bytes for the encoded packet to send. This
* reads from position() to limit(), but does not change the position.
* @throws Error If the encoded packet size exceeds getMaxNdnPacketSize().
*/
public final void
send(ByteBuffer encoding) throws IOException
{
if (encoding.remaining() > getMaxNdnPacketSize())
throw new Error
("The encoded packet size exceeds the maximum limit getMaxNdnPacketSize()");
transport_.send(encoding);
}
/**
* Process any packets to receive and call callbacks such as onData,
* onInterest or onTimeout. This returns immediately if there is no data to
* receive. This blocks while calling the callbacks. You should repeatedly
* call this from an event loop, with calls to sleep as needed so that the
* loop doesn't use 100% of the CPU. Since processEvents modifies the pending
* interest table, your application should make sure that it calls
* processEvents in the same thread as expressInterest (which also modifies
* the pending interest table).
* This may throw an exception for reading data or in the callback for
* processing the data. If you call this from an main event loop, you may want
* to catch and log/disregard all exceptions.
*/
public final void
processEvents() throws IOException, EncodingException
{
transport_.processEvents();
// If Face.callLater is overridden to use a different mechanism, then
// processEvents is not needed to check for delayed calls.
delayedCallTable_.callTimedOut();
}
public final Transport
getTransport() { return transport_; }
public final Transport.ConnectionInfo
getConnectionInfo() { return connectionInfo_; }
public final void onReceivedElement(ByteBuffer element) throws EncodingException
{
LpPacket lpPacket = null;
if (element.get(0) == Tlv.LpPacket_LpPacket) {
// Decode the LpPacket and replace element with the fragment.
lpPacket = new LpPacket();
// Set copy false so that the fragment is a slice which will be copied below.
// The header fields are all integers and don't need to be copied.
TlvWireFormat.get().decodeLpPacket(lpPacket, element, false);
element = lpPacket.getFragmentWireEncoding().buf();
}
// First, decode as Interest or Data.
Interest interest = null;
Data data = null;
if (element.get(0) == Tlv.Interest || element.get(0) == Tlv.Data) {
TlvDecoder decoder = new TlvDecoder(element);
if (decoder.peekType(Tlv.Interest, element.remaining())) {
interest = new Interest();
interest.wireDecode(element, TlvWireFormat.get());
if (lpPacket != null)
interest.setLpPacket(lpPacket);
}
else if (decoder.peekType(Tlv.Data, element.remaining())) {
data = new Data();
data.wireDecode(element, TlvWireFormat.get());
if (lpPacket != null)
data.setLpPacket(lpPacket);
}
}
if (lpPacket != null) {
// We have decoded the fragment, so remove the wire encoding to save memory.
lpPacket.setFragmentWireEncoding(new Blob());
NetworkNack networkNack = NetworkNack.getFirstHeader(lpPacket);
if (networkNack != null) {
if (interest == null)
// We got a Nack but not for an Interest, so drop the packet.
return;
ArrayList pitEntries =
new ArrayList();
pendingInterestTable_.extractEntriesForNackInterest(interest, pitEntries);
for (int i = 0; i < pitEntries.size(); ++i) {
PendingInterestTable.Entry pendingInterest = pitEntries.get(i);
try {
pendingInterest.getOnNetworkNack().onNetworkNack
(pendingInterest.getInterest(), networkNack);
} catch (Throwable ex) {
logger_.log(Level.SEVERE, "Error in onNack", ex);
}
}
// We have processed the network Nack packet.
return;
}
}
// Now process as Interest or Data.
if (interest != null) {
// Quickly lock and get all interest filter callbacks which match.
ArrayList matchedFilters = new ArrayList();
interestFilterTable_.getMatchedFilters(interest, matchedFilters);
// The lock on interestFilterTable_ is released, so call the callbacks.
for (int i = 0; i < matchedFilters.size(); ++i) {
InterestFilterTable.Entry entry =
(InterestFilterTable.Entry)matchedFilters.get(i);
try {
entry.getOnInterest().onInterest
(entry.getFilter().getPrefix(), interest, entry.getFace(),
entry.getInterestFilterId(), entry.getFilter());
} catch (Throwable ex) {
logger_.log(Level.SEVERE, "Error in onInterest", ex);
}
}
}
else if (data != null) {
ArrayList pitEntries =
new ArrayList();
pendingInterestTable_.extractEntriesForExpressedInterest(data, pitEntries);
for (int i = 0; i < pitEntries.size(); ++i) {
PendingInterestTable.Entry pendingInterest = pitEntries.get(i);
try {
pendingInterest.getOnData().onData(pendingInterest.getInterest(), data);
} catch (Throwable ex) {
logger_.log(Level.SEVERE, "Error in onData", ex);
}
}
}
}
/**
* Check if the face is local based on the current connection through the
* Transport; some Transport may cause network IO (e.g. an IP host name lookup).
* @return True if the face is local, false if not.
* @throws IOException
*/
public final boolean isLocal() throws IOException{
return transport_.isLocal(connectionInfo_);
}
/**
* Shut down by closing the transport
*/
public final void
shutdown()
{
try {
transport_.close();
}
catch (IOException e) {}
}
/**
* Get the practical limit of the size of a network-layer packet. If a packet
* is larger than this, the library or application MAY drop it.
* @return The maximum NDN packet size.
*/
public static int
getMaxNdnPacketSize() { return Common.MAX_NDN_PACKET_SIZE; }
/**
* Call callback.run() after the given delay. This adds to
* delayedCallTable_ which is used by processEvents().
* @param delayMilliseconds The delay in milliseconds.
* @param callback This calls callback.run() after the delay.
*/
public final void
callLater(double delayMilliseconds, Runnable callback)
{
delayedCallTable_.callLater(delayMilliseconds, callback);
}
/**
* Get the next unique entry ID for the pending interest table, interest
* filter table, etc. This uses a synchronized to be thread safe. Most entry
* IDs are for the pending interest table (there usually are not many interest
* filter table entries) so we use a common pool to only have to do the thread
* safe lock in one method which is called by Face.
* @return The next entry ID.
*/
public long
getNextEntryId()
{
synchronized(lastEntryIdLock_) {
return ++lastEntryId_;
}
}
/**
* This is used in callLater for when the pending interest expires. If the
* pendingInterest is still in the pendingInterestTable_, remove it and call
* its onTimeout callback.
* @param pendingInterest The pending interest to check.
*/
private void
processInterestTimeout(PendingInterestTable.Entry pendingInterest)
{
if (pendingInterestTable_.removeEntry(pendingInterest))
pendingInterest.callTimeout();
}
/**
* Do the work of expressInterest once we know we are connected. Add the entry
* to the PIT, encode and send the interest.
* @param pendingInterestId The getNextEntryId() for the pending interest ID
* which Face got so it could return it to the caller.
* @param interestCopy The Interest to send, which has already been copied by
* expressInterest.
* @param onData This calls onData.onData when a matching data packet is
* received.
* @param onTimeout This calls onTimeout.onTimeout if the interest times out.
* If onTimeout is null, this does not use it.
* @param onNetworkNack This calls onNetworkNack.onNetworkNack when a network
* Nack packet is received. If onNetworkNack is null, this does not use it.
* @param wireFormat A WireFormat object used to encode the message.
* @param face The face which has the callLater method, used for interest
* timeouts. The callLater method may be overridden in a subclass of Face.
* @throws IOException For I/O error in sending the interest.
* @throws Error If the encoded interest size exceeds getMaxNdnPacketSize().
*/
private void
expressInterestHelper
(long pendingInterestId, Interest interestCopy, OnData onData,
OnTimeout onTimeout, OnNetworkNack onNetworkNack, WireFormat wireFormat,
Face face) throws IOException
{
final PendingInterestTable.Entry pendingInterest =
pendingInterestTable_.add
(pendingInterestId, interestCopy, onData, onTimeout, onNetworkNack);
if (pendingInterest == null)
// removePendingInterest was already called with the pendingInterestId.
return;
if (onTimeout != null || interestCopy.getInterestLifetimeMilliseconds() >= 0.0) {
// Set up the timeout.
double delayMilliseconds = interestCopy.getInterestLifetimeMilliseconds();
if (delayMilliseconds < 0.0)
// Use a default timeout delay.
delayMilliseconds = 4000.0;
face.callLater
(delayMilliseconds,
new Runnable() {
public void run() { processInterestTimeout(pendingInterest); }
});
}
// Special case: For timeoutPrefix_ we don't actually send the interest.
if (!timeoutPrefix_.match(interestCopy.getName())) {
Blob encoding = interestCopy.wireEncode(wireFormat);
if (encoding.size() > getMaxNdnPacketSize())
throw new Error
("The encoded interest size exceeds the maximum limit getMaxNdnPacketSize()");
transport_.send(encoding.buf());
}
}
private enum ConnectStatus { UNCONNECTED, CONNECT_REQUESTED, CONNECT_COMPLETE }
private static class RegisterResponse implements OnData, OnTimeout {
public RegisterResponse(Info info, Node parent)
{
info_ = info;
parent_ = parent;
}
/**
* We received the response.
* @param interest
* @param responseData
*/
public void
onData(Interest interest, Data responseData)
{
// Decode responseData.getContent() and check for a success code.
ControlResponse controlResponse = new ControlResponse();
try {
controlResponse.wireDecode(responseData.getContent(), TlvWireFormat.get());
} catch (EncodingException ex) {
logger_.log(Level.INFO,
"Register prefix failed: Error decoding the NFD response: {0}", ex);
try {
info_.onRegisterFailed_.onRegisterFailed(info_.prefix_);
} catch (Throwable exception) {
logger_.log(Level.SEVERE, "Error in onRegisterFailed", exception);
}
return;
}
// Status code 200 is "OK".
if (controlResponse.getStatusCode() != 200) {
logger_.log(Level.INFO,
"Register prefix failed: Expected NFD status code 200, got: {0}",
controlResponse.getStatusCode());
try {
info_.onRegisterFailed_.onRegisterFailed(info_.prefix_);
} catch (Throwable ex) {
logger_.log(Level.SEVERE, "Error in onRegisterFailed", ex);
}
return;
}
// Success, so we can add to the registered prefix table.
if (info_.registeredPrefixId_ != 0) {
long interestFilterId = 0;
if (info_.onInterest_ != null) {
// registerPrefix was called with the "combined" form that includes the
// callback, so add an InterestFilterEntry.
interestFilterId = parent_.getNextEntryId();
parent_.setInterestFilter
(interestFilterId, new InterestFilter
(info_.prefix_), info_.onInterest_, info_.face_);
}
if (!parent_.registeredPrefixTable_.add
(info_.registeredPrefixId_, info_.prefix_, interestFilterId)) {
// removeRegisteredPrefix was already called with the registeredPrefixId.
if (interestFilterId > 0)
// Remove the related interest filter we just added.
parent_.unsetInterestFilter(interestFilterId);
return;
}
}
logger_.log(Level.INFO,
"Register prefix succeeded with the NFD forwarder for prefix {0}",
info_.prefix_.toUri());
if (info_.onRegisterSuccess_ != null) {
try {
info_.onRegisterSuccess_.onRegisterSuccess
(info_.prefix_, info_.registeredPrefixId_);
} catch (Throwable ex) {
logger_.log(Level.SEVERE, "Error in onRegisterSuccess", ex);
}
}
}
/**
* We timed out waiting for the response.
* @param timedOutInterest
*/
public void
onTimeout(Interest timedOutInterest)
{
logger_.log(Level.INFO,
"Timeout for NFD register prefix command.");
try {
info_.onRegisterFailed_.onRegisterFailed(info_.prefix_);
} catch (Throwable ex) {
logger_.log(Level.SEVERE, "Error in onRegisterFailed", ex);
}
}
public static class Info {
/**
*
* @param prefix
* @param onRegisterFailed
* @param onRegisterSuccess
* @param registeredPrefixId The registered prefix ID also returned by
* registerPrefix.
* @param onInterest The callback to add if register succeeds.
* @param face
*/
public Info
(Name prefix,OnRegisterFailed onRegisterFailed,
OnRegisterSuccess onRegisterSuccess, long registeredPrefixId,
OnInterestCallback onInterest, Face face)
{
prefix_ = prefix;
onRegisterFailed_ = onRegisterFailed;
onRegisterSuccess_ = onRegisterSuccess;
registeredPrefixId_ = registeredPrefixId;
onInterest_ = onInterest;
face_ = face;
}
public final Name prefix_;
public final OnRegisterFailed onRegisterFailed_;
public final OnRegisterSuccess onRegisterSuccess_;
public final long registeredPrefixId_;
public final OnInterestCallback onInterest_;
public final Face face_;
}
private final Info info_;
private final Node parent_;
}
/**
* Do the work of registerPrefix to register with NFD.
* @param registeredPrefixId The getNextEntryId() which registerPrefix got so
* it could return it to the caller. If this is 0, then don't add to
* registeredPrefixTable_ (assuming it has already been done).
* @param prefix
* @param onInterest
* @param onRegisterFailed
* @param onRegisterSuccess
* @param flags
* @param commandKeyChain
* @param commandCertificateName
* @param wireFormat
* @param face The face which is passed to the onInterest callback. If
* onInterest is null, this is ignored.
* @throws SecurityException If cannot find the private key for the
* certificateName.
*/
private void
nfdRegisterPrefix
(long registeredPrefixId, Name prefix, OnInterestCallback onInterest,
OnRegisterFailed onRegisterFailed, OnRegisterSuccess onRegisterSuccess,
ForwardingFlags flags, KeyChain commandKeyChain,
Name commandCertificateName, WireFormat wireFormat, Face face)
throws SecurityException
{
if (commandKeyChain == null)
throw new Error
("registerPrefix: The command KeyChain has not been set. You must call setCommandSigningInfo.");
if (commandCertificateName.size() == 0)
throw new Error
("registerPrefix: The command certificate name has not been set. You must call setCommandSigningInfo.");
ControlParameters controlParameters = new ControlParameters();
controlParameters.setName(prefix);
controlParameters.setForwardingFlags(flags);
Interest commandInterest = new Interest();
// Determine whether to use remote prefix registration.
boolean faceIsLocal;
try {
faceIsLocal = isLocal();
} catch (IOException ex) {
logger_.log(Level.INFO,
"Register prefix failed: Error attempting to determine if the face is local: {0}", ex);
try {
onRegisterFailed.onRegisterFailed(prefix);
} catch (Throwable exception) {
logger_.log(Level.SEVERE, "Error in onRegisterFailed", exception);
}
return;
}
if (faceIsLocal) {
commandInterest.setName(new Name("/localhost/nfd/rib/register"));
// The interest is answered by the local host, so set a short timeout.
commandInterest.setInterestLifetimeMilliseconds(2000.0);
}
else {
commandInterest.setName(new Name("/localhop/nfd/rib/register"));
// The host is remote, so set a longer timeout.
commandInterest.setInterestLifetimeMilliseconds(4000.0);
}
// NFD only accepts TlvWireFormat packets.
commandInterest.getName().append(controlParameters.wireEncode(TlvWireFormat.get()));
makeCommandInterest
(commandInterest, commandKeyChain, commandCertificateName,
TlvWireFormat.get());
// Send the registration interest.
RegisterResponse response = new RegisterResponse
(new RegisterResponse.Info
(prefix, onRegisterFailed, onRegisterSuccess, registeredPrefixId,
onInterest, face),
this);
try {
expressInterest
(getNextEntryId(), commandInterest, response, response, null,
wireFormat, face);
}
catch (IOException ex) {
// Can't send the interest. Call onRegisterFailed.
logger_.log(Level.INFO,
"Register prefix failed: Error sending the register prefix interest to the forwarder: {0}", ex);
try {
onRegisterFailed.onRegisterFailed(prefix);
} catch (Throwable exception) {
logger_.log(Level.SEVERE, "Error in onRegisterFailed", exception);
}
}
}
private final Transport transport_;
private final Transport.ConnectionInfo connectionInfo_;
private final PendingInterestTable pendingInterestTable_ =
new PendingInterestTable();
private final InterestFilterTable interestFilterTable_ =
new InterestFilterTable();
private final RegisteredPrefixTable registeredPrefixTable_ =
new RegisteredPrefixTable(interestFilterTable_);
private final DelayedCallTable delayedCallTable_ = new DelayedCallTable();
// Use ArrayList without generics so it works with older Java compilers.
private final List onConnectedCallbacks_ =
Collections.synchronizedList(new ArrayList()); // Runnable
private final CommandInterestGenerator commandInterestGenerator_ =
new CommandInterestGenerator();
private final Name timeoutPrefix_ = new Name("/local/timeout");
private long lastEntryId_;
private final Object lastEntryIdLock_ = new Object();
private ConnectStatus connectStatus_ = ConnectStatus.UNCONNECTED;
private static Blob nonceTemplate_ = new Blob(new byte[] { 0, 0, 0, 0 });
private static final Logger logger_ = Logger.getLogger(Node.class.getName());
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy