| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/sync_socket.h" |
| #include <limits.h> |
| #include <stdio.h> |
| #include <windows.h> |
| #include <sys/types.h> |
| #include "base/logging.h" |
| |
| namespace base { |
| |
| namespace { |
| // IMPORTANT: do not change how this name is generated because it will break |
| // in sandboxed scenarios as we might have by-name policies that allow pipe |
| // creation. Also keep the secure random number generation. |
| const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\chrome.sync.%u.%u.%lu"; |
| const size_t kPipePathMax = arraysize(kPipeNameFormat) + (3 * 10) + 1; |
| |
| // To avoid users sending negative message lengths to Send/Receive |
| // we clamp message lengths, which are size_t, to no more than INT_MAX. |
| const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX); |
| |
| const int kOutBufferSize = 4096; |
| const int kInBufferSize = 4096; |
| const int kDefaultTimeoutMilliSeconds = 1000; |
| |
| } // namespace |
| |
| const SyncSocket::Handle SyncSocket::kInvalidHandle = INVALID_HANDLE_VALUE; |
| |
| bool SyncSocket::CreatePair(SyncSocket* pair[2]) { |
| Handle handles[2]; |
| SyncSocket* tmp_sockets[2]; |
| |
| // Create the two SyncSocket objects first to avoid ugly cleanup issues. |
| tmp_sockets[0] = new SyncSocket(kInvalidHandle); |
| if (tmp_sockets[0] == NULL) { |
| return false; |
| } |
| tmp_sockets[1] = new SyncSocket(kInvalidHandle); |
| if (tmp_sockets[1] == NULL) { |
| delete tmp_sockets[0]; |
| return false; |
| } |
| |
| wchar_t name[kPipePathMax]; |
| do { |
| unsigned int rnd_name; |
| if (rand_s(&rnd_name) != 0) |
| return false; |
| swprintf(name, kPipePathMax, |
| kPipeNameFormat, |
| GetCurrentProcessId(), |
| GetCurrentThreadId(), |
| rnd_name); |
| handles[0] = CreateNamedPipeW( |
| name, |
| PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, |
| PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, |
| 1, |
| kOutBufferSize, |
| kInBufferSize, |
| kDefaultTimeoutMilliSeconds, |
| NULL); |
| } while ((handles[0] == INVALID_HANDLE_VALUE) && |
| (GetLastError() == ERROR_PIPE_BUSY)); |
| |
| if (handles[0] == INVALID_HANDLE_VALUE) { |
| NOTREACHED(); |
| return false; |
| } |
| // The SECURITY_ANONYMOUS flag means that the server side (pair[0]) cannot |
| // impersonate the client (pair[1]). This allows us not to care which side |
| // ends up in which side of a privilege boundary. |
| handles[1] = CreateFileW(name, |
| GENERIC_READ | GENERIC_WRITE, |
| 0, // no sharing. |
| NULL, // default security attributes. |
| OPEN_EXISTING, // opens existing pipe. |
| SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS, |
| NULL); // no template file. |
| if (handles[1] == INVALID_HANDLE_VALUE) { |
| CloseHandle(handles[0]); |
| return false; |
| } |
| if (ConnectNamedPipe(handles[0], NULL) == FALSE) { |
| DWORD error = GetLastError(); |
| if (error != ERROR_PIPE_CONNECTED) { |
| CloseHandle(handles[0]); |
| CloseHandle(handles[1]); |
| return false; |
| } |
| } |
| // Copy the handles out for successful return. |
| tmp_sockets[0]->handle_ = handles[0]; |
| pair[0] = tmp_sockets[0]; |
| tmp_sockets[1]->handle_ = handles[1]; |
| pair[1] = tmp_sockets[1]; |
| return true; |
| } |
| |
| bool SyncSocket::Close() { |
| if (handle_ == kInvalidHandle) { |
| return false; |
| } |
| BOOL retval = CloseHandle(handle_); |
| handle_ = kInvalidHandle; |
| return retval ? true : false; |
| } |
| |
| size_t SyncSocket::Send(const void* buffer, size_t length) { |
| DCHECK_LE(length, kMaxMessageLength); |
| size_t count = 0; |
| while (count < length) { |
| DWORD len; |
| // The following statement is for 64 bit portability. |
| DWORD chunk = static_cast<DWORD>( |
| ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX); |
| if (WriteFile(handle_, static_cast<const char*>(buffer) + count, |
| chunk, &len, NULL) == FALSE) { |
| return (0 < count) ? count : 0; |
| } |
| count += len; |
| } |
| return count; |
| } |
| |
| size_t SyncSocket::Receive(void* buffer, size_t length) { |
| DCHECK_LE(length, kMaxMessageLength); |
| size_t count = 0; |
| while (count < length) { |
| DWORD len; |
| DWORD chunk = static_cast<DWORD>( |
| ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX); |
| if (ReadFile(handle_, static_cast<char*>(buffer) + count, |
| chunk, &len, NULL) == FALSE) { |
| return (0 < count) ? count : 0; |
| } |
| count += len; |
| } |
| return count; |
| } |
| |
| size_t SyncSocket::Peek() { |
| DWORD available = 0; |
| PeekNamedPipe(handle_, NULL, 0, NULL, &available, NULL); |
| return available; |
| } |
| |
| } // namespace base |