Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(247)

Side by Side Diff: sdk/lib/io/websocket_impl.dart

Issue 137833011: Use Int32x4List to optimize mask/unmask websockets. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart.io; 5 part of dart.io;
6 6
7 const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 7 const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
8 8
9 // Matches _WebSocketOpcode. 9 // Matches _WebSocketOpcode.
10 class _WebSocketMessageType { 10 class _WebSocketMessageType {
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 } 162 }
163 } else { 163 } else {
164 if (_state == MASK) { 164 if (_state == MASK) {
165 _maskingBytes[4 - _remainingMaskingKeyBytes--] = byte; 165 _maskingBytes[4 - _remainingMaskingKeyBytes--] = byte;
166 if (_remainingMaskingKeyBytes == 0) { 166 if (_remainingMaskingKeyBytes == 0) {
167 _maskDone(); 167 _maskDone();
168 } 168 }
169 } else { 169 } else {
170 assert(_state == PAYLOAD); 170 assert(_state == PAYLOAD);
171 // The payload is not handled one byte at a time but in blocks. 171 // The payload is not handled one byte at a time but in blocks.
172 int payload = min(lastIndex - index, _remainingPayloadBytes); 172 int payloadLength = min(lastIndex - index, _remainingPayloadBytes);
173 _remainingPayloadBytes -= payload; 173 _remainingPayloadBytes -= payloadLength;
174 // Unmask payload if masked. 174 // Unmask payload if masked.
175 if (_masked) { 175 if (_masked) {
176 for (int i = index; i < index + payload; i++) { 176 _unmask(index, payloadLength, buffer);
177 buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3];
178 }
179 } 177 }
180 // Control frame and data frame share _payload builder. 178 // Control frame and data frame share _payload builder.
181 _payload.add(new Uint8List.view(buffer.buffer, index, payload)); 179 _payload.add(new Uint8List.view(buffer.buffer, index, payloadLength));
182 index += payload; 180 index += payloadLength;
183 if (_isControlFrame()) { 181 if (_isControlFrame()) {
184 if (_remainingPayloadBytes == 0) _controlFrameEnd(); 182 if (_remainingPayloadBytes == 0) _controlFrameEnd();
185 } else { 183 } else {
186 if (_currentMessageType != _WebSocketMessageType.TEXT && 184 if (_currentMessageType != _WebSocketMessageType.TEXT &&
187 _currentMessageType != _WebSocketMessageType.BINARY) { 185 _currentMessageType != _WebSocketMessageType.BINARY) {
188 throw new WebSocketException("Protocol error"); 186 throw new WebSocketException("Protocol error");
189 } 187 }
190 if (_remainingPayloadBytes == 0) _messageFrameEnd(); 188 if (_remainingPayloadBytes == 0) _messageFrameEnd();
191 } 189 }
192 190
193 // Hack - as we always do index++ below. 191 // Hack - as we always do index++ below.
194 index--; 192 index--;
195 } 193 }
196 } 194 }
197 195
198 // Move to the next byte. 196 // Move to the next byte.
199 index++; 197 index++;
200 } 198 }
201 } 199 }
202 200
201 void _unmask(int index, int payload, Uint8List buffer) {
kasperl 2014/01/29 09:47:37 payload -> length
Anders Johnsen 2014/01/29 10:19:04 Done.
202 const int BLOCK_SIZE = 16;
203 // Start by alligning to 16 bytes.
kasperl 2014/01/29 09:47:37 alligning -> aligning
Anders Johnsen 2014/01/29 10:19:04 Done.
204 final int startOffset = min(BLOCK_SIZE - (index & 15), payload);
kasperl 2014/01/29 09:47:37 Maybe replace this whole min computation by checki
Anders Johnsen 2014/01/29 10:19:04 Done.
205 int end = index + startOffset;
206 for (int i = index; i < end; i++) {
207 buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3];
208 }
209 index += startOffset;
210 payload -= startOffset;
211 final int blockCount = payload ~/ BLOCK_SIZE;
212 if (blockCount > 0) {
213 // Create mask block.
214 int mask = 0;
215 for (int i = 3; i >= 0; i--) {
kasperl 2014/01/29 09:47:37 Here's an idea: Why don't you turn masking bytes i
Anders Johnsen 2014/01/29 10:19:04 While the idea is very cool, I'm afraid the build-
216 mask = (mask << 8) | _maskingBytes[(_unmaskingIndex + i) & 3];
217 }
218 Int32x4 blockMask = new Int32x4(mask, mask, mask, mask);
219 Int32x4List blockBuffer = new Int32x4List.view(
220 buffer.buffer, index, blockCount);
221 for (int i = 0; i < blockBuffer.length; i++) {
222 blockBuffer[i] ^= blockMask;
223 }
224 final int bytes = blockCount * BLOCK_SIZE;
225 index += bytes;
226 payload -= bytes;
227 }
228 // Handle end.
229 end = index + payload;
230 for (int i = index; i < end; i++) {
231 buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3];
232 }
233 }
234
203 void _lengthDone() { 235 void _lengthDone() {
204 if (_masked) { 236 if (_masked) {
205 if (!_serverSide) { 237 if (!_serverSide) {
206 throw new WebSocketException("Received masked frame from server"); 238 throw new WebSocketException("Received masked frame from server");
207 } 239 }
208 _state = MASK; 240 _state = MASK;
209 } else { 241 } else {
210 if (_serverSide) { 242 if (_serverSide) {
211 throw new WebSocketException("Received unmasked frame from client"); 243 throw new WebSocketException("Received unmasked frame from client");
212 } 244 }
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after
523 // Write the length in network byte order into the header. 555 // Write the length in network byte order into the header.
524 for (int i = 0; i < lengthBytes; i++) { 556 for (int i = 0; i < lengthBytes; i++) {
525 header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF; 557 header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF;
526 } 558 }
527 if (mask) { 559 if (mask) {
528 header[1] |= 1 << 7; 560 header[1] |= 1 << 7;
529 var maskBytes = _IOCrypto.getRandomBytes(4); 561 var maskBytes = _IOCrypto.getRandomBytes(4);
530 header.setRange(index, index + 4, maskBytes); 562 header.setRange(index, index + 4, maskBytes);
531 index += 4; 563 index += 4;
532 if (data != null) { 564 if (data != null) {
533 var list; 565 Uint8List list;
534 // If this is a text message just do the masking inside the 566 // If this is a text message just do the masking inside the
535 // encoded data. 567 // encoded data.
536 if (opcode == _WebSocketOpcode.TEXT) { 568 if (opcode == _WebSocketOpcode.TEXT && data is Uint8List) {
537 list = data; 569 list = data;
538 } else { 570 } else {
539 list = new Uint8List(data.length); 571 if (data is Uint8List) {
572 list = new Uint8List.fromList(data);
573 } else {
574 list = new Uint8List(data.length);
575 for (int i = 0; i < data.length; i++) {
576 if (data[i] < 0 || 255 < data[i]) {
577 throw new ArgumentError(
578 "List element is not a byte value "
579 "(value ${data[i]} at index $i)");
580 }
581 list[i] = data[i];
582 }
583 }
540 } 584 }
541 if (data is Uint8List) { 585 const int BLOCK_SIZE = 16;
542 for (int i = 0; i < data.length; i++) { 586 int blockCount = list.length ~/ BLOCK_SIZE;
543 list[i] = data[i] ^ maskBytes[i & 3]; 587 if (blockCount > 0) {
588 // Create mask block.
589 int mask = 0;
590 for (int i = 3; i >= 0; i--) {
591 mask = (mask << 8) | maskBytes[i];
544 } 592 }
545 } else { 593 Int32x4 blockMask = new Int32x4(mask, mask, mask, mask);
546 for (int i = 0; i < data.length; i++) { 594 Int32x4List blockBuffer = new Int32x4List.view(
547 if (data[i] < 0 || 255 < data[i]) { 595 list.buffer, 0, blockCount);
548 throw new ArgumentError( 596 for (int i = 0; i < blockBuffer.length; i++) {
549 "List element is not a byte value " 597 blockBuffer[i] ^= blockMask;
550 "(value ${data[i]} at index $i)");
551 }
552 list[i] = data[i] ^ maskBytes[i & 3];
553 } 598 }
554 } 599 }
600 // Handle end.
601 for (int i = blockCount * BLOCK_SIZE; i < list.length; i++) {
602 list[i] ^= maskBytes[i & 3];
603 }
555 data = list; 604 data = list;
556 } 605 }
557 } 606 }
558 assert(index == headerSize); 607 assert(index == headerSize);
559 if (data == null) { 608 if (data == null) {
560 return [header]; 609 return [header];
561 } else { 610 } else {
562 return [header, data]; 611 return [header, data];
563 } 612 }
564 } 613 }
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after
900 (code < WebSocketStatus.NORMAL_CLOSURE || 949 (code < WebSocketStatus.NORMAL_CLOSURE ||
901 code == WebSocketStatus.RESERVED_1004 || 950 code == WebSocketStatus.RESERVED_1004 ||
902 code == WebSocketStatus.NO_STATUS_RECEIVED || 951 code == WebSocketStatus.NO_STATUS_RECEIVED ||
903 code == WebSocketStatus.ABNORMAL_CLOSURE || 952 code == WebSocketStatus.ABNORMAL_CLOSURE ||
904 (code > WebSocketStatus.INTERNAL_SERVER_ERROR && 953 (code > WebSocketStatus.INTERNAL_SERVER_ERROR &&
905 code < WebSocketStatus.RESERVED_1015) || 954 code < WebSocketStatus.RESERVED_1015) ||
906 (code >= WebSocketStatus.RESERVED_1015 && 955 (code >= WebSocketStatus.RESERVED_1015 &&
907 code < 3000)); 956 code < 3000));
908 } 957 }
909 } 958 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698