dom/system/gonk/worker_buf.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5
michael@0 6 /**
michael@0 7 * This object contains helpers buffering incoming data & deconstructing it
michael@0 8 * into parcels as well as buffering outgoing data & constructing parcels.
michael@0 9 * For that it maintains two buffers and corresponding uint8 views, indexes.
michael@0 10 *
michael@0 11 * The incoming buffer is a circular buffer where we store incoming data.
michael@0 12 * As soon as a complete parcel is received, it is processed right away, so
michael@0 13 * the buffer only needs to be large enough to hold one parcel.
michael@0 14 *
michael@0 15 * The outgoing buffer is to prepare outgoing parcels. The index is reset
michael@0 16 * every time a parcel is sent.
michael@0 17 */
michael@0 18
michael@0 19 let Buf = {
michael@0 20 INT32_MAX: 2147483647,
michael@0 21 UINT8_SIZE: 1,
michael@0 22 UINT16_SIZE: 2,
michael@0 23 UINT32_SIZE: 4,
michael@0 24 PARCEL_SIZE_SIZE: 4,
michael@0 25 PDU_HEX_OCTET_SIZE: 4,
michael@0 26
michael@0 27 incomingBufferLength: 1024,
michael@0 28 incomingBuffer: null,
michael@0 29 incomingBytes: null,
michael@0 30 incomingWriteIndex: 0,
michael@0 31 incomingReadIndex: 0,
michael@0 32 readIncoming: 0,
michael@0 33 readAvailable: 0,
michael@0 34 currentParcelSize: 0,
michael@0 35
michael@0 36 outgoingBufferLength: 1024,
michael@0 37 outgoingBuffer: null,
michael@0 38 outgoingBytes: null,
michael@0 39 outgoingIndex: 0,
michael@0 40 outgoingBufferCalSizeQueue: null,
michael@0 41
michael@0 42 _init: function() {
michael@0 43 this.incomingBuffer = new ArrayBuffer(this.incomingBufferLength);
michael@0 44 this.outgoingBuffer = new ArrayBuffer(this.outgoingBufferLength);
michael@0 45
michael@0 46 this.incomingBytes = new Uint8Array(this.incomingBuffer);
michael@0 47 this.outgoingBytes = new Uint8Array(this.outgoingBuffer);
michael@0 48
michael@0 49 // Track where incoming data is read from and written to.
michael@0 50 this.incomingWriteIndex = 0;
michael@0 51 this.incomingReadIndex = 0;
michael@0 52
michael@0 53 // Leave room for the parcel size for outgoing parcels.
michael@0 54 this.outgoingIndex = this.PARCEL_SIZE_SIZE;
michael@0 55
michael@0 56 // How many bytes we've read for this parcel so far.
michael@0 57 this.readIncoming = 0;
michael@0 58
michael@0 59 // How many bytes available as parcel data.
michael@0 60 this.readAvailable = 0;
michael@0 61
michael@0 62 // Size of the incoming parcel. If this is zero, we're expecting a new
michael@0 63 // parcel.
michael@0 64 this.currentParcelSize = 0;
michael@0 65
michael@0 66 // Queue for storing outgoing override points
michael@0 67 this.outgoingBufferCalSizeQueue = [];
michael@0 68 },
michael@0 69
michael@0 70 /**
michael@0 71 * Mark current outgoingIndex as start point for calculation length of data
michael@0 72 * written to outgoingBuffer.
michael@0 73 * Mark can be nested for here uses queue to remember marks.
michael@0 74 *
michael@0 75 * @param writeFunction
michael@0 76 * Function to write data length into outgoingBuffer, this function is
michael@0 77 * also used to allocate buffer for data length.
michael@0 78 * Raw data size(in Uint8) is provided as parameter calling writeFunction.
michael@0 79 * If raw data size is not in proper unit for writing, user can adjust
michael@0 80 * the length value in writeFunction before writing.
michael@0 81 **/
michael@0 82 startCalOutgoingSize: function(writeFunction) {
michael@0 83 let sizeInfo = {index: this.outgoingIndex,
michael@0 84 write: writeFunction};
michael@0 85
michael@0 86 // Allocate buffer for data lemgtj.
michael@0 87 writeFunction.call(0);
michael@0 88
michael@0 89 // Get size of data length buffer for it is not counted into data size.
michael@0 90 sizeInfo.size = this.outgoingIndex - sizeInfo.index;
michael@0 91
michael@0 92 // Enqueue size calculation information.
michael@0 93 this.outgoingBufferCalSizeQueue.push(sizeInfo);
michael@0 94 },
michael@0 95
michael@0 96 /**
michael@0 97 * Calculate data length since last mark, and write it into mark position.
michael@0 98 **/
michael@0 99 stopCalOutgoingSize: function() {
michael@0 100 let sizeInfo = this.outgoingBufferCalSizeQueue.pop();
michael@0 101
michael@0 102 // Remember current outgoingIndex.
michael@0 103 let currentOutgoingIndex = this.outgoingIndex;
michael@0 104 // Calculate data length, in uint8.
michael@0 105 let writeSize = this.outgoingIndex - sizeInfo.index - sizeInfo.size;
michael@0 106
michael@0 107 // Write data length to mark, use same function for allocating buffer to make
michael@0 108 // sure there is no buffer overloading.
michael@0 109 this.outgoingIndex = sizeInfo.index;
michael@0 110 sizeInfo.write(writeSize);
michael@0 111
michael@0 112 // Restore outgoingIndex.
michael@0 113 this.outgoingIndex = currentOutgoingIndex;
michael@0 114 },
michael@0 115
michael@0 116 /**
michael@0 117 * Grow the incoming buffer.
michael@0 118 *
michael@0 119 * @param min_size
michael@0 120 * Minimum new size. The actual new size will be the the smallest
michael@0 121 * power of 2 that's larger than this number.
michael@0 122 */
michael@0 123 growIncomingBuffer: function(min_size) {
michael@0 124 if (DEBUG) {
michael@0 125 debug("Current buffer of " + this.incomingBufferLength +
michael@0 126 " can't handle incoming " + min_size + " bytes.");
michael@0 127 }
michael@0 128 let oldBytes = this.incomingBytes;
michael@0 129 this.incomingBufferLength =
michael@0 130 2 << Math.floor(Math.log(min_size)/Math.log(2));
michael@0 131 if (DEBUG) debug("New incoming buffer size: " + this.incomingBufferLength);
michael@0 132 this.incomingBuffer = new ArrayBuffer(this.incomingBufferLength);
michael@0 133 this.incomingBytes = new Uint8Array(this.incomingBuffer);
michael@0 134 if (this.incomingReadIndex <= this.incomingWriteIndex) {
michael@0 135 // Read and write index are in natural order, so we can just copy
michael@0 136 // the old buffer over to the bigger one without having to worry
michael@0 137 // about the indexes.
michael@0 138 this.incomingBytes.set(oldBytes, 0);
michael@0 139 } else {
michael@0 140 // The write index has wrapped around but the read index hasn't yet.
michael@0 141 // Write whatever the read index has left to read until it would
michael@0 142 // circle around to the beginning of the new buffer, and the rest
michael@0 143 // behind that.
michael@0 144 let head = oldBytes.subarray(this.incomingReadIndex);
michael@0 145 let tail = oldBytes.subarray(0, this.incomingReadIndex);
michael@0 146 this.incomingBytes.set(head, 0);
michael@0 147 this.incomingBytes.set(tail, head.length);
michael@0 148 this.incomingReadIndex = 0;
michael@0 149 this.incomingWriteIndex += head.length;
michael@0 150 }
michael@0 151 if (DEBUG) {
michael@0 152 debug("New incoming buffer size is " + this.incomingBufferLength);
michael@0 153 }
michael@0 154 },
michael@0 155
michael@0 156 /**
michael@0 157 * Grow the outgoing buffer.
michael@0 158 *
michael@0 159 * @param min_size
michael@0 160 * Minimum new size. The actual new size will be the the smallest
michael@0 161 * power of 2 that's larger than this number.
michael@0 162 */
michael@0 163 growOutgoingBuffer: function(min_size) {
michael@0 164 if (DEBUG) {
michael@0 165 debug("Current buffer of " + this.outgoingBufferLength +
michael@0 166 " is too small.");
michael@0 167 }
michael@0 168 let oldBytes = this.outgoingBytes;
michael@0 169 this.outgoingBufferLength =
michael@0 170 2 << Math.floor(Math.log(min_size)/Math.log(2));
michael@0 171 this.outgoingBuffer = new ArrayBuffer(this.outgoingBufferLength);
michael@0 172 this.outgoingBytes = new Uint8Array(this.outgoingBuffer);
michael@0 173 this.outgoingBytes.set(oldBytes, 0);
michael@0 174 if (DEBUG) {
michael@0 175 debug("New outgoing buffer size is " + this.outgoingBufferLength);
michael@0 176 }
michael@0 177 },
michael@0 178
michael@0 179 /**
michael@0 180 * Functions for reading data from the incoming buffer.
michael@0 181 *
michael@0 182 * These are all little endian, apart from readParcelSize();
michael@0 183 */
michael@0 184
michael@0 185 /**
michael@0 186 * Ensure position specified is readable.
michael@0 187 *
michael@0 188 * @param index
michael@0 189 * Data position in incoming parcel, valid from 0 to
michael@0 190 * currentParcelSize.
michael@0 191 */
michael@0 192 ensureIncomingAvailable: function(index) {
michael@0 193 if (index >= this.currentParcelSize) {
michael@0 194 throw new Error("Trying to read data beyond the parcel end!");
michael@0 195 } else if (index < 0) {
michael@0 196 throw new Error("Trying to read data before the parcel begin!");
michael@0 197 }
michael@0 198 },
michael@0 199
michael@0 200 /**
michael@0 201 * Seek in current incoming parcel.
michael@0 202 *
michael@0 203 * @param offset
michael@0 204 * Seek offset in relative to current position.
michael@0 205 */
michael@0 206 seekIncoming: function(offset) {
michael@0 207 // Translate to 0..currentParcelSize
michael@0 208 let cur = this.currentParcelSize - this.readAvailable;
michael@0 209
michael@0 210 let newIndex = cur + offset;
michael@0 211 this.ensureIncomingAvailable(newIndex);
michael@0 212
michael@0 213 // ... incomingReadIndex -->|
michael@0 214 // 0 new cur currentParcelSize
michael@0 215 // |================|=======|====================|
michael@0 216 // |<-- cur -->|<- readAvailable ->|
michael@0 217 // |<-- newIndex -->|<-- new readAvailable -->|
michael@0 218 this.readAvailable = this.currentParcelSize - newIndex;
michael@0 219
michael@0 220 // Translate back:
michael@0 221 if (this.incomingReadIndex < cur) {
michael@0 222 // The incomingReadIndex is wrapped.
michael@0 223 newIndex += this.incomingBufferLength;
michael@0 224 }
michael@0 225 newIndex += (this.incomingReadIndex - cur);
michael@0 226 newIndex %= this.incomingBufferLength;
michael@0 227 this.incomingReadIndex = newIndex;
michael@0 228 },
michael@0 229
michael@0 230 readUint8Unchecked: function() {
michael@0 231 let value = this.incomingBytes[this.incomingReadIndex];
michael@0 232 this.incomingReadIndex = (this.incomingReadIndex + 1) %
michael@0 233 this.incomingBufferLength;
michael@0 234 return value;
michael@0 235 },
michael@0 236
michael@0 237 readUint8: function() {
michael@0 238 // Translate to 0..currentParcelSize
michael@0 239 let cur = this.currentParcelSize - this.readAvailable;
michael@0 240 this.ensureIncomingAvailable(cur);
michael@0 241
michael@0 242 this.readAvailable--;
michael@0 243 return this.readUint8Unchecked();
michael@0 244 },
michael@0 245
michael@0 246 readUint8Array: function(length) {
michael@0 247 // Translate to 0..currentParcelSize
michael@0 248 let last = this.currentParcelSize - this.readAvailable;
michael@0 249 last += (length - 1);
michael@0 250 this.ensureIncomingAvailable(last);
michael@0 251
michael@0 252 let array = new Uint8Array(length);
michael@0 253 for (let i = 0; i < length; i++) {
michael@0 254 array[i] = this.readUint8Unchecked();
michael@0 255 }
michael@0 256
michael@0 257 this.readAvailable -= length;
michael@0 258 return array;
michael@0 259 },
michael@0 260
michael@0 261 readUint16: function() {
michael@0 262 return this.readUint8() | this.readUint8() << 8;
michael@0 263 },
michael@0 264
michael@0 265 readInt32: function() {
michael@0 266 return this.readUint8() | this.readUint8() << 8 |
michael@0 267 this.readUint8() << 16 | this.readUint8() << 24;
michael@0 268 },
michael@0 269
michael@0 270 readInt32List: function() {
michael@0 271 let length = this.readInt32();
michael@0 272 let ints = [];
michael@0 273 for (let i = 0; i < length; i++) {
michael@0 274 ints.push(this.readInt32());
michael@0 275 }
michael@0 276 return ints;
michael@0 277 },
michael@0 278
michael@0 279 readString: function() {
michael@0 280 let string_len = this.readInt32();
michael@0 281 if (string_len < 0 || string_len >= this.INT32_MAX) {
michael@0 282 return null;
michael@0 283 }
michael@0 284 let s = "";
michael@0 285 for (let i = 0; i < string_len; i++) {
michael@0 286 s += String.fromCharCode(this.readUint16());
michael@0 287 }
michael@0 288 // Strings are \0\0 delimited, but that isn't part of the length. And
michael@0 289 // if the string length is even, the delimiter is two characters wide.
michael@0 290 // It's insane, I know.
michael@0 291 this.readStringDelimiter(string_len);
michael@0 292 return s;
michael@0 293 },
michael@0 294
michael@0 295 readStringList: function() {
michael@0 296 let num_strings = this.readInt32();
michael@0 297 let strings = [];
michael@0 298 for (let i = 0; i < num_strings; i++) {
michael@0 299 strings.push(this.readString());
michael@0 300 }
michael@0 301 return strings;
michael@0 302 },
michael@0 303
michael@0 304 readStringDelimiter: function(length) {
michael@0 305 let delimiter = this.readUint16();
michael@0 306 if (!(length & 1)) {
michael@0 307 delimiter |= this.readUint16();
michael@0 308 }
michael@0 309 if (DEBUG) {
michael@0 310 if (delimiter !== 0) {
michael@0 311 debug("Something's wrong, found string delimiter: " + delimiter);
michael@0 312 }
michael@0 313 }
michael@0 314 },
michael@0 315
michael@0 316 readParcelSize: function() {
michael@0 317 return this.readUint8Unchecked() << 24 |
michael@0 318 this.readUint8Unchecked() << 16 |
michael@0 319 this.readUint8Unchecked() << 8 |
michael@0 320 this.readUint8Unchecked();
michael@0 321 },
michael@0 322
michael@0 323 /**
michael@0 324 * Functions for writing data to the outgoing buffer.
michael@0 325 */
michael@0 326
michael@0 327 /**
michael@0 328 * Ensure position specified is writable.
michael@0 329 *
michael@0 330 * @param index
michael@0 331 * Data position in outgoing parcel, valid from 0 to
michael@0 332 * outgoingBufferLength.
michael@0 333 */
michael@0 334 ensureOutgoingAvailable: function(index) {
michael@0 335 if (index >= this.outgoingBufferLength) {
michael@0 336 this.growOutgoingBuffer(index + 1);
michael@0 337 }
michael@0 338 },
michael@0 339
michael@0 340 writeUint8: function(value) {
michael@0 341 this.ensureOutgoingAvailable(this.outgoingIndex);
michael@0 342
michael@0 343 this.outgoingBytes[this.outgoingIndex] = value;
michael@0 344 this.outgoingIndex++;
michael@0 345 },
michael@0 346
michael@0 347 writeUint16: function(value) {
michael@0 348 this.writeUint8(value & 0xff);
michael@0 349 this.writeUint8((value >> 8) & 0xff);
michael@0 350 },
michael@0 351
michael@0 352 writeInt32: function(value) {
michael@0 353 this.writeUint8(value & 0xff);
michael@0 354 this.writeUint8((value >> 8) & 0xff);
michael@0 355 this.writeUint8((value >> 16) & 0xff);
michael@0 356 this.writeUint8((value >> 24) & 0xff);
michael@0 357 },
michael@0 358
michael@0 359 writeString: function(value) {
michael@0 360 if (value == null) {
michael@0 361 this.writeInt32(-1);
michael@0 362 return;
michael@0 363 }
michael@0 364 this.writeInt32(value.length);
michael@0 365 for (let i = 0; i < value.length; i++) {
michael@0 366 this.writeUint16(value.charCodeAt(i));
michael@0 367 }
michael@0 368 // Strings are \0\0 delimited, but that isn't part of the length. And
michael@0 369 // if the string length is even, the delimiter is two characters wide.
michael@0 370 // It's insane, I know.
michael@0 371 this.writeStringDelimiter(value.length);
michael@0 372 },
michael@0 373
michael@0 374 writeStringList: function(strings) {
michael@0 375 this.writeInt32(strings.length);
michael@0 376 for (let i = 0; i < strings.length; i++) {
michael@0 377 this.writeString(strings[i]);
michael@0 378 }
michael@0 379 },
michael@0 380
michael@0 381 writeStringDelimiter: function(length) {
michael@0 382 this.writeUint16(0);
michael@0 383 if (!(length & 1)) {
michael@0 384 this.writeUint16(0);
michael@0 385 }
michael@0 386 },
michael@0 387
michael@0 388 writeParcelSize: function(value) {
michael@0 389 /**
michael@0 390 * Parcel size will always be the first thing in the parcel byte
michael@0 391 * array, but the last thing written. Store the current index off
michael@0 392 * to a temporary to be reset after we write the size.
michael@0 393 */
michael@0 394 let currentIndex = this.outgoingIndex;
michael@0 395 this.outgoingIndex = 0;
michael@0 396 this.writeUint8((value >> 24) & 0xff);
michael@0 397 this.writeUint8((value >> 16) & 0xff);
michael@0 398 this.writeUint8((value >> 8) & 0xff);
michael@0 399 this.writeUint8(value & 0xff);
michael@0 400 this.outgoingIndex = currentIndex;
michael@0 401 },
michael@0 402
michael@0 403 copyIncomingToOutgoing: function(length) {
michael@0 404 if (!length || (length < 0)) {
michael@0 405 return;
michael@0 406 }
michael@0 407
michael@0 408 let translatedReadIndexEnd =
michael@0 409 this.currentParcelSize - this.readAvailable + length - 1;
michael@0 410 this.ensureIncomingAvailable(translatedReadIndexEnd);
michael@0 411
michael@0 412 let translatedWriteIndexEnd = this.outgoingIndex + length - 1;
michael@0 413 this.ensureOutgoingAvailable(translatedWriteIndexEnd);
michael@0 414
michael@0 415 let newIncomingReadIndex = this.incomingReadIndex + length;
michael@0 416 if (newIncomingReadIndex < this.incomingBufferLength) {
michael@0 417 // Reading won't cause wrapping, go ahead with builtin copy.
michael@0 418 this.outgoingBytes
michael@0 419 .set(this.incomingBytes.subarray(this.incomingReadIndex,
michael@0 420 newIncomingReadIndex),
michael@0 421 this.outgoingIndex);
michael@0 422 } else {
michael@0 423 // Not so lucky.
michael@0 424 newIncomingReadIndex %= this.incomingBufferLength;
michael@0 425 this.outgoingBytes
michael@0 426 .set(this.incomingBytes.subarray(this.incomingReadIndex,
michael@0 427 this.incomingBufferLength),
michael@0 428 this.outgoingIndex);
michael@0 429 if (newIncomingReadIndex) {
michael@0 430 let firstPartLength = this.incomingBufferLength - this.incomingReadIndex;
michael@0 431 this.outgoingBytes.set(this.incomingBytes.subarray(0, newIncomingReadIndex),
michael@0 432 this.outgoingIndex + firstPartLength);
michael@0 433 }
michael@0 434 }
michael@0 435
michael@0 436 this.incomingReadIndex = newIncomingReadIndex;
michael@0 437 this.readAvailable -= length;
michael@0 438 this.outgoingIndex += length;
michael@0 439 },
michael@0 440
michael@0 441 /**
michael@0 442 * Parcel management
michael@0 443 */
michael@0 444
michael@0 445 /**
michael@0 446 * Write incoming data to the circular buffer.
michael@0 447 *
michael@0 448 * @param incoming
michael@0 449 * Uint8Array containing the incoming data.
michael@0 450 */
michael@0 451 writeToIncoming: function(incoming) {
michael@0 452 // We don't have to worry about the head catching the tail since
michael@0 453 // we process any backlog in parcels immediately, before writing
michael@0 454 // new data to the buffer. So the only edge case we need to handle
michael@0 455 // is when the incoming data is larger than the buffer size.
michael@0 456 let minMustAvailableSize = incoming.length + this.readIncoming;
michael@0 457 if (minMustAvailableSize > this.incomingBufferLength) {
michael@0 458 this.growIncomingBuffer(minMustAvailableSize);
michael@0 459 }
michael@0 460
michael@0 461 // We can let the typed arrays do the copying if the incoming data won't
michael@0 462 // wrap around the edges of the circular buffer.
michael@0 463 let remaining = this.incomingBufferLength - this.incomingWriteIndex;
michael@0 464 if (remaining >= incoming.length) {
michael@0 465 this.incomingBytes.set(incoming, this.incomingWriteIndex);
michael@0 466 } else {
michael@0 467 // The incoming data would wrap around it.
michael@0 468 let head = incoming.subarray(0, remaining);
michael@0 469 let tail = incoming.subarray(remaining);
michael@0 470 this.incomingBytes.set(head, this.incomingWriteIndex);
michael@0 471 this.incomingBytes.set(tail, 0);
michael@0 472 }
michael@0 473 this.incomingWriteIndex = (this.incomingWriteIndex + incoming.length) %
michael@0 474 this.incomingBufferLength;
michael@0 475 },
michael@0 476
michael@0 477 /**
michael@0 478 * Process incoming data.
michael@0 479 *
michael@0 480 * @param incoming
michael@0 481 * Uint8Array containing the incoming data.
michael@0 482 */
michael@0 483 processIncoming: function(incoming) {
michael@0 484 if (DEBUG) {
michael@0 485 debug("Received " + incoming.length + " bytes.");
michael@0 486 debug("Already read " + this.readIncoming);
michael@0 487 }
michael@0 488
michael@0 489 this.writeToIncoming(incoming);
michael@0 490 this.readIncoming += incoming.length;
michael@0 491 while (true) {
michael@0 492 if (!this.currentParcelSize) {
michael@0 493 // We're expecting a new parcel.
michael@0 494 if (this.readIncoming < this.PARCEL_SIZE_SIZE) {
michael@0 495 // We don't know how big the next parcel is going to be, need more
michael@0 496 // data.
michael@0 497 if (DEBUG) debug("Next parcel size unknown, going to sleep.");
michael@0 498 return;
michael@0 499 }
michael@0 500 this.currentParcelSize = this.readParcelSize();
michael@0 501 if (DEBUG) {
michael@0 502 debug("New incoming parcel of size " + this.currentParcelSize);
michael@0 503 }
michael@0 504 // The size itself is not included in the size.
michael@0 505 this.readIncoming -= this.PARCEL_SIZE_SIZE;
michael@0 506 }
michael@0 507
michael@0 508 if (this.readIncoming < this.currentParcelSize) {
michael@0 509 // We haven't read enough yet in order to be able to process a parcel.
michael@0 510 if (DEBUG) debug("Read " + this.readIncoming + ", but parcel size is "
michael@0 511 + this.currentParcelSize + ". Going to sleep.");
michael@0 512 return;
michael@0 513 }
michael@0 514
michael@0 515 // Alright, we have enough data to process at least one whole parcel.
michael@0 516 // Let's do that.
michael@0 517 let expectedAfterIndex = (this.incomingReadIndex + this.currentParcelSize)
michael@0 518 % this.incomingBufferLength;
michael@0 519
michael@0 520 if (DEBUG) {
michael@0 521 let parcel;
michael@0 522 if (expectedAfterIndex < this.incomingReadIndex) {
michael@0 523 let head = this.incomingBytes.subarray(this.incomingReadIndex);
michael@0 524 let tail = this.incomingBytes.subarray(0, expectedAfterIndex);
michael@0 525 parcel = Array.slice(head).concat(Array.slice(tail));
michael@0 526 } else {
michael@0 527 parcel = Array.slice(this.incomingBytes.subarray(
michael@0 528 this.incomingReadIndex, expectedAfterIndex));
michael@0 529 }
michael@0 530 debug("Parcel (size " + this.currentParcelSize + "): " + parcel);
michael@0 531 }
michael@0 532
michael@0 533 if (DEBUG) debug("We have at least one complete parcel.");
michael@0 534 try {
michael@0 535 this.readAvailable = this.currentParcelSize;
michael@0 536 this.processParcel();
michael@0 537 } catch (ex) {
michael@0 538 if (DEBUG) debug("Parcel handling threw " + ex + "\n" + ex.stack);
michael@0 539 }
michael@0 540
michael@0 541 // Ensure that the whole parcel was consumed.
michael@0 542 if (this.incomingReadIndex != expectedAfterIndex) {
michael@0 543 if (DEBUG) {
michael@0 544 debug("Parcel handler didn't consume whole parcel, " +
michael@0 545 Math.abs(expectedAfterIndex - this.incomingReadIndex) +
michael@0 546 " bytes left over");
michael@0 547 }
michael@0 548 this.incomingReadIndex = expectedAfterIndex;
michael@0 549 }
michael@0 550 this.readIncoming -= this.currentParcelSize;
michael@0 551 this.readAvailable = 0;
michael@0 552 this.currentParcelSize = 0;
michael@0 553 }
michael@0 554 },
michael@0 555
michael@0 556 /**
michael@0 557 * Communicate with the IPC thread.
michael@0 558 */
michael@0 559 sendParcel: function() {
michael@0 560 // Compute the size of the parcel and write it to the front of the parcel
michael@0 561 // where we left room for it. Note that he parcel size does not include
michael@0 562 // the size itself.
michael@0 563 let parcelSize = this.outgoingIndex - this.PARCEL_SIZE_SIZE;
michael@0 564 this.writeParcelSize(parcelSize);
michael@0 565
michael@0 566 // This assumes that postRILMessage will make a copy of the ArrayBufferView
michael@0 567 // right away!
michael@0 568 let parcel = this.outgoingBytes.subarray(0, this.outgoingIndex);
michael@0 569 if (DEBUG) debug("Outgoing parcel: " + Array.slice(parcel));
michael@0 570 this.onSendParcel(parcel);
michael@0 571 this.outgoingIndex = this.PARCEL_SIZE_SIZE;
michael@0 572 },
michael@0 573
michael@0 574 getCurrentParcelSize: function() {
michael@0 575 return this.currentParcelSize;
michael@0 576 },
michael@0 577
michael@0 578 getReadAvailable: function() {
michael@0 579 return this.readAvailable;
michael@0 580 }
michael@0 581
michael@0 582 /**
michael@0 583 * Process one parcel.
michael@0 584 *
michael@0 585 * |processParcel| is an implementation provided incoming parcel processing
michael@0 586 * function invoked when we have received a complete parcel. Implementation
michael@0 587 * may call multiple read functions to extract data from the incoming buffer.
michael@0 588 */
michael@0 589 //processParcel: function() {
michael@0 590 // let something = this.readInt32();
michael@0 591 // ...
michael@0 592 //},
michael@0 593
michael@0 594 /**
michael@0 595 * Write raw data out to underlying channel.
michael@0 596 *
michael@0 597 * |onSendParcel| is an implementation provided stream output function
michael@0 598 * invoked when we're really going to write something out. We assume the
michael@0 599 * data are completely copied to some output buffer in this call and may
michael@0 600 * be destroyed when it's done.
michael@0 601 *
michael@0 602 * @param parcel
michael@0 603 * An array of numeric octet data.
michael@0 604 */
michael@0 605 //onSendParcel: function(parcel) {
michael@0 606 // ...
michael@0 607 //}
michael@0 608 };
michael@0 609
michael@0 610 module.exports = { Buf: Buf };

mercurial