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