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);
210 bool SyncSocket::Close() {
211 if (handle_
== kInvalidHandle
)
214 const BOOL result
= CloseHandle(handle_
);
215 handle_
= kInvalidHandle
;
216 return result
== TRUE
;
219 size_t SyncSocket::Send(const void* buffer
, size_t length
) {
220 ThreadRestrictions::AssertIOAllowed();
221 DCHECK_GT(length
, 0u);
222 DCHECK_LE(length
, kMaxMessageLength
);
223 DCHECK_NE(handle_
, kInvalidHandle
);
225 while (count
< length
) {
227 DWORD chunk
= GetNextChunkSize(count
, length
);
228 if (WriteFile(handle_
, static_cast<const char*>(buffer
) + count
,
229 chunk
, &len
, NULL
) == FALSE
) {
237 size_t SyncSocket::ReceiveWithTimeout(void* buffer
,
244 size_t SyncSocket::Receive(void* buffer
, size_t length
) {
245 ThreadRestrictions::AssertIOAllowed();
246 DCHECK_GT(length
, 0u);
247 DCHECK_LE(length
, kMaxMessageLength
);
248 DCHECK_NE(handle_
, kInvalidHandle
);
250 while (count
< length
) {
252 DWORD chunk
= GetNextChunkSize(count
, length
);
253 if (ReadFile(handle_
, static_cast<char*>(buffer
) + count
,
254 chunk
, &len
, NULL
) == FALSE
) {
262 size_t SyncSocket::Peek() {
264 PeekNamedPipe(handle_
, NULL
, 0, NULL
, &available
, NULL
);
268 CancelableSyncSocket::CancelableSyncSocket()
269 : shutdown_event_(true, false), file_operation_(true, false) {
272 CancelableSyncSocket::CancelableSyncSocket(Handle handle
)
273 : SyncSocket(handle
), shutdown_event_(true, false),
274 file_operation_(true, false) {
277 bool CancelableSyncSocket::Shutdown() {
278 // This doesn't shut down the pipe immediately, but subsequent Receive or Send
279 // methods will fail straight away.
280 shutdown_event_
.Signal();
284 bool CancelableSyncSocket::Close() {
285 const bool result
= SyncSocket::Close();
286 shutdown_event_
.Reset();
290 size_t CancelableSyncSocket::Send(const void* buffer
, size_t length
) {
291 static const DWORD kWaitTimeOutInMs
= 500;
292 return CancelableFileOperation(
293 &WriteFile
, handle_
, reinterpret_cast<const char*>(buffer
),
294 length
, &file_operation_
, &shutdown_event_
, this, kWaitTimeOutInMs
);
297 size_t CancelableSyncSocket::Receive(void* buffer
, size_t length
) {
298 return CancelableFileOperation(
299 &ReadFile
, handle_
, reinterpret_cast<char*>(buffer
), length
,
300 &file_operation_
, &shutdown_event_
, this, INFINITE
);
303 size_t CancelableSyncSocket::ReceiveWithTimeout(void* buffer
,
306 return CancelableFileOperation(
307 &ReadFile
, handle_
, reinterpret_cast<char*>(buffer
), length
,
308 &file_operation_
, &shutdown_event_
, this, timeout
.InMilliseconds());
312 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket
* socket_a
,
313 CancelableSyncSocket
* socket_b
) {
314 return CreatePairImpl(&socket_a
->handle_
, &socket_b
->handle_
, true);