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
3 // found in the LICENSE file.
5 #include "base/sync_socket.h"
7 #include "base/logging.h"
8 #include "base/win/scoped_handle.h"
12 using win::ScopedHandle
;
15 // 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 // creation. Also keep the secure random number generation.
18 const wchar_t kPipeNameFormat
[] = L
"\\\\.\\pipe\\chrome.sync.%u.%u.%lu";
19 const size_t kPipePathMax
= arraysize(kPipeNameFormat
) + (3 * 10) + 1;
21 // 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 const size_t kMaxMessageLength
= static_cast<size_t>(INT_MAX
);
25 const int kOutBufferSize
= 4096;
26 const int kInBufferSize
= 4096;
27 const int kDefaultTimeoutMilliSeconds
= 1000;
29 bool CreatePairImpl(HANDLE
* socket_a
, HANDLE
* socket_b
, bool overlapped
) {
30 DCHECK(socket_a
!= socket_b
);
31 DCHECK(*socket_a
== SyncSocket::kInvalidHandle
);
32 DCHECK(*socket_b
== SyncSocket::kInvalidHandle
);
34 wchar_t name
[kPipePathMax
];
35 ScopedHandle handle_a
;
36 DWORD flags
= PIPE_ACCESS_DUPLEX
| FILE_FLAG_FIRST_PIPE_INSTANCE
;
38 flags
|= FILE_FLAG_OVERLAPPED
;
41 unsigned int rnd_name
;
42 if (rand_s(&rnd_name
) != 0)
45 swprintf(name
, kPipePathMax
,
47 GetCurrentProcessId(),
51 handle_a
.Set(CreateNamedPipeW(
54 PIPE_TYPE_BYTE
| PIPE_READMODE_BYTE
,
58 kDefaultTimeoutMilliSeconds
,
60 } while (!handle_a
.IsValid() &&
61 (GetLastError() == ERROR_PIPE_BUSY
));
63 if (!handle_a
.IsValid()) {
68 // The SECURITY_ANONYMOUS flag means that the server side (handle_a) cannot
69 // impersonate the client (handle_b). This allows us not to care which side
70 // ends up in which side of a privilege boundary.
71 flags
= SECURITY_SQOS_PRESENT
| SECURITY_ANONYMOUS
;
73 flags
|= FILE_FLAG_OVERLAPPED
;
75 ScopedHandle
handle_b(CreateFileW(name
,
76 GENERIC_READ
| GENERIC_WRITE
,
78 NULL
, // default security attributes.
79 OPEN_EXISTING
, // opens existing pipe.
81 NULL
)); // no template file.
82 if (!handle_b
.IsValid()) {
83 DPLOG(ERROR
) << "CreateFileW failed";
87 if (!ConnectNamedPipe(handle_a
, NULL
)) {
88 DWORD error
= GetLastError();
89 if (error
!= ERROR_PIPE_CONNECTED
) {
90 DPLOG(ERROR
) << "ConnectNamedPipe failed";
95 *socket_a
= handle_a
.Take();
96 *socket_b
= handle_b
.Take();
101 // Inline helper to avoid having the cast everywhere.
102 DWORD
GetNextChunkSize(size_t current_pos
, size_t max_size
) {
103 // The following statement is for 64 bit portability.
104 return static_cast<DWORD
>(((max_size
- current_pos
) <= UINT_MAX
) ?
105 (max_size
- current_pos
) : UINT_MAX
);
108 // Template function that supports calling ReadFile or WriteFile in an
109 // 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 // is cancelled, the function returns and closes the relevant socket object.
112 template <typename BufferType
, typename Function
>
113 size_t CancelableFileOperation(Function operation
, HANDLE file
,
114 BufferType
* buffer
, size_t length
,
115 base::WaitableEvent
* io_event
,
116 base::WaitableEvent
* cancel_event
,
117 CancelableSyncSocket
* socket
,
118 DWORD timeout_in_ms
) {
119 // 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
);
121 DCHECK_LE(length
, kMaxMessageLength
);
124 ol
.hEvent
= io_event
->handle();
126 while (count
< length
) {
127 DWORD chunk
= GetNextChunkSize(count
, length
);
128 // This is either the ReadFile or WriteFile call depending on whether
129 // we're receiving or sending data.
131 BOOL ok
= operation(file
, static_cast<BufferType
*>(buffer
) + count
, chunk
,
134 if (::GetLastError() == ERROR_IO_PENDING
) {
135 HANDLE events
[] = { io_event
->handle(), cancel_event
->handle() };
136 int wait_result
= WaitForMultipleObjects(
137 arraysize(events
), events
, FALSE
, timeout_in_ms
);
138 if (wait_result
== (WAIT_OBJECT_0
+ 0)) {
139 GetOverlappedResult(file
, &ol
, &len
, TRUE
);
140 } else if (wait_result
== (WAIT_OBJECT_0
+ 1)) {
141 VLOG(1) << "Shutdown was signaled. Closing socket.";
148 DCHECK_EQ(WAIT_TIMEOUT
, wait_result
);
149 if (!CancelIo(file
)){
150 DLOG(WARNING
) << "CancelIo() failed";
161 // Quit the operation if we can't write/read anymore.
166 return (count
> 0) ? count
: 0;
171 const SyncSocket::Handle
SyncSocket::kInvalidHandle
= INVALID_HANDLE_VALUE
;
173 SyncSocket::SyncSocket() : handle_(kInvalidHandle
) {}
175 SyncSocket::~SyncSocket() {
180 bool SyncSocket::CreatePair(SyncSocket
* socket_a
, SyncSocket
* socket_b
) {
181 return CreatePairImpl(&socket_a
->handle_
, &socket_b
->handle_
, false);
184 bool SyncSocket::Close() {
185 if (handle_
== kInvalidHandle
)
188 BOOL retval
= CloseHandle(handle_
);
189 handle_
= kInvalidHandle
;
190 return retval
? true : false;
193 size_t SyncSocket::Send(const void* buffer
, size_t length
) {
194 DCHECK_LE(length
, kMaxMessageLength
);
196 while (count
< length
) {
198 DWORD chunk
= GetNextChunkSize(count
, length
);
199 if (WriteFile(handle_
, static_cast<const char*>(buffer
) + count
,
200 chunk
, &len
, NULL
) == FALSE
) {
201 return (0 < count
) ? count
: 0;
208 size_t SyncSocket::Receive(void* buffer
, size_t length
) {
209 DCHECK_LE(length
, kMaxMessageLength
);
211 while (count
< length
) {
213 DWORD chunk
= GetNextChunkSize(count
, length
);
214 if (ReadFile(handle_
, static_cast<char*>(buffer
) + count
,
215 chunk
, &len
, NULL
) == FALSE
) {
216 return (0 < count
) ? count
: 0;
223 size_t SyncSocket::Peek() {
225 PeekNamedPipe(handle_
, NULL
, 0, NULL
, &available
, NULL
);
229 CancelableSyncSocket::CancelableSyncSocket()
230 : shutdown_event_(true, false), file_operation_(true, false) {
233 CancelableSyncSocket::CancelableSyncSocket(Handle handle
)
234 : SyncSocket(handle
), shutdown_event_(true, false),
235 file_operation_(true, false) {
238 bool CancelableSyncSocket::Shutdown() {
239 // This doesn't shut down the pipe immediately, but subsequent Receive or Send
240 // methods will fail straight away.
241 shutdown_event_
.Signal();
245 bool CancelableSyncSocket::Close() {
246 bool ret
= SyncSocket::Close();
247 shutdown_event_
.Reset();
251 size_t CancelableSyncSocket::Send(const void* buffer
, size_t length
) {
252 static const DWORD kWaitTimeOutInMs
= 500;
253 return CancelableFileOperation(
254 &WriteFile
, handle_
, reinterpret_cast<const char*>(buffer
),
255 length
, &file_operation_
, &shutdown_event_
, this, kWaitTimeOutInMs
);
258 size_t CancelableSyncSocket::Receive(void* buffer
, size_t length
) {
259 return CancelableFileOperation(&ReadFile
, handle_
,
260 reinterpret_cast<char*>(buffer
), length
, &file_operation_
,
261 &shutdown_event_
, this, INFINITE
);
265 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket
* socket_a
,
266 CancelableSyncSocket
* socket_b
) {
267 return CreatePairImpl(&socket_a
->handle_
, &socket_b
->handle_
, true);