1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/sync_socket.h" 6 #include <limits.h> 7 #include <stdio.h> 8 #include <windows.h> 9 #include <sys/types.h> 10 #include "base/logging.h" 11 12 13 namespace base { 14 15 namespace { 16 // This prefix used to be appended to pipe names for pipes 17 // created in CreatePair. 18 const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\chrome.sync."; 19 const size_t kPipePrefixSize = arraysize(kPipePrefix); 20 const size_t kPathMax = 28; // print length of process id + pair count. 21 const size_t kPipePathMax = kPipePrefixSize + kPathMax + 1; 22 23 // To avoid users sending negative message lengths to Send/Receive 24 // we clamp message lengths, which are size_t, to no more than INT_MAX. 25 const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX); 26 27 const int kOutBufferSize = 4096; 28 const int kInBufferSize = 4096; 29 const int kDefaultTimeoutMilliSeconds = 1000; 30 31 static const SyncSocket::Handle kInvalidHandle = INVALID_HANDLE_VALUE; 32 33 } // namespace 34 35 bool SyncSocket::CreatePair(SyncSocket* pair[2]) { 36 Handle handles[2]; 37 SyncSocket* tmp_sockets[2]; 38 39 // Create the two SyncSocket objects first to avoid ugly cleanup issues. 40 tmp_sockets[0] = new SyncSocket(kInvalidHandle); 41 if (tmp_sockets[0] == NULL) { 42 return false; 43 } 44 tmp_sockets[1] = new SyncSocket(kInvalidHandle); 45 if (tmp_sockets[1] == NULL) { 46 delete tmp_sockets[0]; 47 return false; 48 } 49 50 wchar_t name[kPipePathMax]; 51 do { 52 unsigned int rnd_name; 53 if (rand_s(&rnd_name) != 0) 54 return false; 55 swprintf(name, kPipePathMax, L"%s%u.%lu", 56 kPipePrefix, GetCurrentProcessId(), 57 rnd_name); 58 handles[0] = CreateNamedPipeW( 59 name, 60 PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, 61 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 62 1, 63 kOutBufferSize, 64 kInBufferSize, 65 kDefaultTimeoutMilliSeconds, 66 NULL); 67 if (handles[0] == INVALID_HANDLE_VALUE && 68 GetLastError() != ERROR_ACCESS_DENIED && 69 GetLastError() != ERROR_PIPE_BUSY) { 70 return false; 71 } 72 } while (handles[0] == INVALID_HANDLE_VALUE); 73 handles[1] = CreateFileW(name, 74 GENERIC_READ | GENERIC_WRITE, 75 0, // no sharing. 76 NULL, // default security attributes. 77 OPEN_EXISTING, // opens existing pipe. 78 SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS, 79 // no impersonation. 80 NULL); // no template file. 81 if (handles[1] == INVALID_HANDLE_VALUE) { 82 CloseHandle(handles[0]); 83 return false; 84 } 85 if (ConnectNamedPipe(handles[0], NULL) == FALSE) { 86 DWORD error = GetLastError(); 87 if (error != ERROR_PIPE_CONNECTED) { 88 CloseHandle(handles[0]); 89 CloseHandle(handles[1]); 90 return false; 91 } 92 } 93 // Copy the handles out for successful return. 94 tmp_sockets[0]->handle_ = handles[0]; 95 pair[0] = tmp_sockets[0]; 96 tmp_sockets[1]->handle_ = handles[1]; 97 pair[1] = tmp_sockets[1]; 98 return true; 99 } 100 101 bool SyncSocket::Close() { 102 if (handle_ == kInvalidHandle) { 103 return false; 104 } 105 BOOL retval = CloseHandle(handle_); 106 handle_ = kInvalidHandle; 107 return retval ? true : false; 108 } 109 110 size_t SyncSocket::Send(const void* buffer, size_t length) { 111 DCHECK(length <= kMaxMessageLength); 112 size_t count = 0; 113 while (count < length) { 114 DWORD len; 115 // The following statement is for 64 bit portability. 116 DWORD chunk = static_cast<DWORD>( 117 ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX); 118 if (WriteFile(handle_, static_cast<const char*>(buffer) + count, 119 chunk, &len, NULL) == FALSE) { 120 return (0 < count) ? count : 0; 121 } 122 count += len; 123 } 124 return count; 125 } 126 127 size_t SyncSocket::Receive(void* buffer, size_t length) { 128 DCHECK(length <= kMaxMessageLength); 129 size_t count = 0; 130 while (count < length) { 131 DWORD len; 132 DWORD chunk = static_cast<DWORD>( 133 ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX); 134 if (ReadFile(handle_, static_cast<char*>(buffer) + count, 135 chunk, &len, NULL) == FALSE) { 136 return (0 < count) ? count : 0; 137 } 138 count += len; 139 } 140 return count; 141 } 142 143 size_t SyncSocket::Peek() { 144 DWORD available = 0; 145 PeekNamedPipe(handle_, NULL, 0, NULL, &available, NULL); 146 return available; 147 } 148 149 } // namespace base 150