blob: 4ece337c03e2040bef72d2a9ac45cca45a9e3b92 [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");
117 } else {
118 console.log('Connected to ccnd.');
119 self.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
120 if (LOG>3) console.log(self.ccndid);
121 }
122 } else {
123 var pitEntry = getEntryForExpressedInterest(nameStr);
124 if (pitEntry != null) {
125 //console.log(pitEntry);
126 pitEntry.closure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(ndn, null, 0, co));
127 }
128 }
129 } else {
130 console.log('Incoming packet is not Interest or ContentObject. Discard now.');
131 }
132
133 delete decoder;
134
135 // Renew StrcutureDecoder and buffer after we process a full packet
136 delete self.structureDecoder;
137 delete self.buffer;
138 self.structureDecoder = new BinaryXMLStructureDecoder();
139 self.buffer = new Uint8Array(self.maxBufferSize);
140 }
141 }
142
143 this.ws.onopen = function(ev) {
Jeff Thompson3c263812012-12-01 17:20:28 -0800144 if (LOG > 3) console.log(ev);
145 if (LOG > 3) console.log('ws.onopen: WebSocket connection opened.');
146 if (LOG > 3) console.log('ws.onopen: ReadyState: ' + this.readyState);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800147
148 // Fetch ccndid now
Jeff Thompson3c263812012-12-01 17:20:28 -0800149 var interest = new Interest(new Name(ccndIdFetcher));
Jeff Thompson5b265a72012-11-12 01:13:08 -0800150 interest.InterestLifetime = 4200;
151 //var hex = encodeToHexInterest(interest);
152 var hex = encodeToBinaryInterest(interest);
153
154 /*var bytes = new Uint8Array(hex.length / 2);
155 for (var i = 0; i < hex.length; i = i + 2) {
156 bytes[i / 2] = '0x' + hex.substr(i, 2);
157 }*/
158 var bytes = new Uint8Array(hex.length);
159 bytes.set(hex);
160
161 self.ws.send(bytes.buffer);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800162 }
163
164 this.ws.onerror = function(ev) {
165 console.log('ws.onerror: ReadyState: ' + this.readyState);
166 console.log(ev);
167 console.log('ws.onerror: WebSocket error: ' + ev.data);
168 }
169
170 this.ws.onclose = function(ev) {
171 console.log('ws.onclose: WebSocket connection closed.');
172 self.ws = null;
173 }
174}
175
176
177// For fetching data
178var PITTable = new Array();
179
180var PITEntry = function PITEntry(interest, closure) {
181 this.interest = interest; // String
182 this.closure = closure; // Closure
183}
184
185function getEntryForExpressedInterest(name) {
186 for (var i = 0; i < PITTable.length; i++) {
187 if (name.match(PITTable[i].interest) != null)
188 return PITTable[i];
189 // TODO: handle multiple matching prefixes
190 }
191 return null;
192}
193
194
195// For publishing data
196var CSTable = new Array();
197
198var CSEntry = function CSEntry(name, closure) {
199 this.name = name; // String
200 this.closure = closure; // Closure
201}
202
203function getEntryForRegisteredPrefix(name) {
204 for (var i = 0; i < CSTable.length; i++) {
205 if (CSTable[i].name.match(name) != null)
206 return CSTable[i];
207 }
208 return null;
209}
210
211WebSocketTransport.prototype.registerPrefix = function(ndn, name, closure, flag) {
212 if (this.ws != null) {
213 if (this.ccndid == null) {
214 console.log('ccnd node ID unkonwn. Cannot register prefix.');
Jeff Thompson3c263812012-12-01 17:20:28 -0800215 return -1;
Jeff Thompson5b265a72012-11-12 01:13:08 -0800216 }
217
Jeff Thompson48ba4ff2012-11-12 01:23:13 -0800218 var fe = new ForwardingEntry('selfreg', name, null, null, 3, 2147483647);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800219 var bytes = encodeForwardingEntry(fe);
220
221 var si = new SignedInfo();
222 si.setFields();
223
224 var co = new ContentObject(new Name(), si, bytes, new Signature());
225 co.sign();
226 var coBinary = encodeToBinaryContentObject(co);
227
Jeff Thompsonbd829262012-11-30 22:28:37 -0800228 //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');
229 var nodename = this.ccndid;
230 var interestName = new Name(['ccnx', nodename, 'selfreg', coBinary]);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800231
232 var interest = new Interest(interestName);
233 interest.scope = 1;
234 //var hex = encodeToHexInterest(int);
235 var binaryInterest = encodeToBinaryInterest(interest);
Wentao Shangc05dc532012-11-19 12:00:33 -0800236 // If we directly use binaryInterest.buffer to feed ws.send(),
237 // WebSocket will end up sending a packet with 10000 bytes of data.
238 // That is, WebSocket will flush the entire buffer in BinaryXMLEncoder
239 // regardless of the offset of the Uint8Array. So we have to create
240 // a new Uint8Array buffer with just the right size and copy the
241 // content from binaryInterest to the new buffer.
242 // ---Wentao
Jeff Thompson5b265a72012-11-12 01:13:08 -0800243 var bytearray = new Uint8Array(binaryInterest.length);
244 bytearray.set(binaryInterest);
Jeff Thompson3c263812012-12-01 17:20:28 -0800245 if (LOG > 3) console.log('Send Interest registration packet.');
Jeff Thompson5b265a72012-11-12 01:13:08 -0800246
Jeff Thompson48ba4ff2012-11-12 01:23:13 -0800247 var csEntry = new CSEntry(name.getName(), closure);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800248 CSTable.push(csEntry);
249
250 this.ws.send(bytearray.buffer);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800251
252 return 0;
253 } else {
254 console.log('WebSocket connection is not established.');
255 return -1;
256 }
257}
258