| // Copyright (c) 2009 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 { |
| // This prefix used to be appended to pipe names for pipes |
| // created in CreatePair. |
| const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\chrome.sync."; |
| const size_t kPipePrefixSize = arraysize(kPipePrefix); |
| const size_t kPathMax = 28; // print length of process id + pair count. |
| const size_t kPipePathMax = kPipePrefixSize + kPathMax + 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; |
| |
| static const SyncSocket::Handle kInvalidHandle = INVALID_HANDLE_VALUE; |
| |
| } // namespace |
| |
| 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, L"%s%u.%lu", |
| kPipePrefix, GetCurrentProcessId(), |
| 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); |
| if (handles[0] == INVALID_HANDLE_VALUE && |
| GetLastError() != ERROR_ACCESS_DENIED && |
| GetLastError() != ERROR_PIPE_BUSY) { |
| return false; |
| } |
| } while (handles[0] == INVALID_HANDLE_VALUE); |
| 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, |
| // no impersonation. |
| 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(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(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 |