// 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/atomicops.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