blob: 034e8b87defcf61b3b68134a4403f104c874db8d [file] [log] [blame]
Wentao Shangc0311e52012-12-03 10:38:23 -08001/**
Jeff Thompson5b265a72012-11-12 01:13:08 -08002 * @author: Wentao Shang
3 * See COPYING for copyright and distribution information.
4 * Implement getAsync and putAsync used by NDN using nsISocketTransportService.
5 * This is used inside Firefox XPCOM modules.
6 */
7
8var WebSocketTransport = function WebSocketTransport() {
9 this.ws = null;
10 this.ccndid = null;
11 this.maxBufferSize = 10000; // Currently support 10000 bytes data input, consistent with BinaryXMLEncoder
12 this.buffer = new Uint8Array(this.maxBufferSize);
13 this.structureDecoder = new BinaryXMLStructureDecoder();
14};
15
Jeff Thompson5b265a72012-11-12 01:13:08 -080016var ccndIdFetcher = '/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY';
17
18WebSocketTransport.prototype.connectWebSocket = function(ndn) {
19 if (this.ws != null)
20 delete this.ws;
21
22 this.ws = new WebSocket('ws://' + ndn.host + ':' + ndn.port);
Jeff Thompson3c263812012-12-01 17:20:28 -080023 if (LOG > 0) console.log('ws connection created.');
Jeff Thompson5b265a72012-11-12 01:13:08 -080024
25 this.ws.binaryType = "arraybuffer";
26
27 var self = this;
28 this.ws.onmessage = function(ev) {
29 var result = ev.data;
30 //console.log('RecvHandle called.');
31
32 if(result == null || result == undefined || result == "" ) {
33 console.log('INVALID ANSWER');
34 } else if (result instanceof ArrayBuffer) {
35 var bytearray = new Uint8Array(result);
36
Jeff Thompson13c2e7b2012-12-01 17:33:30 -080037 if (LOG>3) console.log('BINARY RESPONSE IS ' + DataUtils.toHex(bytearray));
Jeff Thompson5b265a72012-11-12 01:13:08 -080038
39 try {
40 if (bytearray.length + self.buffer.byteOffset >= self.buffer.byteLength) {
41 console.log("NDN.ws.onmessage: buffer overflow. Accumulate received length: " + self.buffer.byteOffset
42 + ". Current packet length: " + bytearray.length + ".");
43 // Purge and quit.
44 delete self.structureDecoder;
45 delete self.buffer;
46 self.structureDecoder = new BinaryXMLStructureDecoder();
47 self.buffer = new Uint8Array(self.maxBufferSize);
48 return;
49 }
50
51 /*for (var i = 0; i < bytearray.length; i++) {
52 self.buffer.push(bytearray[i]);
53 }*/
54 self.buffer.set(bytearray, self.buffer.byteOffset);
55
56 if (!self.structureDecoder.findElementEnd(self.buffer)) {
57 // Need more data to decode
58 console.log('Incomplete packet received. Length ' + bytearray.length + '. Wait for more input.');
59 console.log('self.buffer length: ' + self.buffer.length);
60 return;
61 }
62 } catch (ex) {
63 console.log("NDN.ws.onmessage exception: " + ex);
64 return;
65 }
66
67 var decoder = new BinaryXMLDecoder(self.buffer);
68 // Dispatch according to packet type
69 if (decoder.peekStartElement(CCNProtocolDTags.Interest)) { // Interest packet
Jeff Thompson3c263812012-12-01 17:20:28 -080070 if (LOG > 3) console.log('Interest packet received.');
Jeff Thompson5b265a72012-11-12 01:13:08 -080071
72 var interest = new Interest();
73 interest.from_ccnb(decoder);
74 if (LOG>3) console.log(interest);
75 var nameStr = escape(interest.name.getName());
Jeff Thompson3c263812012-12-01 17:20:28 -080076 if (LOG > 3) console.log(nameStr);
Jeff Thompson5b265a72012-11-12 01:13:08 -080077
78 var entry = getEntryForRegisteredPrefix(nameStr);
79 if (entry != null) {
80 //console.log(entry);
81 entry.closure.upcall(Closure.UPCALL_INTEREST, new UpcallInfo(ndn, interest, 0, null));
82 }
83
84 } else if (decoder.peekStartElement(CCNProtocolDTags.ContentObject)) { // Content packet
Jeff Thompson3c263812012-12-01 17:20:28 -080085 if (LOG > 3) console.log('ContentObject packet received.');
Jeff Thompson5b265a72012-11-12 01:13:08 -080086
87 var co = new ContentObject();
88 co.from_ccnb(decoder);
Jeff Thompson3c263812012-12-01 17:20:28 -080089 if (LOG > 3) console.log(co);
Jeff Thompson5b265a72012-11-12 01:13:08 -080090 nameStr = co.name.getName();
Jeff Thompson3c263812012-12-01 17:20:28 -080091 if (LOG > 3) console.log(nameStr);
Jeff Thompson5b265a72012-11-12 01:13:08 -080092
93 if (self.ccndid == null && nameStr.match(ccndIdFetcher) != null) {
94 // We are in starting phase, record publisherPublicKeyDigest in self.ccndid
95 if(!co.signedInfo || !co.signedInfo.publisher
96 || !co.signedInfo.publisher.publisherPublicKeyDigest) {
Wentao Shangaf25c6b2012-12-03 00:09:30 -080097 console.log("Cannot contact router, close NDN now.");
Wentao Shang0e291c82012-12-02 23:36:29 -080098
99 // Close NDN if we fail to connect to a ccn router
100 ndn.readyStatus = NDN.CLOSED;
101 ndn.onclose();
Wentao Shangaf25c6b2012-12-03 00:09:30 -0800102 //console.log("NDN.onclose event fired.");
Jeff Thompson5b265a72012-11-12 01:13:08 -0800103 } else {
Wentao Shangaf25c6b2012-12-03 00:09:30 -0800104 //console.log('Connected to ccnd.');
Jeff Thompson5b265a72012-11-12 01:13:08 -0800105 self.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
106 if (LOG>3) console.log(self.ccndid);
Wentao Shang0e291c82012-12-02 23:36:29 -0800107
108 // Call NDN.onopen after success
109 ndn.readyStatus = NDN.OPENED;
110 ndn.onopen();
Wentao Shangaf25c6b2012-12-03 00:09:30 -0800111 //console.log("NDN.onopen event fired.");
Jeff Thompson5b265a72012-11-12 01:13:08 -0800112 }
113 } else {
114 var pitEntry = getEntryForExpressedInterest(nameStr);
115 if (pitEntry != null) {
116 //console.log(pitEntry);
Wentao Shangc0311e52012-12-03 10:38:23 -0800117
118 // Cancel interest timer
119 clearTimeout(pitEntry.closure.timerID);
120 //console.log("Clear interest timer");
121 //console.log(pitEntry.closure.timerID);
Wentao Shangbd63e462012-12-03 16:19:33 -0800122
123 // Remove PIT entry from PITTable
124 index = PITTable.indexOf(pitEntry);
125 PITTable.splice(index, 1);
126
Wentao Shangc0311e52012-12-03 10:38:23 -0800127 // Raise callback
Jeff Thompson5b265a72012-11-12 01:13:08 -0800128 pitEntry.closure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(ndn, null, 0, co));
129 }
130 }
131 } else {
132 console.log('Incoming packet is not Interest or ContentObject. Discard now.');
133 }
134
135 delete decoder;
136
137 // Renew StrcutureDecoder and buffer after we process a full packet
138 delete self.structureDecoder;
139 delete self.buffer;
140 self.structureDecoder = new BinaryXMLStructureDecoder();
141 self.buffer = new Uint8Array(self.maxBufferSize);
142 }
143 }
144
145 this.ws.onopen = function(ev) {
Jeff Thompson3c263812012-12-01 17:20:28 -0800146 if (LOG > 3) console.log(ev);
147 if (LOG > 3) console.log('ws.onopen: WebSocket connection opened.');
148 if (LOG > 3) console.log('ws.onopen: ReadyState: ' + this.readyState);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800149
150 // Fetch ccndid now
Jeff Thompson3c263812012-12-01 17:20:28 -0800151 var interest = new Interest(new Name(ccndIdFetcher));
Jeff Thompson5b265a72012-11-12 01:13:08 -0800152 interest.InterestLifetime = 4200;
153 //var hex = encodeToHexInterest(interest);
154 var hex = encodeToBinaryInterest(interest);
155
156 /*var bytes = new Uint8Array(hex.length / 2);
157 for (var i = 0; i < hex.length; i = i + 2) {
158 bytes[i / 2] = '0x' + hex.substr(i, 2);
159 }*/
160 var bytes = new Uint8Array(hex.length);
161 bytes.set(hex);
162
163 self.ws.send(bytes.buffer);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800164 }
165
166 this.ws.onerror = function(ev) {
167 console.log('ws.onerror: ReadyState: ' + this.readyState);
168 console.log(ev);
169 console.log('ws.onerror: WebSocket error: ' + ev.data);
170 }
171
172 this.ws.onclose = function(ev) {
173 console.log('ws.onclose: WebSocket connection closed.');
174 self.ws = null;
Wentao Shang0e291c82012-12-02 23:36:29 -0800175
176 // Close NDN when WebSocket is closed
177 ndn.readyStatus = NDN.CLOSED;
178 ndn.onclose();
Wentao Shangaf25c6b2012-12-03 00:09:30 -0800179 //console.log("NDN.onclose event fired.");
Jeff Thompson5b265a72012-11-12 01:13:08 -0800180 }
181}
182
183
184// For fetching data
185var PITTable = new Array();
186
187var PITEntry = function PITEntry(interest, closure) {
188 this.interest = interest; // String
189 this.closure = closure; // Closure
190}
191
192function getEntryForExpressedInterest(name) {
193 for (var i = 0; i < PITTable.length; i++) {
194 if (name.match(PITTable[i].interest) != null)
195 return PITTable[i];
196 // TODO: handle multiple matching prefixes
197 }
198 return null;
199}
200
Wentao Shangc0311e52012-12-03 10:38:23 -0800201WebSocketTransport.prototype.expressInterest = function(ndn, interest, closure) {
202 if (this.ws != null) {
203 //TODO: check local content store first
204
205 var binaryInterest = encodeToBinaryInterest(interest);
206 var bytearray = new Uint8Array(binaryInterest.length);
207 bytearray.set(binaryInterest);
208
209 var pitEntry = new PITEntry(interest.name.getName(), closure);
210 PITTable.push(pitEntry);
211
212 this.ws.send(bytearray.buffer);
213 if (LOG > 3) console.log('ws.send() returned.');
214
215 // Set interest timer
216 closure.timerID = setTimeout(function() {
Wentao Shangbd63e462012-12-03 16:19:33 -0800217 if (LOG > 3) console.log("Interest time out.");
Wentao Shangc0311e52012-12-03 10:38:23 -0800218
219 // Remove PIT entry from PITTable
220 index = PITTable.indexOf(pitEntry);
221 //console.log(PITTable);
222 PITTable.splice(index, 1);
223 //console.log(PITTable);
224 // Raise closure callback
225 closure.upcall(Closure.UPCALL_INTEREST_TIMED_OUT, new UpcallInfo(ndn, interest, 0, null));
Wentao Shangbd63e462012-12-03 16:19:33 -0800226 }, interest.interestLifetime);
Wentao Shangc0311e52012-12-03 10:38:23 -0800227 //console.log(closure.timerID);
228 }
229 else
230 console.log('WebSocket connection is not established.');
231};
232
Jeff Thompson5b265a72012-11-12 01:13:08 -0800233
234// For publishing data
235var CSTable = new Array();
236
237var CSEntry = function CSEntry(name, closure) {
238 this.name = name; // String
239 this.closure = closure; // Closure
240}
241
242function getEntryForRegisteredPrefix(name) {
243 for (var i = 0; i < CSTable.length; i++) {
244 if (CSTable[i].name.match(name) != null)
245 return CSTable[i];
246 }
247 return null;
248}
249
250WebSocketTransport.prototype.registerPrefix = function(ndn, name, closure, flag) {
251 if (this.ws != null) {
252 if (this.ccndid == null) {
253 console.log('ccnd node ID unkonwn. Cannot register prefix.');
Jeff Thompson3c263812012-12-01 17:20:28 -0800254 return -1;
Jeff Thompson5b265a72012-11-12 01:13:08 -0800255 }
256
Jeff Thompson48ba4ff2012-11-12 01:23:13 -0800257 var fe = new ForwardingEntry('selfreg', name, null, null, 3, 2147483647);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800258 var bytes = encodeForwardingEntry(fe);
259
260 var si = new SignedInfo();
261 si.setFields();
262
263 var co = new ContentObject(new Name(), si, bytes, new Signature());
264 co.sign();
265 var coBinary = encodeToBinaryContentObject(co);
266
Jeff Thompsonbd829262012-11-30 22:28:37 -0800267 //var nodename = unescape('%00%88%E2%F4%9C%91%16%16%D6%21%8E%A0c%95%A5%A6r%11%E0%A0%82%89%A6%A9%85%AB%D6%E2%065%DB%AF');
268 var nodename = this.ccndid;
269 var interestName = new Name(['ccnx', nodename, 'selfreg', coBinary]);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800270
271 var interest = new Interest(interestName);
272 interest.scope = 1;
273 //var hex = encodeToHexInterest(int);
274 var binaryInterest = encodeToBinaryInterest(interest);
Wentao Shangc05dc532012-11-19 12:00:33 -0800275 // If we directly use binaryInterest.buffer to feed ws.send(),
276 // WebSocket will end up sending a packet with 10000 bytes of data.
277 // That is, WebSocket will flush the entire buffer in BinaryXMLEncoder
278 // regardless of the offset of the Uint8Array. So we have to create
279 // a new Uint8Array buffer with just the right size and copy the
280 // content from binaryInterest to the new buffer.
281 // ---Wentao
Jeff Thompson5b265a72012-11-12 01:13:08 -0800282 var bytearray = new Uint8Array(binaryInterest.length);
283 bytearray.set(binaryInterest);
Jeff Thompson3c263812012-12-01 17:20:28 -0800284 if (LOG > 3) console.log('Send Interest registration packet.');
Jeff Thompson5b265a72012-11-12 01:13:08 -0800285
Jeff Thompson48ba4ff2012-11-12 01:23:13 -0800286 var csEntry = new CSEntry(name.getName(), closure);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800287 CSTable.push(csEntry);
288
289 this.ws.send(bytearray.buffer);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800290
291 return 0;
292 } else {
293 console.log('WebSocket connection is not established.');
294 return -1;
295 }
296}
297