Major updates to change default behavior of NDN to connect to a random host on the testbed.
Make expressInterest and registerPrefix connect when needed. Removed WebSocketTransport.connectWebSocket.
Also, don't fetch the ccndid until registerPrefix needs it.
diff --git a/js/NDN.js b/js/NDN.js
index 30d5d3f..f77e73c 100644
--- a/js/NDN.js
+++ b/js/NDN.js
@@ -11,7 +11,7 @@
* {
* getTransport: function() { return new WebSocketTransport(); }
* getHostAndPort: transport.defaultGetHostAndPort,
- * host: 'localhost', // If null, use getHostAndPort when connecting.
+ * host: null, // If null, use getHostAndPort when connecting.
* port: 9696,
* onopen: function() { if (LOG > 3) console.log("NDN connection established."); }
* onclose: function() { if (LOG > 3) console.log("NDN connection closed."); }
@@ -25,7 +25,7 @@
var getTransport = (settings.getTransport || function() { return new WebSocketTransport(); });
this.transport = getTransport();
this.getHostAndPort = (settings.getHostAndPort || this.transport.defaultGetHostAndPort);
- this.host = (settings.host !== undefined ? settings.host : 'localhost');
+ this.host = (settings.host !== undefined ? settings.host : null);
this.port = (settings.port || 9696);
this.readyStatus = NDN.UNOPEN;
this.verify = (settings.verify !== undefined ? settings.verify : true);
@@ -176,16 +176,74 @@
};
NDN.prototype.registerPrefix = function(name, closure, flag) {
- if (this.readyStatus != NDN.OPENED) {
- console.log('Connection is not established.');
- return -1;
- }
+ var thisNDN = this;
+ var onConnected = function() {
+ if (thisNDN.ccndid == null) {
+ // Fetch ccndid first, then register.
+ var interest = new Interest(NDN.ccndIdFetcher);
+ interest.interestLifetime = 4000; // milliseconds
+ if (LOG>3) console.log('Expressing interest for ccndid from ccnd.');
+ thisNDN.transport.expressInterest
+ (thisNDN, interest, new NDN.FetchCcndidClosure(thisNDN, name, closure, flag));
+ }
+ else
+ thisNDN.registerPrefixHelper(name, closure, flag);
+ };
- if (this.ccndid == null) {
- console.log('ccnd node ID unkonwn. Cannot register prefix.');
- return -1;
+ if (this.host == null || this.port == null) {
+ if (this.getHostAndPort == null)
+ console.log('ERROR: host OR port NOT SET');
+ else
+ this.connectAndExecute(onConnected);
+ }
+ else
+ onConnected();
+};
+
+/*
+ * This is a closure to receive the ContentObject for NDN.ccndIdFetcher and call
+ * registerPrefixHelper(name, callerClosure, flag).
+ */
+NDN.FetchCcndidClosure = function FetchCcndidClosure(ndn, name, callerClosure, flag) {
+ // Inherit from Closure.
+ Closure.call(this);
+
+ this.ndn = ndn;
+ this.name = name;
+ this.callerClosure = callerClosure;
+ this.flag = flag;
+};
+
+NDN.FetchCcndidClosure.prototype.upcall = function(kind, upcallInfo) {
+ if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
+ console.log("Timeout while requesting the ccndid. Cannot registerPrefix for " +
+ this.name.to_uri() + " .");
+ return Closure.RESULT_OK;
+ }
+ if (!(kind == Closure.UPCALL_CONTENT ||
+ kind == Closure.UPCALL_CONTENT_UNVERIFIED))
+ // The upcall is not for us.
+ return Closure.RESULT_ERR;
+
+ var co = upcallInfo.contentObject;
+ if (!co.signedInfo || !co.signedInfo.publisher
+ || !co.signedInfo.publisher.publisherPublicKeyDigest)
+ console.log
+ ("ContentObject doesn't have a publisherPublicKeyDigest. Cannot set ccndid and registerPrefix for "
+ + this.name.to_uri() + " .");
+ else {
+ if (LOG>3) console.log('Got ccndid from ccnd.');
+ this.ndn.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
+ if (LOG>3) console.log(this.ndn.ccndid);
+
+ this.ndn.registerPrefixHelper(this.name, this.callerClosure, this.flag);
}
-
+
+ return Closure.RESULT_OK;
+};
+
+// Do the work of registerPrefix once we know we are connected with a ccndid.
+NDN.prototype.registerPrefixHelper = function(name, closure, flag) {
var fe = new ForwardingEntry('selfreg', name, null, null, 3, 2147483647);
var bytes = encodeForwardingEntry(fe);
@@ -208,8 +266,6 @@
NDN.CSTable.push(csEntry);
this.transport.send(encodeToBinaryInterest(interest));
-
- return 0;
};
/*
@@ -243,154 +299,132 @@
var co = new ContentObject();
co.from_ccnb(decoder);
- if (this.ccndid == null && NDN.ccndIdFetcher.match(co.name)) {
- // We are in starting phase, record publisherPublicKeyDigest in ccndid
- if(!co.signedInfo || !co.signedInfo.publisher
- || !co.signedInfo.publisher.publisherPublicKeyDigest) {
- console.log("Cannot contact router, close NDN now.");
+ var pitEntry = NDN.getEntryForExpressedInterest(co.name);
+ if (pitEntry != null) {
+ //console.log(pitEntry);
+ // Remove PIT entry from NDN.PITTable
+ var index = NDN.PITTable.indexOf(pitEntry);
+ if (index >= 0)
+ NDN.PITTable.splice(index, 1);
- // Close NDN if we fail to connect to a ccn router
- this.readyStatus = NDN.CLOSED;
- this.onclose();
- //console.log("NDN.onclose event fired.");
- } else {
- if (LOG>3) console.log('Connected to ccnd.');
- this.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
- if (LOG>3) console.log(ndn.ccndid);
+ var currentClosure = pitEntry.closure;
- // Call NDN.onopen after success
- this.readyStatus = NDN.OPENED;
- this.onopen();
- //console.log("NDN.onopen event fired.");
+ // Cancel interest timer
+ clearTimeout(pitEntry.timerID);
+ //console.log("Clear interest timer");
+ //console.log(currentClosure.timerID);
+
+ if (this.verify == false) {
+ // Pass content up without verifying the signature
+ currentClosure.upcall(Closure.UPCALL_CONTENT_UNVERIFIED, new UpcallInfo(this, null, 0, co));
+ return;
}
- } else {
- var pitEntry = NDN.getEntryForExpressedInterest(co.name);
- if (pitEntry != null) {
- //console.log(pitEntry);
- // Remove PIT entry from NDN.PITTable
- var index = NDN.PITTable.indexOf(pitEntry);
- if (index >= 0)
- NDN.PITTable.splice(index, 1);
-
- var currentClosure = pitEntry.closure;
-
- // Cancel interest timer
- clearTimeout(pitEntry.timerID);
- //console.log("Clear interest timer");
- //console.log(currentClosure.timerID);
- if (this.verify == false) {
- // Pass content up without verifying the signature
- currentClosure.upcall(Closure.UPCALL_CONTENT_UNVERIFIED, new UpcallInfo(this, null, 0, co));
- return;
+ // Key verification
+
+ // Recursive key fetching & verification closure
+ var KeyFetchClosure = function KeyFetchClosure(content, closure, key, sig, wit) {
+ this.contentObject = content; // unverified content object
+ this.closure = closure; // closure corresponding to the contentObject
+ this.keyName = key; // name of current key to be fetched
+ this.sigHex = sig; // hex signature string to be verified
+ this.witness = wit;
+
+ Closure.call(this);
+ };
+
+ var thisNDN = this;
+ KeyFetchClosure.prototype.upcall = function(kind, upcallInfo) {
+ if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
+ console.log("In KeyFetchClosure.upcall: interest time out.");
+ console.log(this.keyName.contentName.getName());
+ } else if (kind == Closure.UPCALL_CONTENT) {
+ //console.log("In KeyFetchClosure.upcall: signature verification passed");
+
+ var rsakey = decodeSubjectPublicKeyInfo(upcallInfo.contentObject.content);
+ var verified = rsakey.verifyByteArray(this.contentObject.rawSignatureData, this.witness, this.sigHex);
+
+ var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
+ //console.log("raise encapsulated closure");
+ this.closure.upcall(flag, new UpcallInfo(thisNDN, null, 0, this.contentObject));
+
+ // Store key in cache
+ var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
+ NDN.addKeyEntry(keyEntry);
+ //console.log(NDN.KeyStore);
+ } else if (kind == Closure.UPCALL_CONTENT_BAD) {
+ console.log("In KeyFetchClosure.upcall: signature verification failed");
}
-
- // Key verification
+ };
- // Recursive key fetching & verification closure
- var KeyFetchClosure = function KeyFetchClosure(content, closure, key, sig, wit) {
- this.contentObject = content; // unverified content object
- this.closure = closure; // closure corresponding to the contentObject
- this.keyName = key; // name of current key to be fetched
- this.sigHex = sig; // hex signature string to be verified
- this.witness = wit;
-
- Closure.call(this);
- };
-
- var thisNdn = this;
- KeyFetchClosure.prototype.upcall = function(kind, upcallInfo) {
- if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
- console.log("In KeyFetchClosure.upcall: interest time out.");
- console.log(this.keyName.contentName.getName());
- } else if (kind == Closure.UPCALL_CONTENT) {
- //console.log("In KeyFetchClosure.upcall: signature verification passed");
-
- var rsakey = decodeSubjectPublicKeyInfo(upcallInfo.contentObject.content);
- var verified = rsakey.verifyByteArray(this.contentObject.rawSignatureData, this.witness, this.sigHex);
-
- var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
- //console.log("raise encapsulated closure");
- this.closure.upcall(flag, new UpcallInfo(thisNdn, null, 0, this.contentObject));
-
- // Store key in cache
- var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
- NDN.addKeyEntry(keyEntry);
- //console.log(NDN.KeyStore);
- } else if (kind == Closure.UPCALL_CONTENT_BAD) {
- console.log("In KeyFetchClosure.upcall: signature verification failed");
- }
- };
-
- if (co.signedInfo && co.signedInfo.locator && co.signature) {
- if (LOG > 3) console.log("Key verification...");
- var sigHex = DataUtils.toHex(co.signature.signature).toLowerCase();
+ if (co.signedInfo && co.signedInfo.locator && co.signature) {
+ if (LOG > 3) console.log("Key verification...");
+ var sigHex = DataUtils.toHex(co.signature.signature).toLowerCase();
- var wit = null;
- if (co.signature.Witness != null) {
- wit = new Witness();
- wit.decode(co.signature.Witness);
- }
+ var wit = null;
+ if (co.signature.Witness != null) {
+ wit = new Witness();
+ wit.decode(co.signature.Witness);
+ }
- var keylocator = co.signedInfo.locator;
- if (keylocator.type == KeyLocatorType.KEYNAME) {
- if (LOG > 3) console.log("KeyLocator contains KEYNAME");
- //var keyname = keylocator.keyName.contentName.getName();
- //console.log(nameStr);
- //console.log(keyname);
+ var keylocator = co.signedInfo.locator;
+ if (keylocator.type == KeyLocatorType.KEYNAME) {
+ if (LOG > 3) console.log("KeyLocator contains KEYNAME");
+ //var keyname = keylocator.keyName.contentName.getName();
+ //console.log(nameStr);
+ //console.log(keyname);
- if (keylocator.keyName.contentName.match(co.name)) {
- if (LOG > 3) console.log("Content is key itself");
+ if (keylocator.keyName.contentName.match(co.name)) {
+ if (LOG > 3) console.log("Content is key itself");
- var rsakey = decodeSubjectPublicKeyInfo(co.content);
+ var rsakey = decodeSubjectPublicKeyInfo(co.content);
+ var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
+ var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
+
+ currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
+
+ // SWT: We don't need to store key here since the same key will be
+ // stored again in the closure.
+ //var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
+ //NDN.addKeyEntry(keyEntry);
+ //console.log(NDN.KeyStore);
+ } else {
+ // Check local key store
+ var keyEntry = NDN.getKeyByName(keylocator.keyName);
+ if (keyEntry) {
+ // Key found, verify now
+ if (LOG > 3) console.log("Local key cache hit");
+ var rsakey = keyEntry.rsaKey;
var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
-
- currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
-
- // SWT: We don't need to store key here since the same key will be
- // stored again in the closure.
- //var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
- //NDN.addKeyEntry(keyEntry);
- //console.log(NDN.KeyStore);
- } else {
- // Check local key store
- var keyEntry = NDN.getKeyByName(keylocator.keyName);
- if (keyEntry) {
- // Key found, verify now
- if (LOG > 3) console.log("Local key cache hit");
- var rsakey = keyEntry.rsaKey;
- var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
- var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
- // Raise callback
- currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
- } else {
- // Not found, fetch now
- if (LOG > 3) console.log("Fetch key according to keylocator");
- var nextClosure = new KeyFetchClosure(co, currentClosure, keylocator.keyName, sigHex, wit);
- this.expressInterest(keylocator.keyName.contentName.getPrefix(4), nextClosure);
- }
+ // Raise callback
+ currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
+ } else {
+ // Not found, fetch now
+ if (LOG > 3) console.log("Fetch key according to keylocator");
+ var nextClosure = new KeyFetchClosure(co, currentClosure, keylocator.keyName, sigHex, wit);
+ this.expressInterest(keylocator.keyName.contentName.getPrefix(4), nextClosure);
}
- } else if (keylocator.type == KeyLocatorType.KEY) {
- if (LOG > 3) console.log("Keylocator contains KEY");
-
- var rsakey = decodeSubjectPublicKeyInfo(co.signedInfo.locator.publicKey);
- var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
-
- var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
- // Raise callback
- currentClosure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(this, null, 0, co));
-
- // Since KeyLocator does not contain key name for this key,
- // we have no way to store it as a key entry in KeyStore.
- } else {
- var cert = keylocator.certificate;
- console.log("KeyLocator contains CERT");
- console.log(cert);
-
- // TODO: verify certificate
}
+ } else if (keylocator.type == KeyLocatorType.KEY) {
+ if (LOG > 3) console.log("Keylocator contains KEY");
+
+ var rsakey = decodeSubjectPublicKeyInfo(co.signedInfo.locator.publicKey);
+ var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
+
+ var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
+ // Raise callback
+ currentClosure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(this, null, 0, co));
+
+ // Since KeyLocator does not contain key name for this key,
+ // we have no way to store it as a key entry in KeyStore.
+ } else {
+ var cert = keylocator.certificate;
+ console.log("KeyLocator contains CERT");
+ console.log(cert);
+
+ // TODO: verify certificate
}
}
}
@@ -452,6 +486,11 @@
// The host is alive, so cancel the timeout and continue with onConnected().
clearTimeout(this.timerID);
+
+ // Call NDN.onopen after success
+ this.ndn.readyStatus = NDN.OPENED;
+ this.ndn.onopen();
+
this.onConnected();
return Closure.RESULT_OK;
diff --git a/js/WebSocketTransport.js b/js/WebSocketTransport.js
index e0c768a..316a1f0 100644
--- a/js/WebSocketTransport.js
+++ b/js/WebSocketTransport.js
@@ -5,6 +5,8 @@
var WebSocketTransport = function WebSocketTransport() {
this.ws = null;
+ this.connectedHost = null;
+ this.connectedPort = null;
this.elementReader = null;
this.defaultGetHostAndPort = NDN.makeShuffledGetHostAndPort
(["A.ws.ndn.ucla.edu", "B.ws.ndn.ucla.edu", "C.ws.ndn.ucla.edu", "D.ws.ndn.ucla.edu",
@@ -12,12 +14,14 @@
9696);
};
-WebSocketTransport.prototype.connectWebSocket = function(ndn) {
+WebSocketTransport.prototype.connect = function(ndn, onopenCallback) {
if (this.ws != null)
delete this.ws;
this.ws = new WebSocket('ws://' + ndn.host + ':' + ndn.port);
if (LOG > 0) console.log('ws connection created.');
+ this.connectedHost = ndn.host;
+ this.connectedPort = ndn.port;
this.ws.binaryType = "arraybuffer";
@@ -48,11 +52,9 @@
if (LOG > 3) console.log(ev);
if (LOG > 3) console.log('ws.onopen: WebSocket connection opened.');
if (LOG > 3) console.log('ws.onopen: ReadyState: ' + this.readyState);
-
- // Fetch ccndid now
- var interest = new Interest(NDN.ccndIdFetcher);
- interest.interestLifetime = 4000; // milliseconds
- self.send(encodeToBinaryInterest(interest));
+ // NDN.registerPrefix will fetch the ccndid when needed.
+
+ onopenCallback();
}
this.ws.onerror = function(ev) {
@@ -94,11 +96,15 @@
}
WebSocketTransport.prototype.expressInterest = function(ndn, interest, closure) {
- if (ndn.readyStatus != NDN.OPENED) {
- console.log('Connection is not established.');
- return;
+ if (this.ws == null || this.connectedHost != ndn.host || this.connectedPort != ndn.port) {
+ var self = this;
+ this.connect(ndn, function() { self.expressInterestHelper(ndn, interest, closure); });
}
-
+ else
+ this.expressInterestHelper(ndn, interest, closure);
+};
+
+WebSocketTransport.prototype.expressInterestHelper = function(ndn, interest, closure) {
//TODO: check local content store first
if (closure != null) {
var pitEntry = new PITEntry(interest, closure);
@@ -129,4 +135,3 @@
this.send(encodeToBinaryInterest(interest));
};
-
diff --git a/js/tools/build/ndn-js-uncomp.js b/js/tools/build/ndn-js-uncomp.js
index b2ec4d4..a6c2c4d 100644
--- a/js/tools/build/ndn-js-uncomp.js
+++ b/js/tools/build/ndn-js-uncomp.js
@@ -70,6 +70,8 @@
var WebSocketTransport = function WebSocketTransport() {
this.ws = null;
+ this.connectedHost = null;
+ this.connectedPort = null;
this.elementReader = null;
this.defaultGetHostAndPort = NDN.makeShuffledGetHostAndPort
(["A.ws.ndn.ucla.edu", "B.ws.ndn.ucla.edu", "C.ws.ndn.ucla.edu", "D.ws.ndn.ucla.edu",
@@ -77,12 +79,14 @@
9696);
};
-WebSocketTransport.prototype.connectWebSocket = function(ndn) {
+WebSocketTransport.prototype.connect = function(ndn, onopenCallback) {
if (this.ws != null)
delete this.ws;
this.ws = new WebSocket('ws://' + ndn.host + ':' + ndn.port);
if (LOG > 0) console.log('ws connection created.');
+ this.connectedHost = ndn.host;
+ this.connectedPort = ndn.port;
this.ws.binaryType = "arraybuffer";
@@ -113,11 +117,9 @@
if (LOG > 3) console.log(ev);
if (LOG > 3) console.log('ws.onopen: WebSocket connection opened.');
if (LOG > 3) console.log('ws.onopen: ReadyState: ' + this.readyState);
-
- // Fetch ccndid now
- var interest = new Interest(NDN.ccndIdFetcher);
- interest.interestLifetime = 4000; // milliseconds
- self.send(encodeToBinaryInterest(interest));
+ // NDN.registerPrefix will fetch the ccndid when needed.
+
+ onopenCallback();
}
this.ws.onerror = function(ev) {
@@ -159,11 +161,15 @@
}
WebSocketTransport.prototype.expressInterest = function(ndn, interest, closure) {
- if (ndn.readyStatus != NDN.OPENED) {
- console.log('Connection is not established.');
- return;
+ if (this.ws == null || this.connectedHost != ndn.host || this.connectedPort != ndn.port) {
+ var self = this;
+ this.connect(ndn, function() { self.expressInterestHelper(ndn, interest, closure); });
}
-
+ else
+ this.expressInterestHelper(ndn, interest, closure);
+};
+
+WebSocketTransport.prototype.expressInterestHelper = function(ndn, interest, closure) {
//TODO: check local content store first
if (closure != null) {
var pitEntry = new PITEntry(interest, closure);
@@ -194,7 +200,6 @@
this.send(encodeToBinaryInterest(interest));
};
-
/**
* @author: Meki Cheraoui
* See COPYING for copyright and distribution information.
@@ -7512,7 +7517,7 @@
* {
* getTransport: function() { return new WebSocketTransport(); }
* getHostAndPort: transport.defaultGetHostAndPort,
- * host: 'localhost', // If null, use getHostAndPort when connecting.
+ * host: null, // If null, use getHostAndPort when connecting.
* port: 9696,
* onopen: function() { if (LOG > 3) console.log("NDN connection established."); }
* onclose: function() { if (LOG > 3) console.log("NDN connection closed."); }
@@ -7526,7 +7531,7 @@
var getTransport = (settings.getTransport || function() { return new WebSocketTransport(); });
this.transport = getTransport();
this.getHostAndPort = (settings.getHostAndPort || this.transport.defaultGetHostAndPort);
- this.host = (settings.host !== undefined ? settings.host : 'localhost');
+ this.host = (settings.host !== undefined ? settings.host : null);
this.port = (settings.port || 9696);
this.readyStatus = NDN.UNOPEN;
this.verify = (settings.verify !== undefined ? settings.verify : true);
@@ -7677,16 +7682,74 @@
};
NDN.prototype.registerPrefix = function(name, closure, flag) {
- if (this.readyStatus != NDN.OPENED) {
- console.log('Connection is not established.');
- return -1;
- }
+ var thisNDN = this;
+ var onConnected = function() {
+ if (thisNDN.ccndid == null) {
+ // Fetch ccndid first, then register.
+ var interest = new Interest(NDN.ccndIdFetcher);
+ interest.interestLifetime = 4000; // milliseconds
+ if (LOG>3) console.log('Expressing interest for ccndid from ccnd.');
+ thisNDN.transport.expressInterest
+ (thisNDN, interest, new NDN.FetchCcndidClosure(thisNDN, name, closure, flag));
+ }
+ else
+ thisNDN.registerPrefixHelper(name, closure, flag);
+ };
- if (this.ccndid == null) {
- console.log('ccnd node ID unkonwn. Cannot register prefix.');
- return -1;
+ if (this.host == null || this.port == null) {
+ if (this.getHostAndPort == null)
+ console.log('ERROR: host OR port NOT SET');
+ else
+ this.connectAndExecute(onConnected);
+ }
+ else
+ onConnected();
+};
+
+/*
+ * This is a closure to receive the ContentObject for NDN.ccndIdFetcher and call
+ * registerPrefixHelper(name, callerClosure, flag).
+ */
+NDN.FetchCcndidClosure = function FetchCcndidClosure(ndn, name, callerClosure, flag) {
+ // Inherit from Closure.
+ Closure.call(this);
+
+ this.ndn = ndn;
+ this.name = name;
+ this.callerClosure = callerClosure;
+ this.flag = flag;
+};
+
+NDN.FetchCcndidClosure.prototype.upcall = function(kind, upcallInfo) {
+ if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
+ console.log("Timeout while requesting the ccndid. Cannot registerPrefix for " +
+ this.name.to_uri() + " .");
+ return Closure.RESULT_OK;
+ }
+ if (!(kind == Closure.UPCALL_CONTENT ||
+ kind == Closure.UPCALL_CONTENT_UNVERIFIED))
+ // The upcall is not for us.
+ return Closure.RESULT_ERR;
+
+ var co = upcallInfo.contentObject;
+ if (!co.signedInfo || !co.signedInfo.publisher
+ || !co.signedInfo.publisher.publisherPublicKeyDigest)
+ console.log
+ ("ContentObject doesn't have a publisherPublicKeyDigest. Cannot set ccndid and registerPrefix for "
+ + this.name.to_uri() + " .");
+ else {
+ if (LOG>3) console.log('Got ccndid from ccnd.');
+ this.ndn.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
+ if (LOG>3) console.log(this.ndn.ccndid);
+
+ this.ndn.registerPrefixHelper(this.name, this.callerClosure, this.flag);
}
-
+
+ return Closure.RESULT_OK;
+};
+
+// Do the work of registerPrefix once we know we are connected with a ccndid.
+NDN.prototype.registerPrefixHelper = function(name, closure, flag) {
var fe = new ForwardingEntry('selfreg', name, null, null, 3, 2147483647);
var bytes = encodeForwardingEntry(fe);
@@ -7709,8 +7772,6 @@
NDN.CSTable.push(csEntry);
this.transport.send(encodeToBinaryInterest(interest));
-
- return 0;
};
/*
@@ -7744,154 +7805,132 @@
var co = new ContentObject();
co.from_ccnb(decoder);
- if (this.ccndid == null && NDN.ccndIdFetcher.match(co.name)) {
- // We are in starting phase, record publisherPublicKeyDigest in ccndid
- if(!co.signedInfo || !co.signedInfo.publisher
- || !co.signedInfo.publisher.publisherPublicKeyDigest) {
- console.log("Cannot contact router, close NDN now.");
+ var pitEntry = NDN.getEntryForExpressedInterest(co.name);
+ if (pitEntry != null) {
+ //console.log(pitEntry);
+ // Remove PIT entry from NDN.PITTable
+ var index = NDN.PITTable.indexOf(pitEntry);
+ if (index >= 0)
+ NDN.PITTable.splice(index, 1);
- // Close NDN if we fail to connect to a ccn router
- this.readyStatus = NDN.CLOSED;
- this.onclose();
- //console.log("NDN.onclose event fired.");
- } else {
- if (LOG>3) console.log('Connected to ccnd.');
- this.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
- if (LOG>3) console.log(ndn.ccndid);
+ var currentClosure = pitEntry.closure;
- // Call NDN.onopen after success
- this.readyStatus = NDN.OPENED;
- this.onopen();
- //console.log("NDN.onopen event fired.");
+ // Cancel interest timer
+ clearTimeout(pitEntry.timerID);
+ //console.log("Clear interest timer");
+ //console.log(currentClosure.timerID);
+
+ if (this.verify == false) {
+ // Pass content up without verifying the signature
+ currentClosure.upcall(Closure.UPCALL_CONTENT_UNVERIFIED, new UpcallInfo(this, null, 0, co));
+ return;
}
- } else {
- var pitEntry = NDN.getEntryForExpressedInterest(co.name);
- if (pitEntry != null) {
- //console.log(pitEntry);
- // Remove PIT entry from NDN.PITTable
- var index = NDN.PITTable.indexOf(pitEntry);
- if (index >= 0)
- NDN.PITTable.splice(index, 1);
-
- var currentClosure = pitEntry.closure;
-
- // Cancel interest timer
- clearTimeout(pitEntry.timerID);
- //console.log("Clear interest timer");
- //console.log(currentClosure.timerID);
- if (this.verify == false) {
- // Pass content up without verifying the signature
- currentClosure.upcall(Closure.UPCALL_CONTENT_UNVERIFIED, new UpcallInfo(this, null, 0, co));
- return;
+ // Key verification
+
+ // Recursive key fetching & verification closure
+ var KeyFetchClosure = function KeyFetchClosure(content, closure, key, sig, wit) {
+ this.contentObject = content; // unverified content object
+ this.closure = closure; // closure corresponding to the contentObject
+ this.keyName = key; // name of current key to be fetched
+ this.sigHex = sig; // hex signature string to be verified
+ this.witness = wit;
+
+ Closure.call(this);
+ };
+
+ var thisNDN = this;
+ KeyFetchClosure.prototype.upcall = function(kind, upcallInfo) {
+ if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
+ console.log("In KeyFetchClosure.upcall: interest time out.");
+ console.log(this.keyName.contentName.getName());
+ } else if (kind == Closure.UPCALL_CONTENT) {
+ //console.log("In KeyFetchClosure.upcall: signature verification passed");
+
+ var rsakey = decodeSubjectPublicKeyInfo(upcallInfo.contentObject.content);
+ var verified = rsakey.verifyByteArray(this.contentObject.rawSignatureData, this.witness, this.sigHex);
+
+ var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
+ //console.log("raise encapsulated closure");
+ this.closure.upcall(flag, new UpcallInfo(thisNDN, null, 0, this.contentObject));
+
+ // Store key in cache
+ var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
+ NDN.addKeyEntry(keyEntry);
+ //console.log(NDN.KeyStore);
+ } else if (kind == Closure.UPCALL_CONTENT_BAD) {
+ console.log("In KeyFetchClosure.upcall: signature verification failed");
}
-
- // Key verification
+ };
- // Recursive key fetching & verification closure
- var KeyFetchClosure = function KeyFetchClosure(content, closure, key, sig, wit) {
- this.contentObject = content; // unverified content object
- this.closure = closure; // closure corresponding to the contentObject
- this.keyName = key; // name of current key to be fetched
- this.sigHex = sig; // hex signature string to be verified
- this.witness = wit;
-
- Closure.call(this);
- };
-
- var thisNdn = this;
- KeyFetchClosure.prototype.upcall = function(kind, upcallInfo) {
- if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
- console.log("In KeyFetchClosure.upcall: interest time out.");
- console.log(this.keyName.contentName.getName());
- } else if (kind == Closure.UPCALL_CONTENT) {
- //console.log("In KeyFetchClosure.upcall: signature verification passed");
-
- var rsakey = decodeSubjectPublicKeyInfo(upcallInfo.contentObject.content);
- var verified = rsakey.verifyByteArray(this.contentObject.rawSignatureData, this.witness, this.sigHex);
-
- var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
- //console.log("raise encapsulated closure");
- this.closure.upcall(flag, new UpcallInfo(thisNdn, null, 0, this.contentObject));
-
- // Store key in cache
- var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
- NDN.addKeyEntry(keyEntry);
- //console.log(NDN.KeyStore);
- } else if (kind == Closure.UPCALL_CONTENT_BAD) {
- console.log("In KeyFetchClosure.upcall: signature verification failed");
- }
- };
-
- if (co.signedInfo && co.signedInfo.locator && co.signature) {
- if (LOG > 3) console.log("Key verification...");
- var sigHex = DataUtils.toHex(co.signature.signature).toLowerCase();
+ if (co.signedInfo && co.signedInfo.locator && co.signature) {
+ if (LOG > 3) console.log("Key verification...");
+ var sigHex = DataUtils.toHex(co.signature.signature).toLowerCase();
- var wit = null;
- if (co.signature.Witness != null) {
- wit = new Witness();
- wit.decode(co.signature.Witness);
- }
+ var wit = null;
+ if (co.signature.Witness != null) {
+ wit = new Witness();
+ wit.decode(co.signature.Witness);
+ }
- var keylocator = co.signedInfo.locator;
- if (keylocator.type == KeyLocatorType.KEYNAME) {
- if (LOG > 3) console.log("KeyLocator contains KEYNAME");
- //var keyname = keylocator.keyName.contentName.getName();
- //console.log(nameStr);
- //console.log(keyname);
+ var keylocator = co.signedInfo.locator;
+ if (keylocator.type == KeyLocatorType.KEYNAME) {
+ if (LOG > 3) console.log("KeyLocator contains KEYNAME");
+ //var keyname = keylocator.keyName.contentName.getName();
+ //console.log(nameStr);
+ //console.log(keyname);
- if (keylocator.keyName.contentName.match(co.name)) {
- if (LOG > 3) console.log("Content is key itself");
+ if (keylocator.keyName.contentName.match(co.name)) {
+ if (LOG > 3) console.log("Content is key itself");
- var rsakey = decodeSubjectPublicKeyInfo(co.content);
+ var rsakey = decodeSubjectPublicKeyInfo(co.content);
+ var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
+ var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
+
+ currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
+
+ // SWT: We don't need to store key here since the same key will be
+ // stored again in the closure.
+ //var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
+ //NDN.addKeyEntry(keyEntry);
+ //console.log(NDN.KeyStore);
+ } else {
+ // Check local key store
+ var keyEntry = NDN.getKeyByName(keylocator.keyName);
+ if (keyEntry) {
+ // Key found, verify now
+ if (LOG > 3) console.log("Local key cache hit");
+ var rsakey = keyEntry.rsaKey;
var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
-
- currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
-
- // SWT: We don't need to store key here since the same key will be
- // stored again in the closure.
- //var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
- //NDN.addKeyEntry(keyEntry);
- //console.log(NDN.KeyStore);
- } else {
- // Check local key store
- var keyEntry = NDN.getKeyByName(keylocator.keyName);
- if (keyEntry) {
- // Key found, verify now
- if (LOG > 3) console.log("Local key cache hit");
- var rsakey = keyEntry.rsaKey;
- var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
- var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
- // Raise callback
- currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
- } else {
- // Not found, fetch now
- if (LOG > 3) console.log("Fetch key according to keylocator");
- var nextClosure = new KeyFetchClosure(co, currentClosure, keylocator.keyName, sigHex, wit);
- this.expressInterest(keylocator.keyName.contentName.getPrefix(4), nextClosure);
- }
+ // Raise callback
+ currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
+ } else {
+ // Not found, fetch now
+ if (LOG > 3) console.log("Fetch key according to keylocator");
+ var nextClosure = new KeyFetchClosure(co, currentClosure, keylocator.keyName, sigHex, wit);
+ this.expressInterest(keylocator.keyName.contentName.getPrefix(4), nextClosure);
}
- } else if (keylocator.type == KeyLocatorType.KEY) {
- if (LOG > 3) console.log("Keylocator contains KEY");
-
- var rsakey = decodeSubjectPublicKeyInfo(co.signedInfo.locator.publicKey);
- var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
-
- var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
- // Raise callback
- currentClosure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(this, null, 0, co));
-
- // Since KeyLocator does not contain key name for this key,
- // we have no way to store it as a key entry in KeyStore.
- } else {
- var cert = keylocator.certificate;
- console.log("KeyLocator contains CERT");
- console.log(cert);
-
- // TODO: verify certificate
}
+ } else if (keylocator.type == KeyLocatorType.KEY) {
+ if (LOG > 3) console.log("Keylocator contains KEY");
+
+ var rsakey = decodeSubjectPublicKeyInfo(co.signedInfo.locator.publicKey);
+ var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
+
+ var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
+ // Raise callback
+ currentClosure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(this, null, 0, co));
+
+ // Since KeyLocator does not contain key name for this key,
+ // we have no way to store it as a key entry in KeyStore.
+ } else {
+ var cert = keylocator.certificate;
+ console.log("KeyLocator contains CERT");
+ console.log(cert);
+
+ // TODO: verify certificate
}
}
}
@@ -7953,6 +7992,11 @@
// The host is alive, so cancel the timeout and continue with onConnected().
clearTimeout(this.timerID);
+
+ // Call NDN.onopen after success
+ this.ndn.readyStatus = NDN.OPENED;
+ this.ndn.onopen();
+
this.onConnected();
return Closure.RESULT_OK;
diff --git a/js/tools/build/ndn-js.js b/js/tools/build/ndn-js.js
index db7f2bc..3aacc7e 100644
--- a/js/tools/build/ndn-js.js
+++ b/js/tools/build/ndn-js.js
@@ -1,10 +1,11 @@
var Closure=function(){this.ndn_data=null;this.ndn_data_dirty=!1};Closure.RESULT_ERR=-1;Closure.RESULT_OK=0;Closure.RESULT_REEXPRESS=1;Closure.RESULT_INTEREST_CONSUMED=2;Closure.RESULT_VERIFY=3;Closure.RESULT_FETCHKEY=4;Closure.UPCALL_FINAL=0;Closure.UPCALL_INTEREST=1;Closure.UPCALL_CONSUMED_INTEREST=2;Closure.UPCALL_CONTENT=3;Closure.UPCALL_INTEREST_TIMED_OUT=4;Closure.UPCALL_CONTENT_UNVERIFIED=5;Closure.UPCALL_CONTENT_BAD=6;Closure.prototype.upcall=function(){return Closure.RESULT_OK};
var UpcallInfo=function(a,b,c,d){this.ndn=a;this.interest=b;this.matchedComps=c;this.contentObject=d};UpcallInfo.prototype.toString=function(){var a="ndn = "+this.ndn,a=a+("\nInterest = "+this.interest),a=a+("\nmatchedComps = "+this.matchedComps);return a+="\nContentObject: "+this.contentObject};
-var WebSocketTransport=function(){this.elementReader=this.ws=null;this.defaultGetHostAndPort=NDN.makeShuffledGetHostAndPort(["A.ws.ndn.ucla.edu","B.ws.ndn.ucla.edu","C.ws.ndn.ucla.edu","D.ws.ndn.ucla.edu","E.ws.ndn.ucla.edu"],9696)};
-WebSocketTransport.prototype.connectWebSocket=function(a){null!=this.ws&&delete this.ws;this.ws=new WebSocket("ws://"+a.host+":"+a.port);0<LOG&&console.log("ws connection created.");this.ws.binaryType="arraybuffer";this.elementReader=new BinaryXmlElementReader(a);var b=this;this.ws.onmessage=function(a){a=a.data;if(null==a||void 0==a||""==a)console.log("INVALID ANSWER");else if(a instanceof ArrayBuffer){a=new Uint8Array(a);3<LOG&&console.log("BINARY RESPONSE IS "+DataUtils.toHex(a));try{b.elementReader.onReceivedData(a)}catch(d){console.log("NDN.ws.onmessage exception: "+
-d)}}};this.ws.onopen=function(a){3<LOG&&console.log(a);3<LOG&&console.log("ws.onopen: WebSocket connection opened.");3<LOG&&console.log("ws.onopen: ReadyState: "+this.readyState);a=new Interest(NDN.ccndIdFetcher);a.interestLifetime=4E3;b.send(encodeToBinaryInterest(a))};this.ws.onerror=function(a){console.log("ws.onerror: ReadyState: "+this.readyState);console.log(a);console.log("ws.onerror: WebSocket error: "+a.data)};this.ws.onclose=function(){console.log("ws.onclose: WebSocket connection closed.");
-b.ws=null;a.readyStatus=NDN.CLOSED;a.onclose()}};WebSocketTransport.prototype.send=function(a){if(null!=this.ws){var b=new Uint8Array(a.length);b.set(a);this.ws.send(b.buffer);3<LOG&&console.log("ws.send() returned.")}else console.log("WebSocket connection is not established.")};
-WebSocketTransport.prototype.expressInterest=function(a,b,c){if(a.readyStatus!=NDN.OPENED)console.log("Connection is not established.");else{if(null!=c){var d=new PITEntry(b,c);NDN.PITTable.push(d);c.pitEntry=d}null!=c&&(d.timerID=setTimeout(function(){3<LOG&&console.log("Interest time out.");var e=NDN.PITTable.indexOf(d);0<=e&&NDN.PITTable.splice(e,1);c.upcall(Closure.UPCALL_INTEREST_TIMED_OUT,new UpcallInfo(a,b,0,null))},b.interestLifetime));this.send(encodeToBinaryInterest(b))}};
+var WebSocketTransport=function(){this.elementReader=this.connectedPort=this.connectedHost=this.ws=null;this.defaultGetHostAndPort=NDN.makeShuffledGetHostAndPort(["A.ws.ndn.ucla.edu","B.ws.ndn.ucla.edu","C.ws.ndn.ucla.edu","D.ws.ndn.ucla.edu","E.ws.ndn.ucla.edu"],9696)};
+WebSocketTransport.prototype.connect=function(a,b){null!=this.ws&&delete this.ws;this.ws=new WebSocket("ws://"+a.host+":"+a.port);0<LOG&&console.log("ws connection created.");this.connectedHost=a.host;this.connectedPort=a.port;this.ws.binaryType="arraybuffer";this.elementReader=new BinaryXmlElementReader(a);var c=this;this.ws.onmessage=function(a){a=a.data;if(null==a||void 0==a||""==a)console.log("INVALID ANSWER");else if(a instanceof ArrayBuffer){a=new Uint8Array(a);3<LOG&&console.log("BINARY RESPONSE IS "+
+DataUtils.toHex(a));try{c.elementReader.onReceivedData(a)}catch(b){console.log("NDN.ws.onmessage exception: "+b)}}};this.ws.onopen=function(a){3<LOG&&console.log(a);3<LOG&&console.log("ws.onopen: WebSocket connection opened.");3<LOG&&console.log("ws.onopen: ReadyState: "+this.readyState);b()};this.ws.onerror=function(a){console.log("ws.onerror: ReadyState: "+this.readyState);console.log(a);console.log("ws.onerror: WebSocket error: "+a.data)};this.ws.onclose=function(){console.log("ws.onclose: WebSocket connection closed.");
+c.ws=null;a.readyStatus=NDN.CLOSED;a.onclose()}};WebSocketTransport.prototype.send=function(a){if(null!=this.ws){var b=new Uint8Array(a.length);b.set(a);this.ws.send(b.buffer);3<LOG&&console.log("ws.send() returned.")}else console.log("WebSocket connection is not established.")};
+WebSocketTransport.prototype.expressInterest=function(a,b,c){if(null==this.ws||this.connectedHost!=a.host||this.connectedPort!=a.port){var d=this;this.connect(a,function(){d.expressInterestHelper(a,b,c)})}else this.expressInterestHelper(a,b,c)};
+WebSocketTransport.prototype.expressInterestHelper=function(a,b,c){if(null!=c){var d=new PITEntry(b,c);NDN.PITTable.push(d);c.pitEntry=d}null!=c&&(d.timerID=setTimeout(function(){3<LOG&&console.log("Interest time out.");var e=NDN.PITTable.indexOf(d);0<=e&&NDN.PITTable.splice(e,1);c.upcall(Closure.UPCALL_INTEREST_TIMED_OUT,new UpcallInfo(a,b,0,null))},b.interestLifetime));this.send(encodeToBinaryInterest(b))};
var CCNProtocolDTags={Any:13,Name:14,Component:15,Certificate:16,Collection:17,CompleteName:18,Content:19,SignedInfo:20,ContentDigest:21,ContentHash:22,Count:24,Header:25,Interest:26,Key:27,KeyLocator:28,KeyName:29,Length:30,Link:31,LinkAuthenticator:32,NameComponentCount:33,RootDigest:36,Signature:37,Start:38,Timestamp:39,Type:40,Nonce:41,Scope:42,Exclude:43,Bloom:44,BloomSeed:45,AnswerOriginKind:47,InterestLifetime:48,Witness:53,SignatureBits:54,DigestAlgorithm:55,BlockSize:56,FreshnessSeconds:58,
FinalBlockID:59,PublisherPublicKeyDigest:60,PublisherCertificateDigest:61,PublisherIssuerKeyDigest:62,PublisherIssuerCertificateDigest:63,ContentObject:64,WrappedKey:65,WrappingKeyIdentifier:66,WrapAlgorithm:67,KeyAlgorithm:68,Label:69,EncryptedKey:70,EncryptedNonceKey:71,WrappingKeyName:72,Action:73,FaceID:74,IPProto:75,Host:76,Port:77,MulticastInterface:78,ForwardingFlags:79,FaceInstance:80,ForwardingEntry:81,MulticastTTL:82,MinSuffixComponents:83,MaxSuffixComponents:84,ChildSelector:85,RepositoryInfo:86,
Version:87,RepositoryVersion:88,GlobalPrefix:89,LocalName:90,Policy:91,Namespace:92,GlobalPrefixName:93,PolicyVersion:94,KeyValueSet:95,KeyValuePair:96,IntegerValue:97,DecimalValue:98,StringValue:99,BinaryValue:100,NameValue:101,Entry:102,ACL:103,ParameterizedName:104,Prefix:105,Suffix:106,Root:107,ProfileName:108,Parameters:109,InfoString:110,StatusResponse:112,StatusCode:113,StatusText:114,SyncNode:115,SyncNodeKind:116,SyncNodeElement:117,SyncVersion:118,SyncNodeElements:119,SyncContentHash:120,
@@ -250,24 +251,27 @@
BigInteger.prototype.millerRabin=bnpMillerRabin;BigInteger.prototype.clone=bnClone;BigInteger.prototype.intValue=bnIntValue;BigInteger.prototype.byteValue=bnByteValue;BigInteger.prototype.shortValue=bnShortValue;BigInteger.prototype.signum=bnSigNum;BigInteger.prototype.toByteArray=bnToByteArray;BigInteger.prototype.equals=bnEquals;BigInteger.prototype.min=bnMin;BigInteger.prototype.max=bnMax;BigInteger.prototype.and=bnAnd;BigInteger.prototype.or=bnOr;BigInteger.prototype.xor=bnXor;
BigInteger.prototype.andNot=bnAndNot;BigInteger.prototype.not=bnNot;BigInteger.prototype.shiftLeft=bnShiftLeft;BigInteger.prototype.shiftRight=bnShiftRight;BigInteger.prototype.getLowestSetBit=bnGetLowestSetBit;BigInteger.prototype.bitCount=bnBitCount;BigInteger.prototype.testBit=bnTestBit;BigInteger.prototype.setBit=bnSetBit;BigInteger.prototype.clearBit=bnClearBit;BigInteger.prototype.flipBit=bnFlipBit;BigInteger.prototype.add=bnAdd;BigInteger.prototype.subtract=bnSubtract;
BigInteger.prototype.multiply=bnMultiply;BigInteger.prototype.divide=bnDivide;BigInteger.prototype.remainder=bnRemainder;BigInteger.prototype.divideAndRemainder=bnDivideAndRemainder;BigInteger.prototype.modPow=bnModPow;BigInteger.prototype.modInverse=bnModInverse;BigInteger.prototype.pow=bnPow;BigInteger.prototype.gcd=bnGCD;BigInteger.prototype.isProbablePrime=bnIsProbablePrime;
-var LOG=0,NDN=function NDN(b){b=b||{};this.transport=(b.getTransport||function(){return new WebSocketTransport})();this.getHostAndPort=b.getHostAndPort||this.transport.defaultGetHostAndPort;this.host=void 0!==b.host?b.host:"localhost";this.port=b.port||9696;this.readyStatus=NDN.UNOPEN;this.verify=void 0!==b.verify?b.verify:!0;this.onopen=b.onopen||function(){3<LOG&&console.log("NDN connection established.")};this.onclose=b.onclose||function(){3<LOG&&console.log("NDN connection closed.")};this.ccndid=
-null};NDN.UNOPEN=0;NDN.OPENED=1;NDN.CLOSED=2;NDN.ccndIdFetcher=new Name("/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY");NDN.prototype.createRoute=function(a,b){this.host=a;this.port=b};NDN.KeyStore=[];var KeyStoreEntry=function(a,b,c){this.keyName=a;this.rsaKey=b;this.timeStamp=c};NDN.addKeyEntry=function(a){null==NDN.getKeyByName(a.keyName)&&NDN.KeyStore.push(a)};
+var LOG=0,NDN=function NDN(b){b=b||{};this.transport=(b.getTransport||function(){return new WebSocketTransport})();this.getHostAndPort=b.getHostAndPort||this.transport.defaultGetHostAndPort;this.host=void 0!==b.host?b.host:null;this.port=b.port||9696;this.readyStatus=NDN.UNOPEN;this.verify=void 0!==b.verify?b.verify:!0;this.onopen=b.onopen||function(){3<LOG&&console.log("NDN connection established.")};this.onclose=b.onclose||function(){3<LOG&&console.log("NDN connection closed.")};this.ccndid=null};
+NDN.UNOPEN=0;NDN.OPENED=1;NDN.CLOSED=2;NDN.ccndIdFetcher=new Name("/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY");NDN.prototype.createRoute=function(a,b){this.host=a;this.port=b};NDN.KeyStore=[];var KeyStoreEntry=function(a,b,c){this.keyName=a;this.rsaKey=b;this.timeStamp=c};NDN.addKeyEntry=function(a){null==NDN.getKeyByName(a.keyName)&&NDN.KeyStore.push(a)};
NDN.getKeyByName=function(a){for(var b=null,c=0;c<NDN.KeyStore.length;c++)if(NDN.KeyStore[c].keyName.contentName.match(a.contentName)&&(null==b||NDN.KeyStore[c].keyName.contentName.components.length>b.keyName.contentName.components.length))b=NDN.KeyStore[c];return b};NDN.PITTable=[];var PITEntry=function(a,b){this.interest=a;this.closure=b;this.timerID=-1};
NDN.getEntryForExpressedInterest=function(a){for(var b=null,c=0;c<NDN.PITTable.length;c++)if(NDN.PITTable[c].interest.matches_name(a)&&(null==b||NDN.PITTable[c].interest.name.components.length>b.interest.name.components.length))b=NDN.PITTable[c];return b};NDN.CSTable=[];var CSEntry=function(a,b){this.name=a;this.closure=b};function getEntryForRegisteredPrefix(a){for(var b=0;b<NDN.CSTable.length;b++)if(null!=NDN.CSTable[b].name.match(a))return NDN.CSTable[b];return null}
NDN.makeShuffledGetHostAndPort=function(a,b){a=a.slice(0,a.length);DataUtils.shuffle(a);return function(){return 0==a.length?null:{host:a.splice(0,1)[0],port:b}}};
NDN.prototype.expressInterest=function(a,b,c){var d=new Interest(a);null!=c?(d.minSuffixComponents=c.minSuffixComponents,d.maxSuffixComponents=c.maxSuffixComponents,d.publisherPublicKeyDigest=c.publisherPublicKeyDigest,d.exclude=c.exclude,d.childSelector=c.childSelector,d.answerOriginKind=c.answerOriginKind,d.scope=c.scope,d.interestLifetime=c.interestLifetime):d.interestLifetime=4E3;if(null==this.host||null==this.port)if(null==this.getHostAndPort)console.log("ERROR: host OR port NOT SET");else{var e=
this;this.connectAndExecute(function(){e.transport.expressInterest(e,d,b)})}else this.transport.expressInterest(this,d,b)};
-NDN.prototype.registerPrefix=function(a,b){if(this.readyStatus!=NDN.OPENED)return console.log("Connection is not established."),-1;if(null==this.ccndid)return console.log("ccnd node ID unkonwn. Cannot register prefix."),-1;var c=new ForwardingEntry("selfreg",a,null,null,3,2147483647),c=encodeForwardingEntry(c),d=new SignedInfo;d.setFields();c=new ContentObject(new Name,d,c,new Signature);c.sign();c=encodeToBinaryContentObject(c);c=new Name(["ccnx",this.ccndid,"selfreg",c]);c=new Interest(c);c.scope=
-1;3<LOG&&console.log("Send Interest registration packet.");d=new CSEntry(a.getName(),b);NDN.CSTable.push(d);this.transport.send(encodeToBinaryInterest(c));return 0};
+NDN.prototype.registerPrefix=function(a,b,c){var d=this,e=function(){if(null==d.ccndid){var e=new Interest(NDN.ccndIdFetcher);e.interestLifetime=4E3;3<LOG&&console.log("Expressing interest for ccndid from ccnd.");d.transport.expressInterest(d,e,new NDN.FetchCcndidClosure(d,a,b,c))}else d.registerPrefixHelper(a,b,c)};null==this.host||null==this.port?null==this.getHostAndPort?console.log("ERROR: host OR port NOT SET"):this.connectAndExecute(e):e()};
+NDN.FetchCcndidClosure=function(a,b,c,d){Closure.call(this);this.ndn=a;this.name=b;this.callerClosure=c;this.flag=d};
+NDN.FetchCcndidClosure.prototype.upcall=function(a,b){if(a==Closure.UPCALL_INTEREST_TIMED_OUT)return console.log("Timeout while requesting the ccndid. Cannot registerPrefix for "+this.name.to_uri()+" ."),Closure.RESULT_OK;if(!(a==Closure.UPCALL_CONTENT||a==Closure.UPCALL_CONTENT_UNVERIFIED))return Closure.RESULT_ERR;var c=b.contentObject;!c.signedInfo||!c.signedInfo.publisher||!c.signedInfo.publisher.publisherPublicKeyDigest?console.log("ContentObject doesn't have a publisherPublicKeyDigest. Cannot set ccndid and registerPrefix for "+
+this.name.to_uri()+" ."):(3<LOG&&console.log("Got ccndid from ccnd."),this.ndn.ccndid=c.signedInfo.publisher.publisherPublicKeyDigest,3<LOG&&console.log(this.ndn.ccndid),this.ndn.registerPrefixHelper(this.name,this.callerClosure,this.flag));return Closure.RESULT_OK};
+NDN.prototype.registerPrefixHelper=function(a,b){var c=new ForwardingEntry("selfreg",a,null,null,3,2147483647),c=encodeForwardingEntry(c),d=new SignedInfo;d.setFields();c=new ContentObject(new Name,d,c,new Signature);c.sign();c=encodeToBinaryContentObject(c);c=new Name(["ccnx",this.ccndid,"selfreg",c]);c=new Interest(c);c.scope=1;3<LOG&&console.log("Send Interest registration packet.");d=new CSEntry(a.getName(),b);NDN.CSTable.push(d);this.transport.send(encodeToBinaryInterest(c))};
NDN.prototype.onReceivedElement=function(a){3<LOG&&console.log("Complete element received. Length "+a.length+". Start decoding.");var b=new BinaryXMLDecoder(a);if(b.peekStartElement(CCNProtocolDTags.Interest))3<LOG&&console.log("Interest packet received."),a=new Interest,a.from_ccnb(b),3<LOG&&console.log(a),b=escape(a.name.getName()),3<LOG&&console.log(b),b=getEntryForRegisteredPrefix(b),null!=b&&(a=new UpcallInfo(this,a,0,null),b.closure.upcall(Closure.UPCALL_INTEREST,a)==Closure.RESULT_INTEREST_CONSUMED&&
-null!=a.contentObject&&this.transport.send(encodeToBinaryContentObject(a.contentObject)));else if(b.peekStartElement(CCNProtocolDTags.ContentObject))if(3<LOG&&console.log("ContentObject packet received."),a=new ContentObject,a.from_ccnb(b),null==this.ccndid&&NDN.ccndIdFetcher.match(a.name))!a.signedInfo||!a.signedInfo.publisher||!a.signedInfo.publisher.publisherPublicKeyDigest?(console.log("Cannot contact router, close NDN now."),this.readyStatus=NDN.CLOSED,this.onclose()):(3<LOG&&console.log("Connected to ccnd."),
-this.ccndid=a.signedInfo.publisher.publisherPublicKeyDigest,3<LOG&&console.log(ndn.ccndid),this.readyStatus=NDN.OPENED,this.onopen());else{var c=NDN.getEntryForExpressedInterest(a.name);if(null!=c)if(b=NDN.PITTable.indexOf(c),0<=b&&NDN.PITTable.splice(b,1),b=c.closure,clearTimeout(c.timerID),!1==this.verify)b.upcall(Closure.UPCALL_CONTENT_UNVERIFIED,new UpcallInfo(this,null,0,a));else{var d=function(a,b,c,d,e){this.contentObject=a;this.closure=b;this.keyName=c;this.sigHex=d;this.witness=e;Closure.call(this)},
-e=this;d.prototype.upcall=function(a,b){if(a==Closure.UPCALL_INTEREST_TIMED_OUT)console.log("In KeyFetchClosure.upcall: interest time out."),console.log(this.keyName.contentName.getName());else if(a==Closure.UPCALL_CONTENT){var c=decodeSubjectPublicKeyInfo(b.contentObject.content),d=!0==c.verifyByteArray(this.contentObject.rawSignatureData,this.witness,this.sigHex)?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD;this.closure.upcall(d,new UpcallInfo(e,null,0,this.contentObject));c=new KeyStoreEntry(g.keyName,
-c,(new Date).getTime());NDN.addKeyEntry(c)}else a==Closure.UPCALL_CONTENT_BAD&&console.log("In KeyFetchClosure.upcall: signature verification failed")};if(a.signedInfo&&a.signedInfo.locator&&a.signature){3<LOG&&console.log("Key verification...");var c=DataUtils.toHex(a.signature.signature).toLowerCase(),f=null;null!=a.signature.Witness&&(f=new Witness,f.decode(a.signature.Witness));var g=a.signedInfo.locator;if(g.type==KeyLocatorType.KEYNAME)if(3<LOG&&console.log("KeyLocator contains KEYNAME"),g.keyName.contentName.match(a.name))3<
-LOG&&console.log("Content is key itself"),d=decodeSubjectPublicKeyInfo(a.content),c=d.verifyByteArray(a.rawSignatureData,f,c),c=!0==c?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD,b.upcall(c,new UpcallInfo(this,null,0,a));else{var j=NDN.getKeyByName(g.keyName);j?(3<LOG&&console.log("Local key cache hit"),d=j.rsaKey,c=d.verifyByteArray(a.rawSignatureData,f,c),c=!0==c?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD,b.upcall(c,new UpcallInfo(this,null,0,a))):(3<LOG&&console.log("Fetch key according to keylocator"),
-a=new d(a,b,g.keyName,c,f),this.expressInterest(g.keyName.contentName.getPrefix(4),a))}else g.type==KeyLocatorType.KEY?(3<LOG&&console.log("Keylocator contains KEY"),d=decodeSubjectPublicKeyInfo(a.signedInfo.locator.publicKey),c=d.verifyByteArray(a.rawSignatureData,f,c),c=!0==c?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD,b.upcall(Closure.UPCALL_CONTENT,new UpcallInfo(this,null,0,a))):(a=g.certificate,console.log("KeyLocator contains CERT"),console.log(a))}}}else console.log("Incoming packet is not Interest or ContentObject. Discard now.")};
+null!=a.contentObject&&this.transport.send(encodeToBinaryContentObject(a.contentObject)));else if(b.peekStartElement(CCNProtocolDTags.ContentObject)){3<LOG&&console.log("ContentObject packet received.");a=new ContentObject;a.from_ccnb(b);var c=NDN.getEntryForExpressedInterest(a.name);if(null!=c)if(b=NDN.PITTable.indexOf(c),0<=b&&NDN.PITTable.splice(b,1),b=c.closure,clearTimeout(c.timerID),!1==this.verify)b.upcall(Closure.UPCALL_CONTENT_UNVERIFIED,new UpcallInfo(this,null,0,a));else{var d=function(a,
+b,c,d,e){this.contentObject=a;this.closure=b;this.keyName=c;this.sigHex=d;this.witness=e;Closure.call(this)},e=this;d.prototype.upcall=function(a,b){if(a==Closure.UPCALL_INTEREST_TIMED_OUT)console.log("In KeyFetchClosure.upcall: interest time out."),console.log(this.keyName.contentName.getName());else if(a==Closure.UPCALL_CONTENT){var c=decodeSubjectPublicKeyInfo(b.contentObject.content),d=!0==c.verifyByteArray(this.contentObject.rawSignatureData,this.witness,this.sigHex)?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD;
+this.closure.upcall(d,new UpcallInfo(e,null,0,this.contentObject));c=new KeyStoreEntry(g.keyName,c,(new Date).getTime());NDN.addKeyEntry(c)}else a==Closure.UPCALL_CONTENT_BAD&&console.log("In KeyFetchClosure.upcall: signature verification failed")};if(a.signedInfo&&a.signedInfo.locator&&a.signature){3<LOG&&console.log("Key verification...");var c=DataUtils.toHex(a.signature.signature).toLowerCase(),f=null;null!=a.signature.Witness&&(f=new Witness,f.decode(a.signature.Witness));var g=a.signedInfo.locator;
+if(g.type==KeyLocatorType.KEYNAME)if(3<LOG&&console.log("KeyLocator contains KEYNAME"),g.keyName.contentName.match(a.name))3<LOG&&console.log("Content is key itself"),d=decodeSubjectPublicKeyInfo(a.content),c=d.verifyByteArray(a.rawSignatureData,f,c),c=!0==c?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD,b.upcall(c,new UpcallInfo(this,null,0,a));else{var j=NDN.getKeyByName(g.keyName);j?(3<LOG&&console.log("Local key cache hit"),d=j.rsaKey,c=d.verifyByteArray(a.rawSignatureData,f,c),c=!0==c?Closure.UPCALL_CONTENT:
+Closure.UPCALL_CONTENT_BAD,b.upcall(c,new UpcallInfo(this,null,0,a))):(3<LOG&&console.log("Fetch key according to keylocator"),a=new d(a,b,g.keyName,c,f),this.expressInterest(g.keyName.contentName.getPrefix(4),a))}else g.type==KeyLocatorType.KEY?(3<LOG&&console.log("Keylocator contains KEY"),d=decodeSubjectPublicKeyInfo(a.signedInfo.locator.publicKey),c=d.verifyByteArray(a.rawSignatureData,f,c),c=!0==c?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD,b.upcall(Closure.UPCALL_CONTENT,new UpcallInfo(this,
+null,0,a))):(a=g.certificate,console.log("KeyLocator contains CERT"),console.log(a))}}}else console.log("Incoming packet is not Interest or ContentObject. Discard now.")};
NDN.prototype.connectAndExecute=function(a){var b=this.getHostAndPort();if(null==b)console.log("ERROR: No more hosts from getHostAndPort"),this.host=null;else if(b.host==this.host&&b.port==this.port)console.log("ERROR: The host returned by getHostAndPort is not alive: "+this.host+":"+this.port);else{this.host=b.host;this.port=b.port;3<LOG&&console.log("Connect: trying host from getHostAndPort: "+this.host);b=new Interest(new Name("/"));b.interestLifetime=4E3;var c=this,d=setTimeout(function(){3<LOG&&
-console.log("Connect: timeout waiting for host "+c.host);c.connectAndExecute(a)},3E3);this.transport.expressInterest(this,b,new NDN.ConnectClosure(this,a,d))}};NDN.ConnectClosure=function(a,b,c){Closure.call(this);this.ndn=a;this.onConnected=b;this.timerID=c};NDN.ConnectClosure.prototype.upcall=function(a){if(!(a==Closure.UPCALL_CONTENT||a==Closure.UPCALL_CONTENT_UNVERIFIED))return Closure.RESULT_ERR;clearTimeout(this.timerID);this.onConnected();return Closure.RESULT_OK};
+console.log("Connect: timeout waiting for host "+c.host);c.connectAndExecute(a)},3E3);this.transport.expressInterest(this,b,new NDN.ConnectClosure(this,a,d))}};NDN.ConnectClosure=function(a,b,c){Closure.call(this);this.ndn=a;this.onConnected=b;this.timerID=c};NDN.ConnectClosure.prototype.upcall=function(a){if(!(a==Closure.UPCALL_CONTENT||a==Closure.UPCALL_CONTENT_UNVERIFIED))return Closure.RESULT_ERR;clearTimeout(this.timerID);this.ndn.readyStatus=NDN.OPENED;this.ndn.onopen();this.onConnected();return Closure.RESULT_OK};
var BinaryXmlElementReader=function(a){this.elementListener=a;this.dataParts=[];this.structureDecoder=new BinaryXMLStructureDecoder};
BinaryXmlElementReader.prototype.onReceivedData=function(a){for(;;)if(this.structureDecoder.seek(0),this.structureDecoder.findElementEnd(a)){if(this.dataParts.push(a.subarray(0,this.structureDecoder.offset)),this.elementListener.onReceivedElement(DataUtils.concatArrays(this.dataParts)),a=a.subarray(this.structureDecoder.offset,a.length),this.dataParts=[],this.structureDecoder=new BinaryXMLStructureDecoder,0==a.length)break}else{this.dataParts.push(a);3<LOG&&console.log("Incomplete packet received. Length "+
a.length+". Wait for more input.");break}};