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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 // The following statement is for 64 bit portability. | 104 // The following statement is for 64 bit portability. |
104 return static_cast<DWORD>(((max_size - current_pos) <= UINT_MAX) ? | 105 return static_cast<DWORD>(((max_size - current_pos) <= UINT_MAX) ? |
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, |
114 BufferType* buffer, size_t length, | 115 HANDLE file, |
115 base::WaitableEvent* io_event, | 116 BufferType* buffer, |
116 base::WaitableEvent* cancel_event, | 117 size_t length, |
| 118 WaitableEvent* io_event, |
| 119 WaitableEvent* cancel_event, |
117 CancelableSyncSocket* socket, | 120 CancelableSyncSocket* socket, |
118 DWORD timeout_in_ms) { | 121 DWORD timeout_in_ms) { |
| 122 ThreadRestrictions::AssertIOAllowed(); |
119 // The buffer must be byte size or the length check won't make much sense. | 123 // 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); | 124 COMPILE_ASSERT(sizeof(buffer[0]) == sizeof(char), incorrect_buffer_type); |
| 125 DCHECK_GT(length, 0u); |
121 DCHECK_LE(length, kMaxMessageLength); | 126 DCHECK_LE(length, kMaxMessageLength); |
| 127 DCHECK_NE(file, SyncSocket::kInvalidHandle); |
122 | 128 |
123 OVERLAPPED ol = {0}; | 129 // Track the finish time so we can calculate the timeout as data is read. |
124 ol.hEvent = io_event->handle(); | 130 TimeTicks current_time, finish_time; |
| 131 if (timeout_in_ms != INFINITE) { |
| 132 current_time = TimeTicks::Now(); |
| 133 finish_time = |
| 134 current_time + base::TimeDelta::FromMilliseconds(timeout_in_ms); |
| 135 } |
| 136 |
125 size_t count = 0; | 137 size_t count = 0; |
126 while (count < length) { | 138 do { |
127 DWORD chunk = GetNextChunkSize(count, length); | 139 // The OVERLAPPED structure will be modified by ReadFile or WriteFile. |
| 140 OVERLAPPED ol = { 0 }; |
| 141 ol.hEvent = io_event->handle(); |
| 142 |
| 143 const DWORD chunk = GetNextChunkSize(count, length); |
128 // This is either the ReadFile or WriteFile call depending on whether | 144 // This is either the ReadFile or WriteFile call depending on whether |
129 // we're receiving or sending data. | 145 // we're receiving or sending data. |
130 DWORD len = 0; | 146 DWORD len = 0; |
131 BOOL ok = operation(file, static_cast<BufferType*>(buffer) + count, chunk, | 147 const BOOL operation_ok = operation( |
132 &len, &ol); | 148 file, static_cast<BufferType*>(buffer) + count, chunk, &len, &ol); |
133 if (!ok) { | 149 if (!operation_ok) { |
134 if (::GetLastError() == ERROR_IO_PENDING) { | 150 if (::GetLastError() == ERROR_IO_PENDING) { |
135 HANDLE events[] = { io_event->handle(), cancel_event->handle() }; | 151 HANDLE events[] = { io_event->handle(), cancel_event->handle() }; |
136 int wait_result = WaitForMultipleObjects( | 152 const int wait_result = WaitForMultipleObjects( |
137 arraysize(events), events, FALSE, timeout_in_ms); | 153 ARRAYSIZE_UNSAFE(events), events, FALSE, |
| 154 timeout_in_ms == INFINITE |
| 155 ? timeout_in_ms |
| 156 : (finish_time - current_time).InMilliseconds()); |
138 if (wait_result == (WAIT_OBJECT_0 + 0)) { | 157 if (wait_result == (WAIT_OBJECT_0 + 0)) { |
139 GetOverlappedResult(file, &ol, &len, TRUE); | 158 GetOverlappedResult(file, &ol, &len, TRUE); |
140 } else if (wait_result == (WAIT_OBJECT_0 + 1)) { | 159 } else if (wait_result == (WAIT_OBJECT_0 + 1)) { |
141 VLOG(1) << "Shutdown was signaled. Closing socket."; | 160 DVLOG(1) << "Shutdown was signaled. Closing socket."; |
142 CancelIo(file); | 161 CancelIo(file); |
143 socket->Close(); | 162 socket->Close(); |
144 count = 0; | 163 count = 0; |
145 break; | 164 break; |
146 } else { | 165 } else { |
147 // Timeout happened. | 166 // Timeout happened. |
148 DCHECK_EQ(WAIT_TIMEOUT, wait_result); | 167 DCHECK_EQ(WAIT_TIMEOUT, wait_result); |
149 if (!CancelIo(file)){ | 168 if (!CancelIo(file)) |
150 DLOG(WARNING) << "CancelIo() failed"; | 169 DLOG(WARNING) << "CancelIo() failed"; |
151 } | |
152 break; | 170 break; |
153 } | 171 } |
154 } else { | 172 } else { |
155 break; | 173 break; |
156 } | 174 } |
157 } | 175 } |
158 | 176 |
159 count += len; | 177 count += len; |
160 | 178 |
161 // Quit the operation if we can't write/read anymore. | 179 // Quit the operation if we can't write/read anymore. |
162 if (len != chunk) | 180 if (len != chunk) |
163 break; | 181 break; |
164 } | |
165 | 182 |
166 return (count > 0) ? count : 0; | 183 // Since TimeTicks::Now() is expensive, only bother updating the time if we |
| 184 // have more work to do. |
| 185 if (timeout_in_ms != INFINITE && count < length) |
| 186 current_time = base::TimeTicks::Now(); |
| 187 } while (count < length && |
| 188 (timeout_in_ms == INFINITE || current_time < finish_time)); |
| 189 |
| 190 return count; |
167 } | 191 } |
168 | 192 |
169 } // namespace | 193 } // namespace |
170 | 194 |
171 #if defined(COMPONENT_BUILD) | 195 #if defined(COMPONENT_BUILD) |
172 const SyncSocket::Handle SyncSocket::kInvalidHandle = INVALID_HANDLE_VALUE; | 196 const SyncSocket::Handle SyncSocket::kInvalidHandle = INVALID_HANDLE_VALUE; |
173 #endif | 197 #endif |
174 | 198 |
175 SyncSocket::SyncSocket() : handle_(kInvalidHandle) {} | 199 SyncSocket::SyncSocket() : handle_(kInvalidHandle) {} |
176 | 200 |
177 SyncSocket::~SyncSocket() { | 201 SyncSocket::~SyncSocket() { |
178 Close(); | 202 Close(); |
179 } | 203 } |
180 | 204 |
181 // static | 205 // static |
182 bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) { | 206 bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) { |
183 return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, false); | 207 return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, false); |
184 } | 208 } |
185 | 209 |
186 bool SyncSocket::Close() { | 210 bool SyncSocket::Close() { |
187 if (handle_ == kInvalidHandle) | 211 if (handle_ == kInvalidHandle) |
188 return false; | 212 return true; |
189 | 213 |
190 BOOL retval = CloseHandle(handle_); | 214 const BOOL result = CloseHandle(handle_); |
191 handle_ = kInvalidHandle; | 215 handle_ = kInvalidHandle; |
192 return retval ? true : false; | 216 return result == TRUE; |
193 } | 217 } |
194 | 218 |
195 size_t SyncSocket::Send(const void* buffer, size_t length) { | 219 size_t SyncSocket::Send(const void* buffer, size_t length) { |
| 220 ThreadRestrictions::AssertIOAllowed(); |
| 221 DCHECK_GT(length, 0u); |
196 DCHECK_LE(length, kMaxMessageLength); | 222 DCHECK_LE(length, kMaxMessageLength); |
| 223 DCHECK_NE(handle_, kInvalidHandle); |
197 size_t count = 0; | 224 size_t count = 0; |
198 while (count < length) { | 225 while (count < length) { |
199 DWORD len; | 226 DWORD len; |
200 DWORD chunk = GetNextChunkSize(count, length); | 227 DWORD chunk = GetNextChunkSize(count, length); |
201 if (WriteFile(handle_, static_cast<const char*>(buffer) + count, | 228 if (WriteFile(handle_, static_cast<const char*>(buffer) + count, |
202 chunk, &len, NULL) == FALSE) { | 229 chunk, &len, NULL) == FALSE) { |
203 return (0 < count) ? count : 0; | 230 return count; |
204 } | 231 } |
205 count += len; | 232 count += len; |
206 } | 233 } |
207 return count; | 234 return count; |
208 } | 235 } |
209 | 236 |
| 237 size_t SyncSocket::ReceiveWithTimeout(void* buffer, |
| 238 size_t length, |
| 239 TimeDelta timeout) { |
| 240 NOTIMPLEMENTED(); |
| 241 return 0; |
| 242 } |
| 243 |
210 size_t SyncSocket::Receive(void* buffer, size_t length) { | 244 size_t SyncSocket::Receive(void* buffer, size_t length) { |
| 245 ThreadRestrictions::AssertIOAllowed(); |
| 246 DCHECK_GT(length, 0u); |
211 DCHECK_LE(length, kMaxMessageLength); | 247 DCHECK_LE(length, kMaxMessageLength); |
| 248 DCHECK_NE(handle_, kInvalidHandle); |
212 size_t count = 0; | 249 size_t count = 0; |
213 while (count < length) { | 250 while (count < length) { |
214 DWORD len; | 251 DWORD len; |
215 DWORD chunk = GetNextChunkSize(count, length); | 252 DWORD chunk = GetNextChunkSize(count, length); |
216 if (ReadFile(handle_, static_cast<char*>(buffer) + count, | 253 if (ReadFile(handle_, static_cast<char*>(buffer) + count, |
217 chunk, &len, NULL) == FALSE) { | 254 chunk, &len, NULL) == FALSE) { |
218 return (0 < count) ? count : 0; | 255 return count; |
219 } | 256 } |
220 count += len; | 257 count += len; |
221 } | 258 } |
222 return count; | 259 return count; |
223 } | 260 } |
224 | 261 |
225 size_t SyncSocket::Peek() { | 262 size_t SyncSocket::Peek() { |
226 DWORD available = 0; | 263 DWORD available = 0; |
227 PeekNamedPipe(handle_, NULL, 0, NULL, &available, NULL); | 264 PeekNamedPipe(handle_, NULL, 0, NULL, &available, NULL); |
228 return available; | 265 return available; |
229 } | 266 } |
230 | 267 |
231 CancelableSyncSocket::CancelableSyncSocket() | 268 CancelableSyncSocket::CancelableSyncSocket() |
232 : shutdown_event_(true, false), file_operation_(true, false) { | 269 : shutdown_event_(true, false), file_operation_(true, false) { |
233 } | 270 } |
234 | 271 |
235 CancelableSyncSocket::CancelableSyncSocket(Handle handle) | 272 CancelableSyncSocket::CancelableSyncSocket(Handle handle) |
236 : SyncSocket(handle), shutdown_event_(true, false), | 273 : SyncSocket(handle), shutdown_event_(true, false), |
237 file_operation_(true, false) { | 274 file_operation_(true, false) { |
238 } | 275 } |
239 | 276 |
240 bool CancelableSyncSocket::Shutdown() { | 277 bool CancelableSyncSocket::Shutdown() { |
241 // This doesn't shut down the pipe immediately, but subsequent Receive or Send | 278 // This doesn't shut down the pipe immediately, but subsequent Receive or Send |
242 // methods will fail straight away. | 279 // methods will fail straight away. |
243 shutdown_event_.Signal(); | 280 shutdown_event_.Signal(); |
244 return true; | 281 return true; |
245 } | 282 } |
246 | 283 |
247 bool CancelableSyncSocket::Close() { | 284 bool CancelableSyncSocket::Close() { |
248 bool ret = SyncSocket::Close(); | 285 const bool result = SyncSocket::Close(); |
249 shutdown_event_.Reset(); | 286 shutdown_event_.Reset(); |
250 return ret; | 287 return result; |
251 } | 288 } |
252 | 289 |
253 size_t CancelableSyncSocket::Send(const void* buffer, size_t length) { | 290 size_t CancelableSyncSocket::Send(const void* buffer, size_t length) { |
254 static const DWORD kWaitTimeOutInMs = 500; | 291 static const DWORD kWaitTimeOutInMs = 500; |
255 return CancelableFileOperation( | 292 return CancelableFileOperation( |
256 &WriteFile, handle_, reinterpret_cast<const char*>(buffer), | 293 &WriteFile, handle_, reinterpret_cast<const char*>(buffer), |
257 length, &file_operation_, &shutdown_event_, this, kWaitTimeOutInMs); | 294 length, &file_operation_, &shutdown_event_, this, kWaitTimeOutInMs); |
258 } | 295 } |
259 | 296 |
260 size_t CancelableSyncSocket::Receive(void* buffer, size_t length) { | 297 size_t CancelableSyncSocket::Receive(void* buffer, size_t length) { |
261 return CancelableFileOperation(&ReadFile, handle_, | 298 return CancelableFileOperation( |
262 reinterpret_cast<char*>(buffer), length, &file_operation_, | 299 &ReadFile, handle_, reinterpret_cast<char*>(buffer), length, |
263 &shutdown_event_, this, INFINITE); | 300 &file_operation_, &shutdown_event_, this, INFINITE); |
| 301 } |
| 302 |
| 303 size_t CancelableSyncSocket::ReceiveWithTimeout(void* buffer, |
| 304 size_t length, |
| 305 TimeDelta timeout) { |
| 306 return CancelableFileOperation( |
| 307 &ReadFile, handle_, reinterpret_cast<char*>(buffer), length, |
| 308 &file_operation_, &shutdown_event_, this, timeout.InMilliseconds()); |
264 } | 309 } |
265 | 310 |
266 // static | 311 // static |
267 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a, | 312 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a, |
268 CancelableSyncSocket* socket_b) { | 313 CancelableSyncSocket* socket_b) { |
269 return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, true); | 314 return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, true); |
270 } | 315 } |
271 | 316 |
272 | |
273 } // namespace base | 317 } // namespace base |
OLD | NEW |