blob: aa3d64fd8717f6d3a0b3131be653ceb70fa2e01a [file] [log] [blame]
Wentao Shangfcb16262013-01-20 14:42:46 -08001<?xml version = "1.0" encoding="utf-8" ?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3"DTD/xhtml1-strict.dtd">
4<html xmlns = "http://www.w3.org/1999/xhtml">
5<meta charset="UTF-8">
6
7<head>
8 <title>NDN Get File via WebSocket</title>
9
10 <script type="text/javascript" src="../tools/build/ndn-js.js"></script>
11
12 <script type="text/javascript">
13 //hostip = "131.179.196.232";
14 hostip = "localhost";
Wentao Shangd4607392013-01-24 23:08:49 -080015 //var ndncon = new NDN({port:9696,host:hostip});
16 var ndncon = new NDN({port:9696,host:hostip,verify:false});
Wentao Shangfcb16262013-01-20 14:42:46 -080017 ndncon.transport.connectWebSocket(ndncon);
18
19///////////////////////////////////////////////////////////////////////////////////////////////////////////
20 /*
21 * Closure for calling expressInterest to fetch big file.
22 */
23 var ContentClosure = function ContentClosure(ndn, T0) {
24 // Inherit from Closure.
25 Closure.call(this);
26
27 this.T0 = T0; // start time
28 this.ndn = ndn;
29 this.totalBlocks = 0; // total # of segments delivered to usr;
30 // TODO: in this test script we simply discard the content after it is received
31 // should consider some way to buffer the whole data in future refactor --- SWT
32
33 // We should always start with the first element so the first content object cannot be ooo data
34 //this.firstReceivedSegmentNumber = null;
35 //this.firstReceivedContentObject = null;
36
37 // statistic counters
38 this.ooo_count = 0; // out-of-order content object counter;
39 // when this counter reaches 3, apply fast retransmission alg.
40 this.pkt_recved = 0; // total # of content object received
41 this.timed_out = 0; // totle # of timed out interest
42 this.interest_sent = 1; // there is an initial interest before calling the closure upcall
43 this.dups = 0; // total # of dup content segments
44
45 this.max_window = 32; // max window size
46 this.max_retrans = 5; // max # of trial before give up; if we fail on one segment, the entire process is aborted
47
48 this.snd_una = 0; // pointer to unacked segments
49 this.snd_wnd = 1; // current window size
50 this.snd_nxt = 1; // pointer to next interest to be sent
51
52 this.ooo_table_size = 128;
53 this.ooo_table = []; // hash table to mark ooo segments
54
55 this.terminated = false; // Set this flag after we receive all the segments;
56 };
57
58 ContentClosure.prototype.upcall = function(kind, upcallInfo) {
59 this.pkt_recved++;
60
61 if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
62 if (this.terminated == false) {
63 this.timed_out++;
64
65 // Reduce window size to 1
66 this.snd_wnd = 1;
67
68 // Retransmit interest for this segment
69 this.ndn.expressInterest(upcallInfo.interest.name, this);
70 //console.log("Resend interest sent for " + upcallInfo.interest.name.getName());
71 document.getElementById('content').innerHTML += "<p>Resend interest sent for "
72 + upcallInfo.interest.name.getName() + "</p>";
73 this.interest_sent++;
74
75 document.getElementById('content').innerHTML += "<p>Interest " + upcallInfo.interest.name.getName() + " time out.</p>";
76 document.getElementById('content').innerHTML += "<p>Total number of blocks: " + this.totalBlocks + "</p>";
77 document.getElementById('content').innerHTML += "<p>Total number of packets: " + this.pkt_recved + "</p>";
78 document.getElementById('content').innerHTML += "<p>Total number of dup segments: " + this.dups + "</p>";
79 document.getElementById('content').innerHTML += "<p>Total number of interest sent: " + this.interest_sent + "</p>";
80 document.getElementById('content').innerHTML += "<p>Total number of time-out interest: " + this.timed_out + "</p>";
81
82 document.getElementById('content').innerHTML += "<p>SND_UNA: " + this.snd_una + "</p>";
83 document.getElementById('content').innerHTML += "<p>SND_WND: " + this.snd_wnd + "</p>";
84 document.getElementById('content').innerHTML += "<p>SND_NXT: " + this.snd_nxt + "</p>";
85 }
86 return Closure.RESULT_OK;
87 }
88
89 if (kind == Closure.UPCALL_CONTENT_BAD) {
90 console.log("NdnProtocol.ContentClosure: signature verification failed");
91 console.log(upcallInfo.contentObject.name.getName());
92 console.log(DataUtils.toHex(upcallInfo.contentObject.signature.Witness).toLowerCase());
93 return Closure.RESULT_OK;
94 }
95
96 if (!(kind == Closure.UPCALL_CONTENT ||
97 kind == Closure.UPCALL_CONTENT_UNVERIFIED))
98 // The upcall is not for us.
99 return Closure.RESULT_ERR;
100
101 var contentObject = upcallInfo.contentObject;
102 if (contentObject.content == null) {
103 console.log("NdnProtocol.ContentClosure: contentObject.content is null");
104 return Closure.RESULT_ERR;
105 }
106
107 // Use the segmentNumber to load multiple segments.
108 var segmentNumber = DataUtils.bigEndianToUnsignedInt
109 (contentObject.name.components[contentObject.name.components.length - 1]);
110 //console.log("Seg # " + segmentNumber + " received");
111 //console.log("Seg name " + contentObject.name.getName());
112
113 /*
114 if (this.firstReceivedSegmentNumber == null) {
115 // This is the first call.
116 this.firstReceivedSegmentNumber = segmentNumber;
117 if (segmentNumber != 0) {
118 // Special case: Save this content object for later and request segment zero.
119 // SWT: this should not happen in normal case;
120 // ccnd should always return the first segment if no seg# is specified
121 this.firstReceivedContentObject = contentObject;
122 var componentsForZero = contentObject.name.components.slice
123 (0, contentObject.name.components.length - 1);
124 componentsForZero.push([0]);
125 this.ndn.expressInterest(new Name(componentsForZero), this);
126 return Closure.RESULT_OK;
127 }
128 }
129 */
130
131 // Process received data here...
132 // Count content length
133 //nameStr = escape(contentObject.name.getName());
134 //document.getElementById('content').innerHTML += "<p>Name string: " + nameStr + "</p>";
135 //document.getElementById('content').innerHTML += "<p>Content buffer length: " + contentObject.content.length + "</p>";
136
137 /*
138 // Check for the special case if the saved content is for the next segment that we need.
139 if (this.firstReceivedContentObject != null &&
140 this.firstReceivedSegmentNumber == segmentNumber + 1) {
141 // Substitute the saved contentObject send its content and keep going.
142 contentObject = this.firstReceivedContentObject;
143 segmentNumber = segmentNumber + 1;
144 // Clear firstReceivedContentObject to save memory.
145 this.firstReceivedContentObject = null;
146
147 // Process received data here...
148 // Count content length
149 //nameStr = escape(contentObject.name.getName());
150 //document.getElementById('content').innerHTML += "<p>Name string: " + nameStr + "</p>";
151 //document.getElementById('content').innerHTML += "<p>Content buffer length: " + contentObject.content.length + "</p>";
152 this.totalBlocks++;
153 }
154 */
155
156 // Record final seg# if present
157 var finalSegmentNumber = null;
158 if (contentObject.signedInfo != null && contentObject.signedInfo.finalBlockID != null)
159 finalSegmentNumber = DataUtils.bigEndianToUnsignedInt(contentObject.signedInfo.finalBlockID);
160
161 // Check for out-of-order segment
162 if (segmentNumber != this.snd_una) {
163 //console.log("Out-of-order segment #" + segmentNumber + " received.");
164 document.getElementById('content').innerHTML += "<p>Out-of-order segment #" + segmentNumber + " received.</p>";
165 this.ooo_count++;
166
167 if (segmentNumber >= this.snd_nxt || segmentNumber < this.snd_una) {
168 // Discard segment that is out of window
169 //console.log("Out-of-window segment #" + segmentNumber);
170 document.getElementById('content').innerHTML += "<p>Out-of-window segment #" + segmentNumber + "</p>";
171 return Closure.RESULT_OK;
172 }
173 // Mark this segment in hash table
174 var slot = segmentNumber % this.ooo_table_size;
175 this.ooo_table[slot] = segmentNumber;
176
177 if (this.ooo_count == 3) {
178 // Fast retransmit
179 // TODO: expressInterest for seg# = this.snd_una
180 //this.snd_wnd = Math.floor(this.snd_wnd / 2) + 3;
181 } else if (this.ooo_count > 3) {
182 //this.snd_wnd++;
183 // TODO: send a new interest if allowed by snd_wnd
184 // SWT: what if we never receive the first unacked segment???
185 }
186
187 return Closure.RESULT_OK;
188 }
189
190 // In-order segment; slide window forward
191 this.snd_una++
192 this.totalBlocks++;
193 var slot = this.snd_una % this.ooo_table_size;
194 while (this.ooo_table[slot] != undefined) {
195 // continue to move forward until we reach a hole in the seg# sequence
196 this.ooo_table[slot] = undefined;
197 this.snd_una++;
198 this.totalBlocks++;
199 slot = this.snd_una % this.ooo_table_size;
200 }
201
202 if (finalSegmentNumber != null && this.snd_una == finalSegmentNumber + 1) {
203 // All blocks before final block, including final block, is received. Mission complete.
204 // Record stop time and print statistic result
205 this.terminated = true;
206 var T1 = new Date();
207 document.getElementById('content').innerHTML += "<p>Final block received.</p>";
208 document.getElementById('content').innerHTML += "<p>Time elapsed: " + (T1 - this.T0) + " ms</p>";
209 document.getElementById('content').innerHTML += "<p>Total number of blocks: " + this.totalBlocks + "</p>";
210 document.getElementById('content').innerHTML += "<p>Total number of packets: " + this.pkt_recved + "</p>";
211 document.getElementById('content').innerHTML += "<p>Total number of dup segments: " + this.dups + "</p>";
212 document.getElementById('content').innerHTML += "<p>Total number of interest sent: " + this.interest_sent + "</p>";
213 document.getElementById('content').innerHTML += "<p>Total number of time-out interest: " + this.timed_out + "</p>";
Wentao Shangd4607392013-01-24 23:08:49 -0800214
215 document.getElementById('content').innerHTML += "<p>SND_UNA: " + this.snd_una + "</p>";
216 document.getElementById('content').innerHTML += "<p>SND_WND: " + this.snd_wnd + "</p>";
217 document.getElementById('content').innerHTML += "<p>SND_NXT: " + this.snd_nxt + "</p>";
Wentao Shangfcb16262013-01-20 14:42:46 -0800218 return Closure.RESULT_OK;
219 }
220
221 // Adjust window size
222 if (this.snd_wnd < this.max_window) {
223 this.snd_wnd++;
224 //console.log("Window size after adjust: " + this.snd_wnd);
225 }
226
227 // Send the next interest if allowed by snd_wnd
228 var nextNameComponents = contentObject.name.components.slice(0, contentObject.name.components.length - 1);
229 //console.log("SND_UNA: " + this.snd_una);
230 //console.log("SND_NXT: " + this.snd_nxt);
231 while (this.snd_nxt - this.snd_una < this.snd_wnd) {
232 // Make a name for the next segment and get it.
233 var segmentNumberPlus1 = DataUtils.nonNegativeIntToBigEndian(this.snd_nxt);
234 // Put a 0 byte in front.
235 var nextSegmentNumber = new Uint8Array(segmentNumberPlus1.length + 1);
236 nextSegmentNumber.set(segmentNumberPlus1, 1);
237
238 nextNameComponents.push(nextSegmentNumber);
239
240 var nextName = new Name(nextNameComponents);
241 this.ndn.expressInterest(nextName, this);
242 //console.log("Interest sent for seg # " + this.snd_nxt + " name " + nextName.getName());
243 this.interest_sent++;
244
245 this.snd_nxt++;
246 nextNameComponents.pop(); // Remove segment number from components
247 }
248
249 return Closure.RESULT_OK;
250 };
251
252 /*
253 * Convert the big endian Uint8Array to an unsigned int.
254 * Don't check for overflow.
255 */
256 function ArrayToNum(bytes) {
257 var result = 0;
258 for (var i = 0; i < bytes.length; ++i) {
259 result = result * 10;
260 result += (bytes[i] - 48);
261 }
262 return result;
263 }
264
265 /*
266 * Convert the int value to a new big endian Uint8Array and return.
267 * If value is 0 or negative, return Uint8Array(0).
268 */
269 function NumToArray(value) {
270 value = Math.round(value);
271 if (value <= 0)
272 return new Uint8Array(0);
273
274 numString = value.toString();
275 var size = numString.length;
276 var result = new Uint8Array(size);
277 for (i = 0; i < size; i++) {
278 result[i] = numString.charCodeAt(i);
279 }
280 return result;
281 }
282///////////////////////////////////////////////////////////////////////////////////////////////////////////
283
284 /*
285 var AsyncGetClosure = function AsyncGetClosure(T0) {
286 this.T0 = T0; // Start time
287 // Inherit from Closure.
288 Closure.call(this);
289 };
290
291 AsyncGetClosure.prototype.upcall = function(kind, upcallInfo) {
292 //console.log("Closure.upcall() executed.");
293 if (kind == Closure.UPCALL_FINAL) {
294 // Do nothing.
295 } else if (kind == Closure.UPCALL_CONTENT) {
296 var T1 = new Date();
297
298 var content = upcallInfo.contentObject;
299 nameStr = escape(content.name.getName());
300 document.getElementById('content').innerHTML += "<p>Time elapsed: " + (T1 - this.T0) + " ms</p>";
301 document.getElementById('content').innerHTML += "<p>Name string: " + nameStr + "</p>";
302 document.getElementById('content').innerHTML += "<p>Content buffer length: " + content.content.length + "</p>";
303 //console.log("In callback, nameStr: " + nameStr);
304 //console.log("In callback, content: ");
305 //console.log(content.content.length);
306 //document.getElementById('content').innerHTML += contentObjectToHtml(content);
307 } else if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
308 console.log("Closure.upcall called with interest time out.");
309 }
310 return Closure.RESULT_OK;
311 };
312 */
313
314 function run() {
315 document.getElementById('content').innerHTML += "<p>Started...</p>";
316 //ndn.expressInterest(new Name(document.getElementById('interest').value), new AsyncGetClosure( new Date() ));
317 var name = new Name(document.getElementById('interest').value);
318 ndncon.expressInterest( name,
319 new ContentClosure( ndncon, new Date() ));
320 }
321
322 </script>
323
324</head>
325<body >
326
327 <form>
328 Please Enter an Interest:<br />
329 <input id="interest" type="text" name="INTEREST" size="50" value="/wentao.shang/mars/%00" />
330 </form>
331
332 <button onclick="run()">Fetch Content</button>
333
334 <p id="content">Result: <br/></p>
335
336</body>
337</html>