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 // CancelIo() doesn't synchronously cancel outstanding IO, only marks
159 // outstanding IO for cancellation. We must call GetOverlappedResult()
160 // below to ensure in flight writes complete before returning.
164 // We set the |bWait| parameter to TRUE for GetOverlappedResult() to
165 // ensure writes are complete before returning.
166 if (!GetOverlappedResult(file
, &ol
, &len
, TRUE
))
169 if (wait_result
== WAIT_OBJECT_0
+ 1) {
170 DVLOG(1) << "Shutdown was signaled. Closing socket.";
175 // Timeouts will be handled by the while() condition below since
176 // GetOverlappedResult() may complete successfully after CancelIo().
177 DCHECK(wait_result
== WAIT_OBJECT_0
+ 0 || wait_result
== WAIT_TIMEOUT
);
185 // Quit the operation if we can't write/read anymore.
189 // Since TimeTicks::Now() is expensive, only bother updating the time if we
190 // have more work to do.
191 if (timeout_in_ms
!= INFINITE
&& count
< length
)
192 current_time
= base::TimeTicks::Now();
193 } while (count
< length
&&
194 (timeout_in_ms
== INFINITE
|| current_time
< finish_time
));
201 #if defined(COMPONENT_BUILD)
202 const SyncSocket::Handle
SyncSocket::kInvalidHandle
= INVALID_HANDLE_VALUE
;
205 SyncSocket::SyncSocket() : handle_(kInvalidHandle
) {}
207 SyncSocket::~SyncSocket() {
212 bool SyncSocket::CreatePair(SyncSocket
* socket_a
, SyncSocket
* socket_b
) {
213 return CreatePairImpl(&socket_a
->handle_
, &socket_b
->handle_
, false);
217 SyncSocket::Handle
SyncSocket::UnwrapHandle(
218 const TransitDescriptor
& descriptor
) {
222 bool SyncSocket::PrepareTransitDescriptor(ProcessHandle peer_process_handle
,
223 TransitDescriptor
* descriptor
) {
225 if (!::DuplicateHandle(GetCurrentProcess(), handle(), peer_process_handle
,
226 descriptor
, 0, FALSE
, DUPLICATE_SAME_ACCESS
)) {
227 DPLOG(ERROR
) << "Cannot duplicate socket handle for peer process.";
233 bool SyncSocket::Close() {
234 if (handle_
== kInvalidHandle
)
237 const BOOL result
= CloseHandle(handle_
);
238 handle_
= kInvalidHandle
;
239 return result
== TRUE
;
242 size_t SyncSocket::Send(const void* buffer
, size_t length
) {
243 ThreadRestrictions::AssertIOAllowed();
244 DCHECK_GT(length
, 0u);
245 DCHECK_LE(length
, kMaxMessageLength
);
246 DCHECK_NE(handle_
, kInvalidHandle
);
248 while (count
< length
) {
250 DWORD chunk
= GetNextChunkSize(count
, length
);
251 if (WriteFile(handle_
, static_cast<const char*>(buffer
) + count
,
252 chunk
, &len
, NULL
) == FALSE
) {
260 size_t SyncSocket::ReceiveWithTimeout(void* buffer
,
267 size_t SyncSocket::Receive(void* buffer
, size_t length
) {
268 ThreadRestrictions::AssertIOAllowed();
269 DCHECK_GT(length
, 0u);
270 DCHECK_LE(length
, kMaxMessageLength
);
271 DCHECK_NE(handle_
, kInvalidHandle
);
273 while (count
< length
) {
275 DWORD chunk
= GetNextChunkSize(count
, length
);
276 if (ReadFile(handle_
, static_cast<char*>(buffer
) + count
,
277 chunk
, &len
, NULL
) == FALSE
) {
285 size_t SyncSocket::Peek() {
287 PeekNamedPipe(handle_
, NULL
, 0, NULL
, &available
, NULL
);
291 CancelableSyncSocket::CancelableSyncSocket()
292 : shutdown_event_(true, false), file_operation_(true, false) {
295 CancelableSyncSocket::CancelableSyncSocket(Handle handle
)
296 : SyncSocket(handle
), shutdown_event_(true, false),
297 file_operation_(true, false) {
300 bool CancelableSyncSocket::Shutdown() {
301 // This doesn't shut down the pipe immediately, but subsequent Receive or Send
302 // methods will fail straight away.
303 shutdown_event_
.Signal();
307 bool CancelableSyncSocket::Close() {
308 const bool result
= SyncSocket::Close();
309 shutdown_event_
.Reset();
313 size_t CancelableSyncSocket::Send(const void* buffer
, size_t length
) {
314 static const DWORD kWaitTimeOutInMs
= 500;
315 return CancelableFileOperation(
316 &WriteFile
, handle_
, reinterpret_cast<const char*>(buffer
),
317 length
, &file_operation_
, &shutdown_event_
, this, kWaitTimeOutInMs
);
320 size_t CancelableSyncSocket::Receive(void* buffer
, size_t length
) {
321 return CancelableFileOperation(
322 &ReadFile
, handle_
, reinterpret_cast<char*>(buffer
), length
,
323 &file_operation_
, &shutdown_event_
, this, INFINITE
);
326 size_t CancelableSyncSocket::ReceiveWithTimeout(void* buffer
,
329 return CancelableFileOperation(
330 &ReadFile
, handle_
, reinterpret_cast<char*>(buffer
), length
,
331 &file_operation_
, &shutdown_event_
, this, timeout
.InMilliseconds());
335 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket
* socket_a
,
336 CancelableSyncSocket
* socket_b
) {
337 return CreatePairImpl(&socket_a
->handle_
, &socket_b
->handle_
, true);