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/threading/thread_restrictions.h"
9 #include "base/win/scoped_handle.h"
13 using win::ScopedHandle
;
16 // IMPORTANT: do not change how this name is generated because it will break
17 // in sandboxed scenarios as we might have by-name policies that allow pipe
18 // creation. Also keep the secure random number generation.
19 const wchar_t kPipeNameFormat
[] = L
"\\\\.\\pipe\\chrome.sync.%u.%u.%lu";
20 const size_t kPipePathMax
= arraysize(kPipeNameFormat
) + (3 * 10) + 1;
22 // To avoid users sending negative message lengths to Send/Receive
23 // we clamp message lengths, which are size_t, to no more than INT_MAX.
24 const size_t kMaxMessageLength
= static_cast<size_t>(INT_MAX
);
26 const int kOutBufferSize
= 4096;
27 const int kInBufferSize
= 4096;
28 const int kDefaultTimeoutMilliSeconds
= 1000;
30 bool CreatePairImpl(HANDLE
* socket_a
, HANDLE
* socket_b
, bool overlapped
) {
31 DCHECK_NE(socket_a
, socket_b
);
32 DCHECK_EQ(*socket_a
, SyncSocket::kInvalidHandle
);
33 DCHECK_EQ(*socket_b
, SyncSocket::kInvalidHandle
);
35 wchar_t name
[kPipePathMax
];
36 ScopedHandle handle_a
;
37 DWORD flags
= PIPE_ACCESS_DUPLEX
| FILE_FLAG_FIRST_PIPE_INSTANCE
;
39 flags
|= FILE_FLAG_OVERLAPPED
;
42 unsigned int rnd_name
;
43 if (rand_s(&rnd_name
) != 0)
46 swprintf(name
, kPipePathMax
,
48 GetCurrentProcessId(),
52 handle_a
.Set(CreateNamedPipeW(
55 PIPE_TYPE_BYTE
| PIPE_READMODE_BYTE
,
59 kDefaultTimeoutMilliSeconds
,
61 } while (!handle_a
.IsValid() &&
62 (GetLastError() == ERROR_PIPE_BUSY
));
64 if (!handle_a
.IsValid()) {
69 // The SECURITY_ANONYMOUS flag means that the server side (handle_a) cannot
70 // impersonate the client (handle_b). This allows us not to care which side
71 // ends up in which side of a privilege boundary.
72 flags
= SECURITY_SQOS_PRESENT
| SECURITY_ANONYMOUS
;
74 flags
|= FILE_FLAG_OVERLAPPED
;
76 ScopedHandle
handle_b(CreateFileW(name
,
77 GENERIC_READ
| GENERIC_WRITE
,
79 NULL
, // default security attributes.
80 OPEN_EXISTING
, // opens existing pipe.
82 NULL
)); // no template file.
83 if (!handle_b
.IsValid()) {
84 DPLOG(ERROR
) << "CreateFileW failed";
88 if (!ConnectNamedPipe(handle_a
, NULL
)) {
89 DWORD error
= GetLastError();
90 if (error
!= ERROR_PIPE_CONNECTED
) {
91 DPLOG(ERROR
) << "ConnectNamedPipe failed";
96 *socket_a
= handle_a
.Take();
97 *socket_b
= handle_b
.Take();
102 // Inline helper to avoid having the cast everywhere.
103 DWORD
GetNextChunkSize(size_t current_pos
, size_t max_size
) {
104 // The following statement is for 64 bit portability.
105 return static_cast<DWORD
>(((max_size
- current_pos
) <= UINT_MAX
) ?
106 (max_size
- current_pos
) : UINT_MAX
);
109 // Template function that supports calling ReadFile or WriteFile in an
110 // overlapped fashion and waits for IO completion. The function also waits
111 // on an event that can be used to cancel the operation. If the operation
112 // is cancelled, the function returns and closes the relevant socket object.
113 template <typename BufferType
, typename Function
>
114 size_t CancelableFileOperation(Function operation
,
118 WaitableEvent
* io_event
,
119 WaitableEvent
* cancel_event
,
120 CancelableSyncSocket
* socket
,
121 DWORD timeout_in_ms
) {
122 ThreadRestrictions::AssertIOAllowed();
123 // The buffer must be byte size or the length check won't make much sense.
124 COMPILE_ASSERT(sizeof(buffer
[0]) == sizeof(char), incorrect_buffer_type
);
125 DCHECK_GT(length
, 0u);
126 DCHECK_LE(length
, kMaxMessageLength
);
127 DCHECK_NE(file
, SyncSocket::kInvalidHandle
);
129 // Track the finish time so we can calculate the timeout as data is read.
130 TimeTicks current_time
, finish_time
;
131 if (timeout_in_ms
!= INFINITE
) {
132 current_time
= TimeTicks::Now();
134 current_time
+ base::TimeDelta::FromMilliseconds(timeout_in_ms
);
139 // The OVERLAPPED structure will be modified by ReadFile or WriteFile.
140 OVERLAPPED ol
= { 0 };
141 ol
.hEvent
= io_event
->handle();
143 const DWORD chunk
= GetNextChunkSize(count
, length
);
144 // This is either the ReadFile or WriteFile call depending on whether
145 // we're receiving or sending data.
147 const BOOL operation_ok
= operation(
148 file
, static_cast<BufferType
*>(buffer
) + count
, chunk
, &len
, &ol
);
150 if (::GetLastError() == ERROR_IO_PENDING
) {
151 HANDLE events
[] = { io_event
->handle(), cancel_event
->handle() };
152 const int wait_result
= WaitForMultipleObjects(
153 ARRAYSIZE_UNSAFE(events
), events
, FALSE
,
154 timeout_in_ms
== INFINITE
156 : (finish_time
- current_time
).InMilliseconds());
157 if (wait_result
== (WAIT_OBJECT_0
+ 0)) {
158 GetOverlappedResult(file
, &ol
, &len
, TRUE
);
159 } else if (wait_result
== (WAIT_OBJECT_0
+ 1)) {
160 DVLOG(1) << "Shutdown was signaled. Closing socket.";
167 DCHECK_EQ(WAIT_TIMEOUT
, wait_result
);
169 DLOG(WARNING
) << "CancelIo() failed";
179 // Quit the operation if we can't write/read anymore.
183 // Since TimeTicks::Now() is expensive, only bother updating the time if we
184 // have more work to do.
185 if (timeout_in_ms
!= INFINITE
&& count
< length
)
186 current_time
= base::TimeTicks::Now();
187 } while (count
< length
&&
188 (timeout_in_ms
== INFINITE
|| current_time
< finish_time
));
195 #if defined(COMPONENT_BUILD)
196 const SyncSocket::Handle
SyncSocket::kInvalidHandle
= INVALID_HANDLE_VALUE
;
199 SyncSocket::SyncSocket() : handle_(kInvalidHandle
) {}
201 SyncSocket::~SyncSocket() {
206 bool SyncSocket::CreatePair(SyncSocket
* socket_a
, SyncSocket
* socket_b
) {
207 return CreatePairImpl(&socket_a
->handle_
, &socket_b
->handle_
, false);
211 SyncSocket::Handle
SyncSocket::UnwrapHandle(
212 const TransitDescriptor
& descriptor
) {
216 bool SyncSocket::PrepareTransitDescriptor(ProcessHandle peer_process_handle
,
217 TransitDescriptor
* descriptor
) {
219 if (!::DuplicateHandle(GetCurrentProcess(), handle(), peer_process_handle
,
220 descriptor
, 0, FALSE
, DUPLICATE_SAME_ACCESS
)) {
221 DPLOG(ERROR
) << "Cannot duplicate socket handle for peer process.";
227 bool SyncSocket::Close() {
228 if (handle_
== kInvalidHandle
)
231 const BOOL result
= CloseHandle(handle_
);
232 handle_
= kInvalidHandle
;
233 return result
== TRUE
;
236 size_t SyncSocket::Send(const void* buffer
, size_t length
) {
237 ThreadRestrictions::AssertIOAllowed();
238 DCHECK_GT(length
, 0u);
239 DCHECK_LE(length
, kMaxMessageLength
);
240 DCHECK_NE(handle_
, kInvalidHandle
);
242 while (count
< length
) {
244 DWORD chunk
= GetNextChunkSize(count
, length
);
245 if (WriteFile(handle_
, static_cast<const char*>(buffer
) + count
,
246 chunk
, &len
, NULL
) == FALSE
) {
254 size_t SyncSocket::ReceiveWithTimeout(void* buffer
,
261 size_t SyncSocket::Receive(void* buffer
, size_t length
) {
262 ThreadRestrictions::AssertIOAllowed();
263 DCHECK_GT(length
, 0u);
264 DCHECK_LE(length
, kMaxMessageLength
);
265 DCHECK_NE(handle_
, kInvalidHandle
);
267 while (count
< length
) {
269 DWORD chunk
= GetNextChunkSize(count
, length
);
270 if (ReadFile(handle_
, static_cast<char*>(buffer
) + count
,
271 chunk
, &len
, NULL
) == FALSE
) {
279 size_t SyncSocket::Peek() {
281 PeekNamedPipe(handle_
, NULL
, 0, NULL
, &available
, NULL
);
285 CancelableSyncSocket::CancelableSyncSocket()
286 : shutdown_event_(true, false), file_operation_(true, false) {
289 CancelableSyncSocket::CancelableSyncSocket(Handle handle
)
290 : SyncSocket(handle
), shutdown_event_(true, false),
291 file_operation_(true, false) {
294 bool CancelableSyncSocket::Shutdown() {
295 // This doesn't shut down the pipe immediately, but subsequent Receive or Send
296 // methods will fail straight away.
297 shutdown_event_
.Signal();
301 bool CancelableSyncSocket::Close() {
302 const bool result
= SyncSocket::Close();
303 shutdown_event_
.Reset();
307 size_t CancelableSyncSocket::Send(const void* buffer
, size_t length
) {
308 static const DWORD kWaitTimeOutInMs
= 500;
309 return CancelableFileOperation(
310 &WriteFile
, handle_
, reinterpret_cast<const char*>(buffer
),
311 length
, &file_operation_
, &shutdown_event_
, this, kWaitTimeOutInMs
);
314 size_t CancelableSyncSocket::Receive(void* buffer
, size_t length
) {
315 return CancelableFileOperation(
316 &ReadFile
, handle_
, reinterpret_cast<char*>(buffer
), length
,
317 &file_operation_
, &shutdown_event_
, this, INFINITE
);
320 size_t CancelableSyncSocket::ReceiveWithTimeout(void* buffer
,
323 return CancelableFileOperation(
324 &ReadFile
, handle_
, reinterpret_cast<char*>(buffer
), length
,
325 &file_operation_
, &shutdown_event_
, this, timeout
.InMilliseconds());
329 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket
* socket_a
,
330 CancelableSyncSocket
* socket_b
) {
331 return CreatePairImpl(&socket_a
->handle_
, &socket_b
->handle_
, true);