def __init__(self, onReceivedSyncState, onInitialized, applicationDataPrefix, applicationBroadcastPrefix, sessionNo, face, keyChain, certificateName, syncLifetime, onRegisterFailed): self._onReceivedSyncState = onReceivedSyncState self._onInitialized = onInitialized self._applicationDataPrefixUri = applicationDataPrefix.toUri() self._applicationBroadcastPrefix = Name(applicationBroadcastPrefix) self._sessionNo = sessionNo self._face = face self._keyChain = keyChain self._certificateName = Name(certificateName) self._syncLifetime = syncLifetime self._contentCache = MemoryContentCache(face) self._digestLog = [] # of _DigestLogEntry self._digestTree = DigestTree() self._sequenceNo = -1 self._enabled = True emptyContent = sync_state_pb2.SyncStateMsg() # Use getattr to avoid pylint errors. self._digestLog.append(self._DigestLogEntry("00", getattr(emptyContent, "ss"))) # Register the prefix with the contentCache_ and use our own onInterest # as the onDataNotFound fallback. self._contentCache.registerPrefix( self._applicationBroadcastPrefix, onRegisterFailed, self._onInterest) interest = Interest(self._applicationBroadcastPrefix) interest.getName().append("00") interest.setInterestLifetimeMilliseconds(1000) interest.setMustBeFresh(True) face.expressInterest(interest, self._onData, self._initialTimeOut) logging.getLogger(__name__).info("initial sync expressed") logging.getLogger(__name__).info("%s", interest.getName().toUri())
def __init__(self, onReceivedSyncState, onInitialized, applicationDataPrefix, applicationBroadcastPrefix, sessionNo, face, keyChain, certificateName, syncLifetime, onRegisterFailed): self._onReceivedSyncState = onReceivedSyncState self._onInitialized = onInitialized self._applicationDataPrefixUri = applicationDataPrefix.toUri() self._applicationBroadcastPrefix = Name(applicationBroadcastPrefix) self._sessionNo = sessionNo self._face = face self._keyChain = keyChain self._certificateName = Name(certificateName) self._syncLifetime = syncLifetime self._contentCache = MemoryContentCache(face) self._digestLog = [] # of _DigestLogEntry self._digestTree = DigestTree() self._sequenceNo = -1 self._enabled = True emptyContent = SyncStateMsg() # Use getattr to avoid pylint errors. self._digestLog.append(self._DigestLogEntry("00", getattr(emptyContent, "ss"))) # Register the prefix with the contentCache_ and use our own onInterest # as the onDataNotFound fallback. self._contentCache.registerPrefix( self._applicationBroadcastPrefix, onRegisterFailed, self._onInterest) interest = Interest(self._applicationBroadcastPrefix) interest.getName().append("00") interest.setInterestLifetimeMilliseconds(1000) interest.setMustBeFresh(True) face.expressInterest(interest, self._onData, self._initialTimeOut) logging.getLogger(__name__).info("initial sync expressed") logging.getLogger(__name__).info("%s", interest.getName().toUri())
def _nfdRegisterPrefix( self, registeredPrefixId, prefix, onInterest, onRegisterFailed, flags, commandKeyChain, commandCertificateName, face): """ Do the work of registerPrefix to register with NFD. :param int 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). """ if commandKeyChain == None: raise RuntimeError( "registerPrefix: The command KeyChain has not been set. You must call setCommandSigningInfo.") if commandCertificateName.size() == 0: raise RuntimeError( "registerPrefix: The command certificate name has not been set. You must call setCommandSigningInfo.") controlParameters = ControlParameters() controlParameters.setName(prefix) controlParameters.setForwardingFlags(flags) commandInterest = Interest() if self.isLocal(): commandInterest.setName(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(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())) self.makeCommandInterest( commandInterest, commandKeyChain, commandCertificateName, TlvWireFormat.get()) if registeredPrefixId != 0: interestFilterId = 0 if onInterest != None: # registerPrefix was called with the "combined" form that includes # the callback, so add an InterestFilterEntry. interestFilterId = self.getNextEntryId() self.setInterestFilter( interestFilterId, InterestFilter(prefix), onInterest, face) self._registeredPrefixTable.append(Node._RegisteredPrefix( registeredPrefixId, prefix, interestFilterId)) # Send the registration interest. response = Node._RegisterResponse( self, prefix, onInterest, onRegisterFailed, flags, TlvWireFormat.get(), True, face) self.expressInterest( self.getNextEntryId(), commandInterest, response.onData, response.onTimeout, TlvWireFormat.get(), face)
def _nfdRegisterPrefix(self, registeredPrefixId, prefix, onInterest, onRegisterFailed, onRegisterSuccess, registrationOptions, commandKeyChain, commandCertificateName, face): """ Do the work of registerPrefix to register with NFD. :param int 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). """ if commandKeyChain == None: raise RuntimeError( "registerPrefix: The command KeyChain has not been set. You must call setCommandSigningInfo." ) if commandCertificateName.size() == 0: raise RuntimeError( "registerPrefix: The command certificate name has not been set. You must call setCommandSigningInfo." ) controlParameters = ControlParameters() controlParameters.setName(prefix) controlParameters.setForwardingFlags(registrationOptions) if (registrationOptions.getOrigin() != None and registrationOptions.getOrigin() >= 0): controlParameters.setOrigin(registrationOptions.getOrigin()) # Remove the origin value from the flags since it is not used to encode. controlParameters.getForwardingFlags().setOrigin(None) commandInterest = Interest() commandInterest.setCanBePrefix(True) commandInterest.setMustBeFresh(True) if self.isLocal(): commandInterest.setName(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(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())) self.makeCommandInterest(commandInterest, commandKeyChain, commandCertificateName, TlvWireFormat.get()) # Send the registration interest. response = Node._RegisterResponse(prefix, onRegisterFailed, onRegisterSuccess, registeredPrefixId, self, onInterest, face) self.expressInterest(self.getNextEntryId(), commandInterest, response.onData, response.onTimeout, None, TlvWireFormat.get(), face)
def _nfdRegisterPrefix( self, registeredPrefixId, prefix, onInterest, onRegisterFailed, onRegisterSuccess, registrationOptions, commandKeyChain, commandCertificateName, face): """ Do the work of registerPrefix to register with NFD. :param int 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). """ if commandKeyChain == None: raise RuntimeError( "registerPrefix: The command KeyChain has not been set. You must call setCommandSigningInfo.") if commandCertificateName.size() == 0: raise RuntimeError( "registerPrefix: The command certificate name has not been set. You must call setCommandSigningInfo.") controlParameters = ControlParameters() controlParameters.setName(prefix) controlParameters.setForwardingFlags(registrationOptions) if (registrationOptions.getOrigin() != None and registrationOptions.getOrigin() >= 0): controlParameters.setOrigin(registrationOptions.getOrigin()) # Remove the origin value from the flags since it is not used to encode. controlParameters.getForwardingFlags().setOrigin(None) commandInterest = Interest() commandInterest.setCanBePrefix(True) if self.isLocal(): commandInterest.setName(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(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())) self.makeCommandInterest( commandInterest, commandKeyChain, commandCertificateName, TlvWireFormat.get()) # Send the registration interest. response = Node._RegisterResponse( prefix, onRegisterFailed, onRegisterSuccess, registeredPrefixId, self, onInterest, face) self.expressInterest( self.getNextEntryId(), commandInterest, response.onData, response.onTimeout, None, TlvWireFormat.get(), face)
def publishNextSequenceNo(self, applicationInfo=None): """ Increment the sequence number, create a sync message with the new sequence number and publish a data packet where the name is the applicationBroadcastPrefix + the root digest of the current digest tree. Then add the sync message to the digest tree and digest log which creates a new root digest. Finally, express an interest for the next sync update with the name applicationBroadcastPrefix + the new root digest. After this, your application should publish the content for the new sequence number. You can get the new sequence number with getSequenceNo(). Note: Your application must call processEvents. Since processEvents modifies the internal ChronoSync data structures, your application should make sure that it calls processEvents in the same thread as publishNextSequenceNo() (which also modifies the data structures). :param Blob applicationInfo: (optional) This appends applicationInfo to the content of the sync messages. This same info is provided to the receiving application in the SyncState state object provided to the onReceivedSyncState callback. """ applicationInfo = (applicationInfo if isinstance( applicationInfo, Blob) else Blob(applicationInfo)) self._sequenceNo += 1 syncMessage = SyncStateMsg() content = getattr(syncMessage, "ss").add() content.name = self._applicationDataPrefixUri content.type = SyncState_UPDATE content.seqno.seq = self._sequenceNo content.seqno.session = self._sessionNo if not applicationInfo.isNull() and applicationInfo.size() > 0: content.application_info = applicationInfo.toBytes() self._broadcastSyncState(self._digestTree.getRoot(), syncMessage) if not self._update(getattr(syncMessage, "ss")): # Since we incremented the sequence number, we expect there to be a # new digest log entry. raise RuntimeError( "ChronoSync: update did not create a new digest log entry") # TODO: Should we have an option to not express an interest if this is the # final publish of the session? interest = Interest(self._applicationBroadcastPrefix) interest.getName().append(self._digestTree.getRoot()) interest.setInterestLifetimeMilliseconds(self._syncLifetime) self._face.expressInterest(interest, self._onData, self._syncTimeout)
def publishNextSequenceNo(self, applicationInfo = None): """ Increment the sequence number, create a sync message with the new sequence number and publish a data packet where the name is the applicationBroadcastPrefix + the root digest of the current digest tree. Then add the sync message to the digest tree and digest log which creates a new root digest. Finally, express an interest for the next sync update with the name applicationBroadcastPrefix + the new root digest. After this, your application should publish the content for the new sequence number. You can get the new sequence number with getSequenceNo(). Note: Your application must call processEvents. Since processEvents modifies the internal ChronoSync data structures, your application should make sure that it calls processEvents in the same thread as publishNextSequenceNo() (which also modifies the data structures). :param Blob applicationInfo: (optional) This appends applicationInfo to the content of the sync messages. This same info is provided to the receiving application in the SyncState state object provided to the onReceivedSyncState callback. """ applicationInfo = (applicationInfo if isinstance(applicationInfo, Blob) else Blob(applicationInfo)) self._sequenceNo += 1 syncMessage = SyncStateMsg() content = getattr(syncMessage, "ss").add() content.name = self._applicationDataPrefixUri content.type = SyncState_UPDATE content.seqno.seq = self._sequenceNo content.seqno.session = self._sessionNo if not applicationInfo.isNull() and applicationInfo.size() > 0: content.application_info = applicationInfo.toBytes() self._broadcastSyncState(self._digestTree.getRoot(), syncMessage) if not self._update(getattr(syncMessage, "ss")): # Since we incremented the sequence number, we expect there to be a # new digest log entry. raise RuntimeError( "ChronoSync: update did not create a new digest log entry") # TODO: Should we have an option to not express an interest if this is the # final publish of the session? interest = Interest(self._applicationBroadcastPrefix) interest.getName().append(self._digestTree.getRoot()) interest.setInterestLifetimeMilliseconds(self._syncLifetime) self._face.expressInterest(interest, self._onData, self._syncTimeout)
def onReceivedElement(self, element): """ This is called by the transport's ElementReader to process an entire received Data or Interest element. :param element: The bytes of the incoming element. :type element: An array type with int elements """ # First, decode as Interest or Data. interest = None data = None decoder = TlvDecoder(element) if decoder.peekType(Tlv.Interest, len(element)): interest = Interest() interest.wireDecode(element, TlvWireFormat.get()) elif decoder.peekType(Tlv.Data, len(element)): data = Data() data.wireDecode(element, TlvWireFormat.get()) # Now process as Interest or Data. if interest != None: # Call all interest filter callbacks which match. for i in range(len(self._interestFilterTable)): entry = self._interestFilterTable[i] if entry.getFilter().doesMatch(interest.getName()): includeFilter = True # Use getcallargs to test if onInterest accepts 5 args. try: inspect.getcallargs(entry.getOnInterest(), None, None, None, None, None) except TypeError: # Assume onInterest is old-style with 4 arguments. includeFilter = False if includeFilter: try: entry.getOnInterest()( entry.getFilter().getPrefix(), interest, entry.getFace(), entry.getInterestFilterId(), entry.getFilter()) except: logging.exception("Error in onInterest") else: # Old-style onInterest without the filter argument. We # still pass a Face instead of Transport since Face also # has a send method. try: entry.getOnInterest()( entry.getFilter().getPrefix(), interest, entry.getFace(), entry.getInterestFilterId()) except: logging.exception("Error in onInterest") elif data != None: pendingInterests = self._extractEntriesForExpressedInterest( data.getName()) for pendingInterest in pendingInterests: try: pendingInterest.getOnData()(pendingInterest.getInterest(), data) except: logging.exception("Error in onData")
def _nfdRegisterPrefix(self, registeredPrefixId, prefix, onInterest, onRegisterFailed, flags, commandKeyChain, commandCertificateName): """ Do the work of registerPrefix to register with NFD. :param int registeredPrefixId: The _RegisteredPrefix.getNextRegisteredPrefixId() 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). """ if commandKeyChain == None: raise RuntimeError( "registerPrefix: The command KeyChain has not been set. You must call setCommandSigningInfo." ) if commandCertificateName.size() == 0: raise RuntimeError( "registerPrefix: The command certificate name has not been set. You must call setCommandSigningInfo." ) controlParameters = ControlParameters() controlParameters.setName(prefix) commandInterest = Interest(Name("/localhost/nfd/rib/register")) # NFD only accepts TlvWireFormat packets. commandInterest.getName().append( controlParameters.wireEncode(TlvWireFormat.get())) self.makeCommandInterest(commandInterest, commandKeyChain, commandCertificateName, TlvWireFormat.get()) # The interest is answered by the local host, so set a short timeout. commandInterest.setInterestLifetimeMilliseconds(2000.0) if registeredPrefixId != 0: # Save the onInterest callback and send the registration interest. self._registeredPrefixTable.append( Node._RegisteredPrefix(registeredPrefixId, prefix, onInterest)) response = Node._RegisterResponse(self, prefix, onInterest, onRegisterFailed, flags, TlvWireFormat.get(), True) self.expressInterest(commandInterest, response.onData, response.onTimeout, TlvWireFormat.get())
def _makeNotificationInterest(self): """ Make and return a new Interest where the name is _applicationBroadcastPrefix plus the encoding of _stateVector. Also use _hmacKey to sign it with HmacWithSha256. :return: The new signed notification interest. :rtype: Interest """ interest = Interest(self._applicationBroadcastPrefix) interest.setInterestLifetimeMilliseconds( self._notificationInterestLifetime) interest.getName().append( StateVectorSync2018.encodeStateVector(self._stateVector, self._sortedStateVectorKeys)) # TODO: Should we just use key name /A ? KeyChain.signWithHmacWithSha256(interest, self._hmacKey, Name("/A")) return interest
def _nfdRegisterPrefix( self, registeredPrefixId, prefix, onInterest, onRegisterFailed, flags, commandKeyChain, commandCertificateName): """ Do the work of registerPrefix to register with NFD. :param int registeredPrefixId: The _RegisteredPrefix.getNextRegisteredPrefixId() 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). """ if commandKeyChain == None: raise RuntimeError( "registerPrefix: The command KeyChain has not been set. You must call setCommandSigningInfo.") if commandCertificateName.size() == 0: raise RuntimeError( "registerPrefix: The command certificate name has not been set. You must call setCommandSigningInfo.") controlParameters = ControlParameters() controlParameters.setName(prefix) commandInterest = Interest(Name("/localhost/nfd/rib/register")) # NFD only accepts TlvWireFormat packets. commandInterest.getName().append(controlParameters.wireEncode(TlvWireFormat.get())) self.makeCommandInterest( commandInterest, commandKeyChain, commandCertificateName, TlvWireFormat.get()) # The interest is answered by the local host, so set a short timeout. commandInterest.setInterestLifetimeMilliseconds(2000.0) if registeredPrefixId != 0: # Save the onInterest callback and send the registration interest. self._registeredPrefixTable.append(Node._RegisteredPrefix( registeredPrefixId, prefix, onInterest)) response = Node._RegisterResponse( self, prefix, onInterest, onRegisterFailed, flags, TlvWireFormat.get(), True) self.expressInterest( commandInterest, response.onData, response.onTimeout, TlvWireFormat.get())
def publishNextSequenceNo(self): """ Increment the sequence number, create a sync message with the new sequence number and publish a data packet where the name is the applicationBroadcastPrefix + the root digest of the current digest tree. Then add the sync message to the digest tree and digest log which creates a new root digest. Finally, express an interest for the next sync update with the name applicationBroadcastPrefix + the new root digest. After this, your application should publish the content for the new sequence number. You can get the new sequence number with getSequenceNo(). Note: Your application must call processEvents. Since processEvents modifies the internal ChronoSync data structures, your application should make sure that it calls processEvents in the same thread as publishNextSequenceNo() (which also modifies the data structures). """ self._sequenceNo += 1 syncMessage = sync_state_pb2.SyncStateMsg() content = getattr(syncMessage, "ss").add() content.name = self._applicationDataPrefixUri content.type = SyncState_UPDATE content.seqno.seq = self._sequenceNo content.seqno.session = self._sessionNo self._broadcastSyncState(self._digestTree.getRoot(), syncMessage) if not self._update(getattr(syncMessage, "ss")): # Since we incremented the sequence number, we expect there to be a # new digest log entry. raise RuntimeError( "ChronoSync: update did not create a new digest log entry") # TODO: Should we have an option to not express an interest if this is the # final publish of the session? interest = Interest(self._applicationBroadcastPrefix) interest.getName().append(self._digestTree.getRoot()) interest.setInterestLifetimeMilliseconds(self._syncLifetime) self._face.expressInterest(interest, self._onData, self._syncTimeout)
def onReceivedElement(self, element): """ This is called by the transport's ElementReader to process an entire received Data or Interest element. :param element: The bytes of the incoming element. :type element: An array type with int elements """ # The type codes for TLV Interest and Data packets are chosen to not # conflict with the first byte of a binary XML packet, so we canjust # look at the first byte. if not (element[0] == Tlv.Interest or element[0] == Tlv.Data): # Ignore non-TLV elements. return # First, decode as Interest or Data. interest = None data = None decoder = TlvDecoder(element) if decoder.peekType(Tlv.Interest, len(element)): interest = Interest() interest.wireDecode(element, TlvWireFormat.get()) elif decoder.peekType(Tlv.Data, len(element)): data = Data() data.wireDecode(element, TlvWireFormat.get()) # Now process as Interest or Data. if interest != None: entry = self._getEntryForRegisteredPrefix(interest.getName()) if entry != None: entry.getOnInterest()(entry.getPrefix(), interest, self._transport, entry.getRegisteredPrefixId()) elif data != None: pendingInterests = self._extractEntriesForExpressedInterest( data.getName()) for pendingInterest in pendingInterests: pendingInterest.getOnData()(pendingInterest.getInterest(), data)
def onReceivedElement(self, element): """ This is called by the transport's ElementReader to process an entire received Data or Interest element. :param element: The bytes of the incoming element. :type element: An array type with int elements """ # The type codes for TLV Interest and Data packets are chosen to not # conflict with the first byte of a binary XML packet, so we canjust # look at the first byte. if not (element[0] == Tlv.Interest or element[0] == Tlv.Data): # Ignore non-TLV elements. return # First, decode as Interest or Data. interest = None data = None decoder = TlvDecoder(element) if decoder.peekType(Tlv.Interest, len(element)): interest = Interest() interest.wireDecode(element, TlvWireFormat.get()) elif decoder.peekType(Tlv.Data, len(element)): data = Data() data.wireDecode(element, TlvWireFormat.get()) # Now process as Interest or Data. if interest != None: entry = self._getEntryForRegisteredPrefix(interest.getName()) if entry != None: entry.getOnInterest()( entry.getPrefix(), interest, self._transport, entry.getRegisteredPrefixId()) elif data != None: pendingInterests = self._extractEntriesForExpressedInterest( data.getName()) for pendingInterest in pendingInterests: pendingInterest.getOnData()(pendingInterest.getInterest(), data)
class InterestValidationState(ValidationState): """ Create a InterestValidationState for the Interest packet. The caller must ensure that the state instance is valid until the validation finishes (i.e., until validateCertificateChain() and validateOriginalPacket() have been called). :param Interest interest: The Date packet being validated, which is copied. :param successCallback: This calls successCallback(interest) to report a successful Interest validation. :type successCallback: function object :param failureCallback: This calls failureCallback(interest, error) to report a failed Interest validation, where error is a ValidationError. :type failureCallback: function object """ def __init__(self, interest, successCallback, failureCallback): super(InterestValidationState, self).__init__() # Make a copy. self._interest = Interest(interest) self._successCallbacks = [successCallback ] # of SuccessCallback function object self._failureCallback = failureCallback if successCallback == None: raise ValueError("The successCallback is None") if self._failureCallback == None: raise ValueError("The failureCallback is None") def fail(self, error): """ Call the failure callback. :param ValidationError error: """ logging.getLogger(__name__).info("" + str(error)) try: self._failureCallback(self._interest, error) except: logging.exception("Error in failureCallback") self.setOutcome(False) def getOriginalInterest(self): """ Get the original Interest packet being validated which was given to the constructor. :return: The original Interest packet. :rtype: Interest """ return self._interest def addSuccessCallback(self, successCallback): """ :param successCallback: This calls successCallback(interest). :type successCallback: function object """ self._successCallbacks.append(successCallback) def _verifyOriginalPacket(self, trustedCertificate): """ Verify the signature of the original packet. This is only called by the Validator class. :param CertificateV2 trustedCertificate: The certificate that signs the original packet. """ if VerificationHelpers.verifyInterestSignature(self._interest, trustedCertificate): logging.getLogger(__name__).info("OK signature for interest `" + self._interest.getName().toUri() + "`") for i in range(len(self._successCallbacks)): try: self._successCallbacks[i](self._interest) except: logging.exception("Error in successCallback") self.setOutcome(True) else: self.fail( ValidationError( ValidationError.INVALID_SIGNATURE, "Invalid signature of interest `" + self._interest.getName().toUri() + "`")) def _bypassValidation(self): """ Call the success callback of the original packet without signature validation. This is only called by the Validator class. """ logging.getLogger( __name__).info("Signature verification bypassed for interest `" + self._interest.getName().toUri() + "`") for i in range(len(self._successCallbacks)): try: self._successCallbacks[i](self._interest) except: logging.exception("Error in successCallback") self.setOutcome(True)
def onReceivedElement(self, element): """ This is called by the transport's ElementReader to process an entire received Data or Interest element. :param element: The bytes of the incoming element. :type element: An array type with int elements """ # The type codes for TLV Interest and Data packets are chosen to not # conflict with the first byte of a binary XML packet, so we canjust # look at the first byte. if not (element[0] == Tlv.Interest or element[0] == Tlv.Data): # Ignore non-TLV elements. # Assume it is Binary XML. if not WireFormat.ENABLE_NDNX: raise RuntimeError( "BinaryXmlWireFormat (NDNx) is deprecated. To enable while you upgrade your network to use NDN-TLV, set WireFormat.ENABLE_NDNX = True") return # First, decode as Interest or Data. interest = None data = None decoder = TlvDecoder(element) if decoder.peekType(Tlv.Interest, len(element)): interest = Interest() interest.wireDecode(element, TlvWireFormat.get()) elif decoder.peekType(Tlv.Data, len(element)): data = Data() data.wireDecode(element, TlvWireFormat.get()) # Now process as Interest or Data. if interest != None: # Call all interest filter callbacks which match. for i in range(len(self._interestFilterTable)): entry = self._interestFilterTable[i] if entry.getFilter().doesMatch(interest.getName()): includeFilter = True # Use getcallargs to test if onInterest accepts 5 args. try: inspect.getcallargs(entry.getOnInterest(), None, None, None, None, None) except TypeError: # Assume onInterest is old-style with 4 arguments. includeFilter = False if includeFilter: entry.getOnInterest()( entry.getFilter().getPrefix(), interest, entry.getFace(), entry.getInterestFilterId(), entry.getFilter()) else: # Old-style onInterest without the filter argument. We # still pass a Face instead of Transport since Face also # has a send method. entry.getOnInterest()( entry.getFilter().getPrefix(), interest, entry.getFace(), entry.getInterestFilterId()) elif data != None: pendingInterests = self._extractEntriesForExpressedInterest( data.getName()) for pendingInterest in pendingInterests: pendingInterest.getOnData()(pendingInterest.getInterest(), data)
def makeCommandInterest(self, name, params=None, wireFormat=None): """ Append the timestamp and nonce name components to the supplied name, create an Interest object and signs it with the KeyChain given to the constructor. This ensures that the timestamp is greater than the timestamp used in the previous call. :param Name name: The Name for the Interest, which is copied. :param SigningInfo params: (optional) The signing parameters. If omitted, use a default SigningInfo(). :param WireFormat wireFormat: (optional) A WireFormat object used to encode the SignatureInfo and to encode interest name for signing. If omitted, use WireFormat getDefaultWireFormat(). :return: The new command Interest object. :rtype: Interest """ arg2 = params arg3 = wireFormat if isinstance(arg2, SigningInfo): params = arg2 else: params = None if isinstance(arg2, WireFormat): wireFormat = arg2 elif isinstance(arg3, WireFormat): wireFormat = arg3 else: wireFormat = None if params == None: params = SigningInfo() if wireFormat == None: wireFormat = WireFormat.getDefaultWireFormat() # This copies the Name. commandInterest = Interest(name) # _nowOffsetMilliseconds is only used for testing. now = Common.getNowMilliseconds() + self._nowOffsetMilliseconds timestamp = round(now) while timestamp <= self._lastUsedTimestamp: timestamp += 1.0 # The timestamp is encoded as a TLV nonNegativeInteger. encoder = TlvEncoder(8) encoder.writeNonNegativeInteger(int(timestamp)) commandInterest.getName().append(Blob(encoder.getOutput(), False)) # The random value is a TLV nonNegativeInteger too, but we know it is 8 # bytes, so we don't need to call the nonNegativeInteger encoder. randomBuffer = bytearray(8) for i in range(len(randomBuffer)): randomBuffer[i] = _systemRandom.randint(0, 0xff) commandInterest.getName().append(Blob(randomBuffer, False)) self._keyChain.sign(commandInterest, params, wireFormat) # We successfully signed the interest, so update the timestamp. self._lastUsedTimestamp = timestamp return commandInterest
class InterestValidationState(ValidationState): """ Create a InterestValidationState for the Interest packet. The caller must ensure that the state instance is valid until the validation finishes (i.e., until validateCertificateChain() and validateOriginalPacket() have been called). :param Interest interest: The Date packet being validated, which is copied. :param successCallback: This calls successCallback(interest) to report a successful Interest validation. :type successCallback: function object :param failureCallback: This calls failureCallback(interest, error) to report a failed Interest validation, where error is a ValidationError. :type failureCallback: function object """ def __init__(self, interest, successCallback, failureCallback): super(InterestValidationState, self).__init__() # Make a copy. self._interest = Interest(interest) self._successCallbacks = [successCallback] # of SuccessCallback function object self._failureCallback = failureCallback if successCallback == None: raise ValueError("The successCallback is None") if self._failureCallback == None: raise ValueError("The failureCallback is None") def fail(self, error): """ Call the failure callback. :param ValidationError error: """ logging.getLogger(__name__).info("" + str(error)) try: self._failureCallback(self._interest, error) except: logging.exception("Error in failureCallback") self.setOutcome(False) def getOriginalInterest(self): """ Get the original Interest packet being validated which was given to the constructor. :return: The original Interest packet. :rtype: Interest """ return self._interest def addSuccessCallback(self, successCallback): """ :param successCallback: This calls successCallback(interest). :type successCallback: function object """ self._successCallbacks.append(successCallback) def _verifyOriginalPacket(self, trustedCertificate): """ Verify the signature of the original packet. This is only called by the Validator class. :param CertificateV2 trustedCertificate: The certificate that signs the original packet. """ if VerificationHelpers.verifyInterestSignature( self._interest, trustedCertificate): logging.getLogger(__name__).info("OK signature for interest `" + self._interest.getName().toUri() + "`") for i in range(len(self._successCallbacks)): try: self._successCallbacks[i](self._interest) except: logging.exception("Error in successCallback") self.setOutcome(True) else: self.fail(ValidationError(ValidationError.INVALID_SIGNATURE, "Invalid signature of interest `" + self._interest.getName().toUri() + "`")) def _bypassValidation(self): """ Call the success callback of the original packet without signature validation. This is only called by the Validator class. """ logging.getLogger(__name__).info( "Signature verification bypassed for interest `" + self._interest.getName().toUri() + "`") for i in range(len(self._successCallbacks)): try: self._successCallbacks[i](self._interest) except: logging.exception("Error in successCallback") self.setOutcome(True)