blob: 83f53d9be2d3cd0c5dbed5ed33eb55dd2b25203a [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);
28 console.log('ws.send() returned.');
29 }
30 else{
31 console.log('WebSocket connection is not established.');
32 return null;
33 }
34};
35
36
37var ccndIdFetcher = '/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY';
38
39WebSocketTransport.prototype.connectWebSocket = function(ndn) {
40 if (this.ws != null)
41 delete this.ws;
42
43 this.ws = new WebSocket('ws://' + ndn.host + ':' + ndn.port);
44 console.log('ws connection created.');
45
46 this.ws.binaryType = "arraybuffer";
47
48 var self = this;
49 this.ws.onmessage = function(ev) {
50 var result = ev.data;
51 //console.log('RecvHandle called.');
52
53 if(result == null || result == undefined || result == "" ) {
54 console.log('INVALID ANSWER');
55 } else if (result instanceof ArrayBuffer) {
56 var bytearray = new Uint8Array(result);
57
58 if (LOG>3) console.log('BINARY RESPONSE IS ' + bytearray);
59
60 try {
61 if (bytearray.length + self.buffer.byteOffset >= self.buffer.byteLength) {
62 console.log("NDN.ws.onmessage: buffer overflow. Accumulate received length: " + self.buffer.byteOffset
63 + ". Current packet length: " + bytearray.length + ".");
64 // Purge and quit.
65 delete self.structureDecoder;
66 delete self.buffer;
67 self.structureDecoder = new BinaryXMLStructureDecoder();
68 self.buffer = new Uint8Array(self.maxBufferSize);
69 return;
70 }
71
72 /*for (var i = 0; i < bytearray.length; i++) {
73 self.buffer.push(bytearray[i]);
74 }*/
75 self.buffer.set(bytearray, self.buffer.byteOffset);
76
77 if (!self.structureDecoder.findElementEnd(self.buffer)) {
78 // Need more data to decode
79 console.log('Incomplete packet received. Length ' + bytearray.length + '. Wait for more input.');
80 console.log('self.buffer length: ' + self.buffer.length);
81 return;
82 }
83 } catch (ex) {
84 console.log("NDN.ws.onmessage exception: " + ex);
85 return;
86 }
87
88 var decoder = new BinaryXMLDecoder(self.buffer);
89 // Dispatch according to packet type
90 if (decoder.peekStartElement(CCNProtocolDTags.Interest)) { // Interest packet
91 console.log('Interest packet received.');
92
93 var interest = new Interest();
94 interest.from_ccnb(decoder);
95 if (LOG>3) console.log(interest);
96 var nameStr = escape(interest.name.getName());
97 console.log(nameStr);
98
99 var entry = getEntryForRegisteredPrefix(nameStr);
100 if (entry != null) {
101 //console.log(entry);
102 entry.closure.upcall(Closure.UPCALL_INTEREST, new UpcallInfo(ndn, interest, 0, null));
103 }
104
105 } else if (decoder.peekStartElement(CCNProtocolDTags.ContentObject)) { // Content packet
106 console.log('ContentObject packet received.');
107
108 var co = new ContentObject();
109 co.from_ccnb(decoder);
110 if (LOG>3) console.log(co);
111 nameStr = co.name.getName();
112 console.log(nameStr);
113
114 if (self.ccndid == null && nameStr.match(ccndIdFetcher) != null) {
115 // We are in starting phase, record publisherPublicKeyDigest in self.ccndid
116 if(!co.signedInfo || !co.signedInfo.publisher
117 || !co.signedInfo.publisher.publisherPublicKeyDigest) {
118 console.log("Cannot contact router");
119 } else {
120 console.log('Connected to ccnd.');
121 self.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
122 if (LOG>3) console.log(self.ccndid);
123 }
124 } else {
125 var pitEntry = getEntryForExpressedInterest(nameStr);
126 if (pitEntry != null) {
127 //console.log(pitEntry);
128 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) {
146 console.log(ev);
147 console.log('ws.onopen: WebSocket connection opened.');
148 console.log('ws.onopen: ReadyState: ' + this.readyState);
149
150 // Fetch ccndid now
151 interest = new Interest(new Name(ccndIdFetcher));
152 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;
175 }
176}
177
178
179// For fetching data
180var PITTable = new Array();
181
182var PITEntry = function PITEntry(interest, closure) {
183 this.interest = interest; // String
184 this.closure = closure; // Closure
185}
186
187function getEntryForExpressedInterest(name) {
188 for (var i = 0; i < PITTable.length; i++) {
189 if (name.match(PITTable[i].interest) != null)
190 return PITTable[i];
191 // TODO: handle multiple matching prefixes
192 }
193 return null;
194}
195
196
197// For publishing data
198var CSTable = new Array();
199
200var CSEntry = function CSEntry(name, closure) {
201 this.name = name; // String
202 this.closure = closure; // Closure
203}
204
205function getEntryForRegisteredPrefix(name) {
206 for (var i = 0; i < CSTable.length; i++) {
207 if (CSTable[i].name.match(name) != null)
208 return CSTable[i];
209 }
210 return null;
211}
212
213WebSocketTransport.prototype.registerPrefix = function(ndn, name, closure, flag) {
214 if (this.ws != null) {
215 if (this.ccndid == null) {
216 console.log('ccnd node ID unkonwn. Cannot register prefix.');
217 return;
218 }
219
Jeff Thompson48ba4ff2012-11-12 01:23:13 -0800220 var fe = new ForwardingEntry('selfreg', name, null, null, 3, 2147483647);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800221 var bytes = encodeForwardingEntry(fe);
222
223 var si = new SignedInfo();
224 si.setFields();
225
226 var co = new ContentObject(new Name(), si, bytes, new Signature());
227 co.sign();
228 var coBinary = encodeToBinaryContentObject(co);
229
230 //var ccnxnodename = 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');
231 var ccnxnodename = this.ccndid;
232 var interestName = new Name(['ccnx', ccnxnodename, 'selfreg', coBinary]);
233
234 var interest = new Interest(interestName);
235 interest.scope = 1;
236 //var hex = encodeToHexInterest(int);
237 var binaryInterest = encodeToBinaryInterest(interest);
Wentao Shangc05dc532012-11-19 12:00:33 -0800238 // If we directly use binaryInterest.buffer to feed ws.send(),
239 // WebSocket will end up sending a packet with 10000 bytes of data.
240 // That is, WebSocket will flush the entire buffer in BinaryXMLEncoder
241 // regardless of the offset of the Uint8Array. So we have to create
242 // a new Uint8Array buffer with just the right size and copy the
243 // content from binaryInterest to the new buffer.
244 // ---Wentao
Jeff Thompson5b265a72012-11-12 01:13:08 -0800245 var bytearray = new Uint8Array(binaryInterest.length);
246 bytearray.set(binaryInterest);
247 console.log('Send Interest registration packet.');
248
Jeff Thompson48ba4ff2012-11-12 01:23:13 -0800249 var csEntry = new CSEntry(name.getName(), closure);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800250 CSTable.push(csEntry);
251
252 this.ws.send(bytearray.buffer);
Jeff Thompson5b265a72012-11-12 01:13:08 -0800253
254 return 0;
255 } else {
256 console.log('WebSocket connection is not established.');
257 return -1;
258 }
259}
260