| 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 |