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

Side by Side Diff: net/websockets/websocket_frame.cc

Issue 11572010: Optimise MaskWebSocketFramePayload(). (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Compile fix for Windows. Created 8 years 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
« no previous file with comments | « no previous file | net/websockets/websocket_frame_unittest.cc » ('j') | 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/websockets/websocket_frame.h" 5 #include "net/websockets/websocket_frame.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/rand_util.h" 9 #include "base/rand_util.h"
10 #include "net/base/big_endian.h" 10 #include "net/base/big_endian.h"
11 #include "net/base/io_buffer.h" 11 #include "net/base/io_buffer.h"
12 #include "net/base/net_errors.h" 12 #include "net/base/net_errors.h"
13 13
14 namespace { 14 namespace {
15 15
16 const uint8 kFinalBit = 0x80; 16 const uint8 kFinalBit = 0x80;
17 const uint8 kReserved1Bit = 0x40; 17 const uint8 kReserved1Bit = 0x40;
18 const uint8 kReserved2Bit = 0x20; 18 const uint8 kReserved2Bit = 0x20;
19 const uint8 kReserved3Bit = 0x10; 19 const uint8 kReserved3Bit = 0x10;
20 const uint8 kOpCodeMask = 0xF; 20 const uint8 kOpCodeMask = 0xF;
21 const uint8 kMaskBit = 0x80; 21 const uint8 kMaskBit = 0x80;
22 const uint64 kMaxPayloadLengthWithoutExtendedLengthField = 125; 22 const uint64 kMaxPayloadLengthWithoutExtendedLengthField = 125;
23 const uint64 kPayloadLengthWithTwoByteExtendedLengthField = 126; 23 const uint64 kPayloadLengthWithTwoByteExtendedLengthField = 126;
24 const uint64 kPayloadLengthWithEightByteExtendedLengthField = 127; 24 const uint64 kPayloadLengthWithEightByteExtendedLengthField = 127;
25 25
26 inline void MaskWebSocketFramePayloadByBytes(
27 const net::WebSocketMaskingKey& masking_key,
28 size_t masking_key_offset,
29 char* const begin,
30 char* const end) {
31 for (char* masked = begin; masked != end; ++masked) {
32 *masked ^= masking_key.key[masking_key_offset++];
33 if (masking_key_offset == net::WebSocketFrameHeader::kMaskingKeyLength)
34 masking_key_offset = 0;
35 }
36 }
37
26 } // Unnamed namespace. 38 } // Unnamed namespace.
27 39
28 namespace net { 40 namespace net {
29 41
30 // Definitions for in-struct constants. 42 // Definitions for in-struct constants.
31 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeContinuation = 43 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeContinuation =
32 0x0; 44 0x0;
33 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeText = 0x1; 45 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeText = 0x1;
34 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeBinary = 0x2; 46 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeBinary = 0x2;
35 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeClose = 0x8; 47 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeClose = 0x8;
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 // Masking keys should be generated from a cryptographically secure random 147 // Masking keys should be generated from a cryptographically secure random
136 // number generator, which means web application authors should not be able 148 // number generator, which means web application authors should not be able
137 // to guess the next value of masking key. 149 // to guess the next value of masking key.
138 WebSocketMaskingKey masking_key; 150 WebSocketMaskingKey masking_key;
139 base::RandBytes(masking_key.key, WebSocketFrameHeader::kMaskingKeyLength); 151 base::RandBytes(masking_key.key, WebSocketFrameHeader::kMaskingKeyLength);
140 return masking_key; 152 return masking_key;
141 } 153 }
142 154
143 void MaskWebSocketFramePayload(const WebSocketMaskingKey& masking_key, 155 void MaskWebSocketFramePayload(const WebSocketMaskingKey& masking_key,
144 uint64 frame_offset, 156 uint64 frame_offset,
145 char* data, 157 char* const data,
146 int data_size) { 158 int data_size) {
147 static const size_t kMaskingKeyLength = 159 static const size_t kMaskingKeyLength =
148 WebSocketFrameHeader::kMaskingKeyLength; 160 WebSocketFrameHeader::kMaskingKeyLength;
149 161
150 DCHECK_GE(data_size, 0); 162 DCHECK_GE(data_size, 0);
151 163
152 // TODO(yutak): Make masking more efficient by XOR'ing every machine word 164 // Most of the masking is done one word at a time, except for the beginning
153 // (4 or 8 bytes), instead of XOR'ing every byte. 165 // and the end of the buffer which may be unaligned. We use size_t to get the
154 size_t masking_key_offset = frame_offset % kMaskingKeyLength; 166 // word size for this architecture. We require it be a multiple of
155 for (int i = 0; i < data_size; ++i) { 167 // kMaskingKeyLength in size.
156 data[i] ^= masking_key.key[masking_key_offset++]; 168 typedef size_t PackedMaskType;
157 if (masking_key_offset == kMaskingKeyLength) 169 PackedMaskType packed_mask_key = 0;
158 masking_key_offset = 0; 170 static const size_t kPackedMaskKeySize = sizeof(packed_mask_key);
171 COMPILE_ASSERT((kPackedMaskKeySize >= kMaskingKeyLength &&
172 kPackedMaskKeySize % kMaskingKeyLength == 0),
173 word_size_is_not_multiple_of_mask_length);
174 char* const end = data + data_size;
175 // If the buffer is too small for the vectorised version to be useful, revert
176 // to the byte-at-a-time implementation early.
177 if (data_size <= static_cast<int>(kPackedMaskKeySize * 2)) {
178 MaskWebSocketFramePayloadByBytes(masking_key,
179 frame_offset % kMaskingKeyLength,
180 data, end);
181 return;
159 } 182 }
183 const size_t data_modulus =
184 reinterpret_cast<size_t>(data) % kPackedMaskKeySize;
185 char* const aligned_begin = data_modulus == 0 ? data :
186 (data + kPackedMaskKeySize - data_modulus);
187 // Guaranteed by the above check for small data_size.
188 DCHECK(aligned_begin < end);
189 MaskWebSocketFramePayloadByBytes(masking_key,
190 frame_offset % kMaskingKeyLength,
191 data, aligned_begin);
192 const size_t end_modulus = reinterpret_cast<size_t>(end) % kPackedMaskKeySize;
193 char* const aligned_end = end - end_modulus;
194 // Guaranteed by the above check for small data_size.
195 DCHECK(aligned_end > aligned_begin);
196 // Create a version of the mask which is rotated by the appropriate offset
197 // for our alignment. The "trick" here is that 0 XORed with the mask will
198 // give the value of the mask for the appropriate byte.
199 char realigned_mask[kMaskingKeyLength] = { 0 };
200 MaskWebSocketFramePayloadByBytes(masking_key,
201 (frame_offset + aligned_begin - data)
202 % kMaskingKeyLength,
203 realigned_mask,
204 realigned_mask + kMaskingKeyLength);
205
206 for (size_t i = 0; i < kPackedMaskKeySize; i += kMaskingKeyLength) {
207 // memcpy() is allegedly blessed by the C++ standard for type-punning.
208 memcpy(reinterpret_cast<char*>(&packed_mask_key) + i,
209 realigned_mask, kMaskingKeyLength);
210 }
211
212 // The main loop.
213 for (char* merged = aligned_begin;
214 merged != aligned_end;
215 merged += kPackedMaskKeySize) {
216 // This is not quite standard-compliant C++. However, the standard-compliant
217 // equivalent (using memcpy()) compiles to slower code using g++. In
218 // practice, this will work for the compilers and architectures currently
219 // supported by Chromium, and the tests are extremely unlikely to pass if a
220 // future compiler/architecture breaks it.
221 *reinterpret_cast<PackedMaskType*>(merged) ^= packed_mask_key;
222 }
223
224 MaskWebSocketFramePayloadByBytes(masking_key,
225 (frame_offset + (aligned_end - data))
226 % kMaskingKeyLength,
227 aligned_end, end);
160 } 228 }
161 229
162 } // namespace net 230 } // namespace net
OLDNEW
« no previous file with comments | « no previous file | net/websockets/websocket_frame_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698