OLD | NEW |
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 "base/sync_socket.h" | 5 #include "base/sync_socket.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/threading/thread_restrictions.h" |
8 #include "base/win/scoped_handle.h" | 9 #include "base/win/scoped_handle.h" |
9 | 10 |
10 namespace base { | 11 namespace base { |
11 | 12 |
12 using win::ScopedHandle; | 13 using win::ScopedHandle; |
13 | 14 |
14 namespace { | 15 namespace { |
15 // IMPORTANT: do not change how this name is generated because it will break | 16 // IMPORTANT: do not change how this name is generated because it will break |
16 // in sandboxed scenarios as we might have by-name policies that allow pipe | 17 // in sandboxed scenarios as we might have by-name policies that allow pipe |
17 // creation. Also keep the secure random number generation. | 18 // creation. Also keep the secure random number generation. |
18 const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\chrome.sync.%u.%u.%lu"; | 19 const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\chrome.sync.%u.%u.%lu"; |
19 const size_t kPipePathMax = arraysize(kPipeNameFormat) + (3 * 10) + 1; | 20 const size_t kPipePathMax = arraysize(kPipeNameFormat) + (3 * 10) + 1; |
20 | 21 |
21 // To avoid users sending negative message lengths to Send/Receive | 22 // To avoid users sending negative message lengths to Send/Receive |
22 // we clamp message lengths, which are size_t, to no more than INT_MAX. | 23 // we clamp message lengths, which are size_t, to no more than INT_MAX. |
23 const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX); | 24 const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX); |
24 | 25 |
25 const int kOutBufferSize = 4096; | 26 const int kOutBufferSize = 4096; |
26 const int kInBufferSize = 4096; | 27 const int kInBufferSize = 4096; |
27 const int kDefaultTimeoutMilliSeconds = 1000; | 28 const int kDefaultTimeoutMilliSeconds = 1000; |
28 | 29 |
29 bool CreatePairImpl(HANDLE* socket_a, HANDLE* socket_b, bool overlapped) { | 30 bool CreatePairImpl(HANDLE* socket_a, HANDLE* socket_b, bool overlapped) { |
30 DCHECK(socket_a != socket_b); | 31 DCHECK_NE(socket_a, socket_b); |
31 DCHECK(*socket_a == SyncSocket::kInvalidHandle); | 32 DCHECK_EQ(*socket_a, SyncSocket::kInvalidHandle); |
32 DCHECK(*socket_b == SyncSocket::kInvalidHandle); | 33 DCHECK_EQ(*socket_b, SyncSocket::kInvalidHandle); |
33 | 34 |
34 wchar_t name[kPipePathMax]; | 35 wchar_t name[kPipePathMax]; |
35 ScopedHandle handle_a; | 36 ScopedHandle handle_a; |
36 DWORD flags = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE; | 37 DWORD flags = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE; |
37 if (overlapped) | 38 if (overlapped) |
38 flags |= FILE_FLAG_OVERLAPPED; | 39 flags |= FILE_FLAG_OVERLAPPED; |
39 | 40 |
40 do { | 41 do { |
41 unsigned int rnd_name; | 42 unsigned int rnd_name; |
42 if (rand_s(&rnd_name) != 0) | 43 if (rand_s(&rnd_name) != 0) |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 (max_size - current_pos) : UINT_MAX); | 106 (max_size - current_pos) : UINT_MAX); |
106 } | 107 } |
107 | 108 |
108 // Template function that supports calling ReadFile or WriteFile in an | 109 // Template function that supports calling ReadFile or WriteFile in an |
109 // overlapped fashion and waits for IO completion. The function also waits | 110 // overlapped fashion and waits for IO completion. The function also waits |
110 // on an event that can be used to cancel the operation. If the operation | 111 // on an event that can be used to cancel the operation. If the operation |
111 // is cancelled, the function returns and closes the relevant socket object. | 112 // is cancelled, the function returns and closes the relevant socket object. |
112 template <typename BufferType, typename Function> | 113 template <typename BufferType, typename Function> |
113 size_t CancelableFileOperation(Function operation, HANDLE file, | 114 size_t CancelableFileOperation(Function operation, HANDLE file, |
114 BufferType* buffer, size_t length, | 115 BufferType* buffer, size_t length, |
115 base::WaitableEvent* io_event, | 116 WaitableEvent* io_event, |
116 base::WaitableEvent* cancel_event, | 117 WaitableEvent* cancel_event, |
117 CancelableSyncSocket* socket, | 118 CancelableSyncSocket* socket, |
118 DWORD timeout_in_ms) { | 119 DWORD timeout_in_ms) { |
| 120 ThreadRestrictions::AssertIOAllowed(); |
119 // The buffer must be byte size or the length check won't make much sense. | 121 // The buffer must be byte size or the length check won't make much sense. |
120 COMPILE_ASSERT(sizeof(buffer[0]) == sizeof(char), incorrect_buffer_type); | 122 COMPILE_ASSERT(sizeof(buffer[0]) == sizeof(char), incorrect_buffer_type); |
| 123 DCHECK_GT(length, 0u); |
121 DCHECK_LE(length, kMaxMessageLength); | 124 DCHECK_LE(length, kMaxMessageLength); |
| 125 DCHECK_NE(file, SyncSocket::kInvalidHandle); |
122 | 126 |
123 OVERLAPPED ol = {0}; | 127 // Track the finish time so we can calculate the timeout as data is read. |
124 ol.hEvent = io_event->handle(); | 128 TimeTicks current_time, finish_time; |
| 129 if (timeout_in_ms != INFINITE) { |
| 130 current_time = TimeTicks::Now(); |
| 131 finish_time = |
| 132 current_time + base::TimeDelta::FromMilliseconds(timeout_in_ms); |
| 133 } |
| 134 |
125 size_t count = 0; | 135 size_t count = 0; |
126 while (count < length) { | 136 do { |
127 DWORD chunk = GetNextChunkSize(count, length); | 137 // The OVERLAPPED structure will be modified by ReadFile or WriteFile. |
| 138 OVERLAPPED ol = { 0 }; |
| 139 ol.hEvent = io_event->handle(); |
| 140 |
| 141 const DWORD chunk = GetNextChunkSize(count, length); |
128 // This is either the ReadFile or WriteFile call depending on whether | 142 // This is either the ReadFile or WriteFile call depending on whether |
129 // we're receiving or sending data. | 143 // we're receiving or sending data. |
130 DWORD len = 0; | 144 DWORD len = 0; |
131 BOOL ok = operation(file, static_cast<BufferType*>(buffer) + count, chunk, | 145 const BOOL operation_ok = operation( |
132 &len, &ol); | 146 file, static_cast<BufferType*>(buffer) + count, chunk, &len, &ol); |
133 if (!ok) { | 147 if (!operation_ok) { |
134 if (::GetLastError() == ERROR_IO_PENDING) { | 148 if (::GetLastError() == ERROR_IO_PENDING) { |
135 HANDLE events[] = { io_event->handle(), cancel_event->handle() }; | 149 HANDLE events[] = { io_event->handle(), cancel_event->handle() }; |
136 int wait_result = WaitForMultipleObjects( | 150 const int wait_result = WaitForMultipleObjects( |
137 arraysize(events), events, FALSE, timeout_in_ms); | 151 ARRAYSIZE_UNSAFE(events), events, FALSE, |
| 152 timeout_in_ms == INFINITE |
| 153 ? timeout_in_ms |
| 154 : (finish_time - current_time).InMilliseconds()); |
138 if (wait_result == (WAIT_OBJECT_0 + 0)) { | 155 if (wait_result == (WAIT_OBJECT_0 + 0)) { |
139 GetOverlappedResult(file, &ol, &len, TRUE); | 156 GetOverlappedResult(file, &ol, &len, TRUE); |
140 } else if (wait_result == (WAIT_OBJECT_0 + 1)) { | 157 } else if (wait_result == (WAIT_OBJECT_0 + 1)) { |
141 VLOG(1) << "Shutdown was signaled. Closing socket."; | 158 DVLOG(1) << "Shutdown was signaled. Closing socket."; |
142 CancelIo(file); | 159 CancelIo(file); |
143 socket->Close(); | 160 socket->Close(); |
144 count = 0; | 161 count = 0; |
145 break; | 162 break; |
146 } else { | 163 } else { |
147 // Timeout happened. | 164 // Timeout happened. |
148 DCHECK_EQ(WAIT_TIMEOUT, wait_result); | 165 DCHECK_EQ(WAIT_TIMEOUT, wait_result); |
149 if (!CancelIo(file)){ | 166 if (!CancelIo(file)) |
150 DLOG(WARNING) << "CancelIo() failed"; | 167 DLOG(WARNING) << "CancelIo() failed"; |
151 } | |
152 break; | 168 break; |
153 } | 169 } |
154 } else { | 170 } else { |
155 break; | 171 break; |
156 } | 172 } |
157 } | 173 } |
158 | 174 |
159 count += len; | 175 count += len; |
160 | 176 |
161 // Quit the operation if we can't write/read anymore. | 177 // Quit the operation if we can't write/read anymore. |
162 if (len != chunk) | 178 if (len != chunk) |
163 break; | 179 break; |
164 } | |
165 | 180 |
166 return (count > 0) ? count : 0; | 181 // Since TimeTicks::Now() is expensive, only bother updating the time if we |
| 182 // have more work to do. |
| 183 if (timeout_in_ms != INFINITE && count < length) |
| 184 current_time = base::TimeTicks::Now(); |
| 185 } while (count < length && |
| 186 (timeout_in_ms == INFINITE || current_time < finish_time)); |
| 187 |
| 188 return count; |
167 } | 189 } |
168 | 190 |
169 } // namespace | 191 } // namespace |
170 | 192 |
171 #if defined(COMPONENT_BUILD) | 193 #if defined(COMPONENT_BUILD) |
172 const SyncSocket::Handle SyncSocket::kInvalidHandle = INVALID_HANDLE_VALUE; | 194 const SyncSocket::Handle SyncSocket::kInvalidHandle = INVALID_HANDLE_VALUE; |
173 #endif | 195 #endif |
174 | 196 |
175 SyncSocket::SyncSocket() : handle_(kInvalidHandle) {} | 197 SyncSocket::SyncSocket() : handle_(kInvalidHandle) {} |
176 | 198 |
177 SyncSocket::~SyncSocket() { | 199 SyncSocket::~SyncSocket() { |
178 Close(); | 200 Close(); |
179 } | 201 } |
180 | 202 |
181 // static | 203 // static |
182 bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) { | 204 bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) { |
183 return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, false); | 205 return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, false); |
184 } | 206 } |
185 | 207 |
186 bool SyncSocket::Close() { | 208 bool SyncSocket::Close() { |
187 if (handle_ == kInvalidHandle) | 209 if (handle_ == kInvalidHandle) |
188 return false; | 210 return true; |
189 | 211 |
190 BOOL retval = CloseHandle(handle_); | 212 const BOOL result = CloseHandle(handle_); |
191 handle_ = kInvalidHandle; | 213 handle_ = kInvalidHandle; |
192 return retval ? true : false; | 214 return result == TRUE; |
193 } | 215 } |
194 | 216 |
195 size_t SyncSocket::Send(const void* buffer, size_t length) { | 217 size_t SyncSocket::Send(const void* buffer, size_t length) { |
| 218 ThreadRestrictions::AssertIOAllowed(); |
| 219 DCHECK_GT(length, 0u); |
196 DCHECK_LE(length, kMaxMessageLength); | 220 DCHECK_LE(length, kMaxMessageLength); |
| 221 DCHECK_NE(handle_, kInvalidHandle); |
197 size_t count = 0; | 222 size_t count = 0; |
198 while (count < length) { | 223 while (count < length) { |
199 DWORD len; | 224 DWORD len; |
200 DWORD chunk = GetNextChunkSize(count, length); | 225 DWORD chunk = GetNextChunkSize(count, length); |
201 if (WriteFile(handle_, static_cast<const char*>(buffer) + count, | 226 if (WriteFile(handle_, static_cast<const char*>(buffer) + count, |
202 chunk, &len, NULL) == FALSE) { | 227 chunk, &len, NULL) == FALSE) { |
203 return (0 < count) ? count : 0; | 228 return count; |
204 } | 229 } |
205 count += len; | 230 count += len; |
206 } | 231 } |
207 return count; | 232 return count; |
208 } | 233 } |
209 | 234 |
| 235 size_t SyncSocket::ReceiveWithTimeout(void* buffer, |
| 236 size_t length, |
| 237 TimeDelta timeout) { |
| 238 NOTIMPLEMENTED(); |
| 239 return 0; |
| 240 } |
| 241 |
210 size_t SyncSocket::Receive(void* buffer, size_t length) { | 242 size_t SyncSocket::Receive(void* buffer, size_t length) { |
| 243 ThreadRestrictions::AssertIOAllowed(); |
| 244 DCHECK_GT(length, 0u); |
211 DCHECK_LE(length, kMaxMessageLength); | 245 DCHECK_LE(length, kMaxMessageLength); |
| 246 DCHECK_NE(handle_, kInvalidHandle); |
212 size_t count = 0; | 247 size_t count = 0; |
213 while (count < length) { | 248 while (count < length) { |
214 DWORD len; | 249 DWORD len; |
215 DWORD chunk = GetNextChunkSize(count, length); | 250 DWORD chunk = GetNextChunkSize(count, length); |
216 if (ReadFile(handle_, static_cast<char*>(buffer) + count, | 251 if (ReadFile(handle_, static_cast<char*>(buffer) + count, |
217 chunk, &len, NULL) == FALSE) { | 252 chunk, &len, NULL) == FALSE) { |
218 return (0 < count) ? count : 0; | 253 return count; |
219 } | 254 } |
220 count += len; | 255 count += len; |
221 } | 256 } |
222 return count; | 257 return count; |
223 } | 258 } |
224 | 259 |
225 size_t SyncSocket::Peek() { | 260 size_t SyncSocket::Peek() { |
226 DWORD available = 0; | 261 DWORD available = 0; |
227 PeekNamedPipe(handle_, NULL, 0, NULL, &available, NULL); | 262 PeekNamedPipe(handle_, NULL, 0, NULL, &available, NULL); |
228 return available; | 263 return available; |
229 } | 264 } |
230 | 265 |
231 CancelableSyncSocket::CancelableSyncSocket() | 266 CancelableSyncSocket::CancelableSyncSocket() |
232 : shutdown_event_(true, false), file_operation_(true, false) { | 267 : shutdown_event_(true, false), file_operation_(true, false) { |
233 } | 268 } |
234 | 269 |
235 CancelableSyncSocket::CancelableSyncSocket(Handle handle) | 270 CancelableSyncSocket::CancelableSyncSocket(Handle handle) |
236 : SyncSocket(handle), shutdown_event_(true, false), | 271 : SyncSocket(handle), shutdown_event_(true, false), |
237 file_operation_(true, false) { | 272 file_operation_(true, false) { |
238 } | 273 } |
239 | 274 |
240 bool CancelableSyncSocket::Shutdown() { | 275 bool CancelableSyncSocket::Shutdown() { |
241 // This doesn't shut down the pipe immediately, but subsequent Receive or Send | 276 // This doesn't shut down the pipe immediately, but subsequent Receive or Send |
242 // methods will fail straight away. | 277 // methods will fail straight away. |
243 shutdown_event_.Signal(); | 278 shutdown_event_.Signal(); |
244 return true; | 279 return true; |
245 } | 280 } |
246 | 281 |
247 bool CancelableSyncSocket::Close() { | 282 bool CancelableSyncSocket::Close() { |
248 bool ret = SyncSocket::Close(); | 283 const bool result = SyncSocket::Close(); |
249 shutdown_event_.Reset(); | 284 shutdown_event_.Reset(); |
250 return ret; | 285 return result; |
251 } | 286 } |
252 | 287 |
253 size_t CancelableSyncSocket::Send(const void* buffer, size_t length) { | 288 size_t CancelableSyncSocket::Send(const void* buffer, size_t length) { |
254 static const DWORD kWaitTimeOutInMs = 500; | 289 static const DWORD kWaitTimeOutInMs = 500; |
255 return CancelableFileOperation( | 290 return CancelableFileOperation( |
256 &WriteFile, handle_, reinterpret_cast<const char*>(buffer), | 291 &WriteFile, handle_, reinterpret_cast<const char*>(buffer), |
257 length, &file_operation_, &shutdown_event_, this, kWaitTimeOutInMs); | 292 length, &file_operation_, &shutdown_event_, this, kWaitTimeOutInMs); |
258 } | 293 } |
259 | 294 |
260 size_t CancelableSyncSocket::Receive(void* buffer, size_t length) { | 295 size_t CancelableSyncSocket::Receive(void* buffer, size_t length) { |
261 return CancelableFileOperation(&ReadFile, handle_, | 296 return CancelableFileOperation( |
262 reinterpret_cast<char*>(buffer), length, &file_operation_, | 297 &ReadFile, handle_, reinterpret_cast<char*>(buffer), length, |
263 &shutdown_event_, this, INFINITE); | 298 &file_operation_, &shutdown_event_, this, INFINITE); |
| 299 } |
| 300 |
| 301 size_t CancelableSyncSocket::ReceiveWithTimeout(void* buffer, |
| 302 size_t length, |
| 303 TimeDelta timeout) { |
| 304 return CancelableFileOperation( |
| 305 &ReadFile, handle_, reinterpret_cast<char*>(buffer), length, |
| 306 &file_operation_, &shutdown_event_, this, timeout.InMilliseconds()); |
264 } | 307 } |
265 | 308 |
266 // static | 309 // static |
267 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a, | 310 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a, |
268 CancelableSyncSocket* socket_b) { | 311 CancelableSyncSocket* socket_b) { |
269 return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, true); | 312 return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, true); |
270 } | 313 } |
271 | 314 |
272 | |
273 } // namespace base | 315 } // namespace base |
OLD | NEW |