blob: 76c1c18d88606179885c29132e99e883165b99a0 [file] [log] [blame]
Jeff Thompson5b265a72012-11-12 01:13:08 -08001/*
2 * @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
16WebSocketTransport.prototype.expressInterest = function(ndn, interest, closure) {
17 if (this.ws != null) {
18 //TODO: check local content store first
19
20 var binaryInterest = encodeToBinaryInterest(interest);
21 var bytearray = new Uint8Array(binaryInterest.length);
22 bytearray.set(binaryInterest);
23
24 var pitEntry = new PITEntry(interest.name.getName(), closure);
25 PITTable.push(pitEntry);
26
27 this.ws.send(bytearray.buffer);
Jeff Thompson3c263812012-12-01 17:20:28 -080028 if (LOG > 3) console.log('ws.send() returned.');
Jeff Thompson5b265a72012-11-12 01:13:08 -080029 }
Jeff Thompson3c263812012-12-01 17:20:28 -080030 else
Jeff Thompson5b265a72012-11-12 01:13:08 -080031 console.log('WebSocket connection is not established.');
Jeff Thompson5b265a72012-11-12 01:13:08 -080032};
33
34
35var ccndIdFetcher = '/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY';
36
37WebSocketTransport.prototype.connectWebSocket = function(ndn) {
38 if (this.ws != null)
39 delete this.ws;
40
41 this.ws = new WebSocket('ws://' + ndn.host + ':' + ndn.port);
Jeff Thompson3c263812012-12-01 17:20:28 -080042 if (LOG > 0) console.log('ws connection created.');
Jeff Thompson5b265a72012-11-12 01:13:08 -080043
44 this.ws.binaryType = "arraybuffer";
45
46 var self = this;
47 this.ws.onmessage = function(ev) {
48 var result = ev.data;
49 //console.log('RecvHandle called.');
50
51 if(result == null || result == undefined || result == "" ) {
52 console.log('INVALID ANSWER');
53 } else if (result instanceof ArrayBuffer) {
54 var bytearray = new Uint8Array(result);
55
Jeff Thompson13c2e7b2012-12-01 17:33:30 -080056 if (LOG>3) console.log('BINARY RESPONSE IS ' + DataUtils.toHex(bytearray));
Jeff Thompson5b265a72012-11-12 01:13:08 -080057
58 try {
59 if (bytearray.length + self.buffer.byteOffset >= self.buffer.byteLength) {
60 console.log("NDN.ws.onmessage: buffer overflow. Accumulate received length: " + self.buffer.byteOffset
61 + ". Current packet length: " + bytearray.length + ".");
62 // Purge and quit.
63 delete self.structureDecoder;
64 delete self.buffer;
65 self.structureDecoder = new BinaryXMLStructureDecoder();
66 self.buffer = new Uint8Array(self.maxBufferSize);
67 return;
68 }
69
70 /*for (var i = 0; i < bytearray.length; i++) {
71 self.buffer.push(bytearray[i]);
72 }*/
73 self.buffer.set(bytearray, self.buffer.byteOffset);
74
75 if (!self.structureDecoder.findElementEnd(self.buffer)) {
76 // Need more data to decode
77 console.log('Incomplete packet received. Length ' + bytearray.length + '. Wait for more input.');
78 console.log('self.buffer length: ' + self.buffer.length);
79 return;
80 }
81 } catch (ex) {
82 console.log("NDN.ws.onmessage exception: " + ex);
83 return;
84 }
85
86 var decoder = new BinaryXMLDecoder(self.buffer);
87 // Dispatch according to packet type
88 if (decoder.peekStartElement(CCNProtocolDTags.Interest)) { // Interest packet
Jeff Thompson3c263812012-12-01 17:20:28 -080089 if (LOG > 3) console.log('Interest packet received.');
Jeff Thompson5b265a72012-11-12 01:13:08 -080090
91 var interest = new Interest();
92 interest.from_ccnb(decoder);
93 if (LOG>3) console.log(interest);
94 var nameStr = escape(interest.name.getName());
Jeff Thompson3c263812012-12-01 17:20:28 -080095 if (LOG > 3) console.log(nameStr);
Jeff Thompson5b265a72012-11-12 01:13:08 -080096
97 var entry = getEntryForRegisteredPrefix(nameStr);
98 if (entry != null) {
99 //console.log(entry);
100 entry.closure.upcall(Closure.UPCALL_INTEREST, new UpcallInfo(ndn, interest, 0, null));
101 }
102
103 } else if (decoder.peekStartElement(CCNProtocolDTags.ContentObject)) { // Content packet
Jeff Thompson3c263812012-12-01 17:20:28 -0800104 if (LOG > 3) console.log('ContentObject packet received.');
Jeff Thompson5b265a72012-11-12 01:13:08 -0800105
106 var co = new ContentObject();
107 co.from_ccnb(decoder);
Jeff Thompson3c263812012-12-01 17:20:28 -0800108 if (LOG > 3) console.log(co);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800109 nameStr = co.name.getName();
Jeff Thompson3c263812012-12-01 17:20:28 -0800110 if (LOG > 3) console.log(nameStr);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800111
112 if (self.ccndid == null && nameStr.match(ccndIdFetcher) != null) {
113 // We are in starting phase, record publisherPublicKeyDigest in self.ccndid
114 if(!co.signedInfo || !co.signedInfo.publisher
115 || !co.signedInfo.publisher.publisherPublicKeyDigest) {
116 console.log("Cannot contact router");
Wentao Shang0e291c82012-12-02 23:36:29 -0800117
118 // Close NDN if we fail to connect to a ccn router
119 ndn.readyStatus = NDN.CLOSED;
120 ndn.onclose();
121 console.log("NDN.onclose event fired.");
Jeff Thompson5b265a72012-11-12 01:13:08 -0800122 } else {
123 console.log('Connected to ccnd.');
124 self.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
125 if (LOG>3) console.log(self.ccndid);
Wentao Shang0e291c82012-12-02 23:36:29 -0800126
127 // Call NDN.onopen after success
128 ndn.readyStatus = NDN.OPENED;
129 ndn.onopen();
130 console.log("NDN.onopen event fired.");
Jeff Thompson5b265a72012-11-12 01:13:08 -0800131 }
132 } else {
133 var pitEntry = getEntryForExpressedInterest(nameStr);
134 if (pitEntry != null) {
135 //console.log(pitEntry);
136 pitEntry.closure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(ndn, null, 0, co));
137 }
138 }
139 } else {
140 console.log('Incoming packet is not Interest or ContentObject. Discard now.');
141 }
142
143 delete decoder;
144
145 // Renew StrcutureDecoder and buffer after we process a full packet
146 delete self.structureDecoder;
147 delete self.buffer;
148 self.structureDecoder = new BinaryXMLStructureDecoder();
149 self.buffer = new Uint8Array(self.maxBufferSize);
150 }
151 }
152
153 this.ws.onopen = function(ev) {
Jeff Thompson3c263812012-12-01 17:20:28 -0800154 if (LOG > 3) console.log(ev);
155 if (LOG > 3) console.log('ws.onopen: WebSocket connection opened.');
156 if (LOG > 3) console.log('ws.onopen: ReadyState: ' + this.readyState);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800157
158 // Fetch ccndid now
Jeff Thompson3c263812012-12-01 17:20:28 -0800159 var interest = new Interest(new Name(ccndIdFetcher));
Jeff Thompson5b265a72012-11-12 01:13:08 -0800160 interest.InterestLifetime = 4200;
161 //var hex = encodeToHexInterest(interest);
162 var hex = encodeToBinaryInterest(interest);
163
164 /*var bytes = new Uint8Array(hex.length / 2);
165 for (var i = 0; i < hex.length; i = i + 2) {
166 bytes[i / 2] = '0x' + hex.substr(i, 2);
167 }*/
168 var bytes = new Uint8Array(hex.length);
169 bytes.set(hex);
170
171 self.ws.send(bytes.buffer);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800172 }
173
174 this.ws.onerror = function(ev) {
175 console.log('ws.onerror: ReadyState: ' + this.readyState);
176 console.log(ev);
177 console.log('ws.onerror: WebSocket error: ' + ev.data);
178 }
179
180 this.ws.onclose = function(ev) {
181 console.log('ws.onclose: WebSocket connection closed.');
182 self.ws = null;
Wentao Shang0e291c82012-12-02 23:36:29 -0800183
184 // Close NDN when WebSocket is closed
185 ndn.readyStatus = NDN.CLOSED;
186 ndn.onclose();
187 console.log("NDN.onclose event fired.");
Jeff Thompson5b265a72012-11-12 01:13:08 -0800188 }
189}
190
191
192// For fetching data
193var PITTable = new Array();
194
195var PITEntry = function PITEntry(interest, closure) {
196 this.interest = interest; // String
197 this.closure = closure; // Closure
198}
199
200function getEntryForExpressedInterest(name) {
201 for (var i = 0; i < PITTable.length; i++) {
202 if (name.match(PITTable[i].interest) != null)
203 return PITTable[i];
204 // TODO: handle multiple matching prefixes
205 }
206 return null;
207}
208
209
210// For publishing data
211var CSTable = new Array();
212
213var CSEntry = function CSEntry(name, closure) {
214 this.name = name; // String
215 this.closure = closure; // Closure
216}
217
218function getEntryForRegisteredPrefix(name) {
219 for (var i = 0; i < CSTable.length; i++) {
220 if (CSTable[i].name.match(name) != null)
221 return CSTable[i];
222 }
223 return null;
224}
225
226WebSocketTransport.prototype.registerPrefix = function(ndn, name, closure, flag) {
227 if (this.ws != null) {
228 if (this.ccndid == null) {
229 console.log('ccnd node ID unkonwn. Cannot register prefix.');
Jeff Thompson3c263812012-12-01 17:20:28 -0800230 return -1;
Jeff Thompson5b265a72012-11-12 01:13:08 -0800231 }
232
Jeff Thompson48ba4ff2012-11-12 01:23:13 -0800233 var fe = new ForwardingEntry('selfreg', name, null, null, 3, 2147483647);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800234 var bytes = encodeForwardingEntry(fe);
235
236 var si = new SignedInfo();
237 si.setFields();
238
239 var co = new ContentObject(new Name(), si, bytes, new Signature());
240 co.sign();
241 var coBinary = encodeToBinaryContentObject(co);
242
Jeff Thompsonbd829262012-11-30 22:28:37 -0800243 //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');
244 var nodename = this.ccndid;
245 var interestName = new Name(['ccnx', nodename, 'selfreg', coBinary]);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800246
247 var interest = new Interest(interestName);
248 interest.scope = 1;
249 //var hex = encodeToHexInterest(int);
250 var binaryInterest = encodeToBinaryInterest(interest);
Wentao Shangc05dc532012-11-19 12:00:33 -0800251 // If we directly use binaryInterest.buffer to feed ws.send(),
252 // WebSocket will end up sending a packet with 10000 bytes of data.
253 // That is, WebSocket will flush the entire buffer in BinaryXMLEncoder
254 // regardless of the offset of the Uint8Array. So we have to create
255 // a new Uint8Array buffer with just the right size and copy the
256 // content from binaryInterest to the new buffer.
257 // ---Wentao
Jeff Thompson5b265a72012-11-12 01:13:08 -0800258 var bytearray = new Uint8Array(binaryInterest.length);
259 bytearray.set(binaryInterest);
Jeff Thompson3c263812012-12-01 17:20:28 -0800260 if (LOG > 3) console.log('Send Interest registration packet.');
Jeff Thompson5b265a72012-11-12 01:13:08 -0800261
Jeff Thompson48ba4ff2012-11-12 01:23:13 -0800262 var csEntry = new CSEntry(name.getName(), closure);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800263 CSTable.push(csEntry);
264
265 this.ws.send(bytearray.buffer);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800266
267 return 0;
268 } else {
269 console.log('WebSocket connection is not established.');
270 return -1;
271 }
272}
273