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
.Get(), 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
?
157 (finish_time
- current_time
).InMilliseconds()));
158 if (wait_result
!= WAIT_OBJECT_0
+ 0) {
159 // CancelIo() doesn't synchronously cancel outstanding IO, only marks
160 // outstanding IO for cancellation. We must call GetOverlappedResult()
161 // below to ensure in flight writes complete before returning.
165 // We set the |bWait| parameter to TRUE for GetOverlappedResult() to
166 // ensure writes are complete before returning.
167 if (!GetOverlappedResult(file
, &ol
, &len
, TRUE
))
170 if (wait_result
== WAIT_OBJECT_0
+ 1) {
171 DVLOG(1) << "Shutdown was signaled. Closing socket.";
176 // Timeouts will be handled by the while() condition below since
177 // GetOverlappedResult() may complete successfully after CancelIo().
178 DCHECK(wait_result
== WAIT_OBJECT_0
+ 0 || wait_result
== WAIT_TIMEOUT
);
186 // Quit the operation if we can't write/read anymore.
190 // Since TimeTicks::Now() is expensive, only bother updating the time if we
191 // have more work to do.
192 if (timeout_in_ms
!= INFINITE
&& count
< length
)
193 current_time
= base::TimeTicks::Now();
194 } while (count
< length
&&
195 (timeout_in_ms
== INFINITE
|| current_time
< finish_time
));
202 #if defined(COMPONENT_BUILD)
203 const SyncSocket::Handle
SyncSocket::kInvalidHandle
= INVALID_HANDLE_VALUE
;
206 SyncSocket::SyncSocket() : handle_(kInvalidHandle
) {}
208 SyncSocket::~SyncSocket() {
213 bool SyncSocket::CreatePair(SyncSocket
* socket_a
, SyncSocket
* socket_b
) {
214 return CreatePairImpl(&socket_a
->handle_
, &socket_b
->handle_
, false);
218 SyncSocket::Handle
SyncSocket::UnwrapHandle(
219 const TransitDescriptor
& descriptor
) {
223 bool SyncSocket::PrepareTransitDescriptor(ProcessHandle peer_process_handle
,
224 TransitDescriptor
* descriptor
) {
226 if (!::DuplicateHandle(GetCurrentProcess(), handle(), peer_process_handle
,
227 descriptor
, 0, FALSE
, DUPLICATE_SAME_ACCESS
)) {
228 DPLOG(ERROR
) << "Cannot duplicate socket handle for peer process.";
234 bool SyncSocket::Close() {
235 if (handle_
== kInvalidHandle
)
238 const BOOL result
= CloseHandle(handle_
);
239 handle_
= kInvalidHandle
;
240 return result
== TRUE
;
243 size_t SyncSocket::Send(const void* buffer
, size_t length
) {
244 ThreadRestrictions::AssertIOAllowed();
245 DCHECK_GT(length
, 0u);
246 DCHECK_LE(length
, kMaxMessageLength
);
247 DCHECK_NE(handle_
, kInvalidHandle
);
249 while (count
< length
) {
251 DWORD chunk
= GetNextChunkSize(count
, length
);
252 if (WriteFile(handle_
, static_cast<const char*>(buffer
) + count
,
253 chunk
, &len
, NULL
) == FALSE
) {
261 size_t SyncSocket::ReceiveWithTimeout(void* buffer
,
268 size_t SyncSocket::Receive(void* buffer
, size_t length
) {
269 ThreadRestrictions::AssertIOAllowed();
270 DCHECK_GT(length
, 0u);
271 DCHECK_LE(length
, kMaxMessageLength
);
272 DCHECK_NE(handle_
, kInvalidHandle
);
274 while (count
< length
) {
276 DWORD chunk
= GetNextChunkSize(count
, length
);
277 if (ReadFile(handle_
, static_cast<char*>(buffer
) + count
,
278 chunk
, &len
, NULL
) == FALSE
) {
286 size_t SyncSocket::Peek() {
288 PeekNamedPipe(handle_
, NULL
, 0, NULL
, &available
, NULL
);
292 CancelableSyncSocket::CancelableSyncSocket()
293 : shutdown_event_(true, false), file_operation_(true, false) {
296 CancelableSyncSocket::CancelableSyncSocket(Handle handle
)
297 : SyncSocket(handle
), shutdown_event_(true, false),
298 file_operation_(true, false) {
301 bool CancelableSyncSocket::Shutdown() {
302 // This doesn't shut down the pipe immediately, but subsequent Receive or Send
303 // methods will fail straight away.
304 shutdown_event_
.Signal();
308 bool CancelableSyncSocket::Close() {
309 const bool result
= SyncSocket::Close();
310 shutdown_event_
.Reset();
314 size_t CancelableSyncSocket::Send(const void* buffer
, size_t length
) {
315 static const DWORD kWaitTimeOutInMs
= 500;
316 return CancelableFileOperation(
317 &WriteFile
, handle_
, reinterpret_cast<const char*>(buffer
),
318 length
, &file_operation_
, &shutdown_event_
, this, kWaitTimeOutInMs
);
321 size_t CancelableSyncSocket::Receive(void* buffer
, size_t length
) {
322 return CancelableFileOperation(
323 &ReadFile
, handle_
, reinterpret_cast<char*>(buffer
), length
,
324 &file_operation_
, &shutdown_event_
, this, INFINITE
);
327 size_t CancelableSyncSocket::ReceiveWithTimeout(void* buffer
,
330 return CancelableFileOperation(
331 &ReadFile
, handle_
, reinterpret_cast<char*>(buffer
), length
,
332 &file_operation_
, &shutdown_event_
, this,
333 static_cast<DWORD
>(timeout
.InMilliseconds()));
337 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket
* socket_a
,
338 CancelableSyncSocket
* socket_b
) {
339 return CreatePairImpl(&socket_a
->handle_
, &socket_b
->handle_
, true);