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