blob: 4321b04beef1c6cf788701ebd52d95d69f9aea0e [file] [log] [blame]
[email protected]a7c03d4f32012-01-24 02:36:051// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]946d1b22009-07-22 23:57:215#include "ipc/ipc_channel_win.h"
[email protected]c1afbd2c2008-10-13 19:19:366
initial.commit09911bf2008-07-26 23:55:297#include <windows.h>
avi246998d82015-12-22 02:39:048#include <stddef.h>
9#include <stdint.h>
initial.commit09911bf2008-07-26 23:55:2910
[email protected]5be7da242009-11-20 23:16:2611#include "base/auto_reset.h"
[email protected]72b6f8e22011-11-12 21:16:4112#include "base/bind.h"
[email protected]c1afbd2c2008-10-13 19:19:3613#include "base/compiler_specific.h"
initial.commit09911bf2008-07-26 23:55:2914#include "base/logging.h"
danakj03de39b22016-04-23 04:21:0915#include "base/memory/ptr_util.h"
[email protected]7edae3d02012-12-17 20:23:4716#include "base/pickle.h"
[email protected]e66ef602013-07-24 05:15:2417#include "base/process/process_handle.h"
[email protected]5c41e6e12012-03-17 02:20:4618#include "base/rand_util.h"
[email protected]4aa794a12013-06-11 06:32:1819#include "base/strings/string_number_conversions.h"
[email protected]906265872013-06-07 22:40:4520#include "base/strings/utf_string_conversions.h"
[email protected]327e52b2012-06-25 21:11:3621#include "base/threading/thread_checker.h"
[email protected]b90d7e802011-01-09 16:32:2022#include "base/win/scoped_handle.h"
erikchen5708aae2015-09-14 17:45:1223#include "ipc/attachment_broker.h"
[email protected]0ee990682012-11-17 19:20:0524#include "ipc/ipc_listener.h"
[email protected]946d1b22009-07-22 23:57:2125#include "ipc/ipc_logging.h"
erikcheneece6c32015-07-07 22:13:1126#include "ipc/ipc_message_attachment_set.h"
[email protected]946d1b22009-07-22 23:57:2127#include "ipc/ipc_message_utils.h"
initial.commit09911bf2008-07-26 23:55:2928
initial.commit09911bf2008-07-26 23:55:2929namespace IPC {
[email protected]935aa542010-10-15 01:59:1530
fdoray324a0722016-05-11 20:00:3531ChannelWin::State::State() = default;
initial.commit09911bf2008-07-26 23:55:2932
[email protected]2f60c9b2014-06-06 20:13:5133ChannelWin::State::~State() {
anujk.sharma5a7ffe2f2015-01-22 05:39:3734 static_assert(offsetof(ChannelWin::State, context) == 0,
35 "ChannelWin::State should have context as its first data"
36 "member.");
initial.commit09911bf2008-07-26 23:55:2937}
38
erikchen27aa7d82015-06-16 21:21:0439ChannelWin::ChannelWin(const IPC::ChannelHandle& channel_handle,
40 Mode mode,
erikchen5708aae2015-09-14 17:45:1241 Listener* listener)
[email protected]d805c6a2012-03-08 12:30:2842 : ChannelReader(listener),
[email protected]0a6fc4b2012-04-05 02:38:3443 peer_pid_(base::kNullProcessId),
[email protected]1707726c2011-02-03 20:35:0944 waiting_connect_(mode & MODE_SERVER_FLAG),
[email protected]c1afbd2c2008-10-13 19:19:3645 processing_incoming_(false),
[email protected]2d0faf12014-06-27 04:50:4346 validate_client_(false),
[email protected]65727eb2014-07-31 12:24:2947 client_secret_(0),
erikchenf1953822015-06-16 23:16:0448 weak_factory_(this) {
[email protected]c2391b82011-05-06 17:39:0749 CreatePipe(channel_handle, mode);
initial.commit09911bf2008-07-26 23:55:2950}
51
[email protected]2f60c9b2014-06-06 20:13:5152ChannelWin::~ChannelWin() {
erikchen53d919d2015-09-11 17:33:3453 CleanUp();
[email protected]601858c02010-09-01 17:08:2054 Close();
55}
56
[email protected]2f60c9b2014-06-06 20:13:5157void ChannelWin::Close() {
rvargascd742bcb2014-11-14 19:27:3158 if (thread_check_.get())
[email protected]c1e4bff32009-01-29 00:07:0659 DCHECK(thread_check_->CalledOnValidThread());
[email protected]c1e4bff32009-01-29 00:07:0660
[email protected]74f87acf22009-10-14 22:10:4061 if (input_state_.is_pending || output_state_.is_pending)
rvargas8c2d75c2014-09-26 19:50:2662 CancelIo(pipe_.Get());
[email protected]ee78622d2008-10-13 21:25:5063
[email protected]17b89142008-11-07 21:52:1564 // Closing the handle at this point prevents us from issuing more requests
65 // form OnIOCompleted().
rvargas8c2d75c2014-09-26 19:50:2666 if (pipe_.IsValid())
67 pipe_.Close();
initial.commit09911bf2008-07-26 23:55:2968
[email protected]17b89142008-11-07 21:52:1569 // Make sure all IO has completed.
[email protected]17b89142008-11-07 21:52:1570 while (input_state_.is_pending || output_state_.is_pending) {
[email protected]fd0a773a2013-04-30 20:55:0371 base::MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this);
[email protected]17b89142008-11-07 21:52:1572 }
[email protected]17b89142008-11-07 21:52:1573
initial.commit09911bf2008-07-26 23:55:2974 while (!output_queue_.empty()) {
erikchen5142dc72015-09-10 21:00:1875 OutputElement* element = output_queue_.front();
initial.commit09911bf2008-07-26 23:55:2976 output_queue_.pop();
erikchen5142dc72015-09-10 21:00:1877 delete element;
initial.commit09911bf2008-07-26 23:55:2978 }
79}
80
[email protected]2f60c9b2014-06-06 20:13:5181bool ChannelWin::Send(Message* message) {
[email protected]c1e4bff32009-01-29 00:07:0682 DCHECK(thread_check_->CalledOnValidThread());
[email protected]2a9d601b2010-10-19 23:50:0083 DVLOG(2) << "sending message @" << message << " on channel @" << this
84 << " with type " << message->type()
85 << " (" << output_queue_.size() << " in queue)";
initial.commit09911bf2008-07-26 23:55:2986
erikchenc04ab34c2015-07-27 20:28:2087 if (!prelim_queue_.empty()) {
88 prelim_queue_.push(message);
89 return true;
90 }
91
92 if (message->HasBrokerableAttachments() &&
93 peer_pid_ == base::kNullProcessId) {
94 prelim_queue_.push(message);
95 return true;
96 }
97
98 return ProcessMessageForDelivery(message);
99}
100
101bool ChannelWin::ProcessMessageForDelivery(Message* message) {
erikcheneece6c32015-07-07 22:13:11102 // Sending a brokerable attachment requires a call to Channel::Send(), so
erikchen24e44d302015-10-21 22:28:54103 // both Send() and ProcessMessageForDelivery() may be re-entrant.
erikcheneece6c32015-07-07 22:13:11104 if (message->HasBrokerableAttachments()) {
erikchen5708aae2015-09-14 17:45:12105 DCHECK(GetAttachmentBroker());
erikchenc04ab34c2015-07-27 20:28:20106 DCHECK(peer_pid_ != base::kNullProcessId);
erikchena03dde6f2015-10-29 22:37:04107 for (const scoped_refptr<IPC::BrokerableAttachment>& attachment :
erikchen3722a322015-10-07 20:51:55108 message->attachment_set()->GetBrokerableAttachments()) {
erikchen5708aae2015-09-14 17:45:12109 if (!GetAttachmentBroker()->SendAttachmentToProcess(attachment,
110 peer_pid_)) {
erikchenc04ab34c2015-07-27 20:28:20111 delete message;
erikcheneece6c32015-07-07 22:13:11112 return false;
erikchenc04ab34c2015-07-27 20:28:20113 }
erikcheneece6c32015-07-07 22:13:11114 }
115 }
116
initial.commit09911bf2008-07-26 23:55:29117#ifdef IPC_MESSAGE_LOG_ENABLED
[email protected]8e8bb6d2010-12-13 08:18:55118 Logging::GetInstance()->OnSendMessage(message, "");
initial.commit09911bf2008-07-26 23:55:29119#endif
120
yuhaoz9b8157d2015-08-18 22:21:35121 TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
122 "ChannelWin::ProcessMessageForDelivery",
123 message->flags(),
124 TRACE_EVENT_FLAG_FLOW_OUT);
erikchenc04ab34c2015-07-27 20:28:20125
126 // |output_queue_| takes ownership of |message|.
erikchen5142dc72015-09-10 21:00:18127 OutputElement* element = new OutputElement(message);
128 output_queue_.push(element);
129
erikchen3b325062015-09-22 21:59:10130#if USE_ATTACHMENT_BROKER
131 if (message->HasBrokerableAttachments()) {
132 // |output_queue_| takes ownership of |ids.buffer|.
133 Message::SerializedAttachmentIds ids =
134 message->SerializedIdsOfBrokerableAttachments();
135 output_queue_.push(new OutputElement(ids.buffer, ids.size));
136 }
137#endif
erikchen5142dc72015-09-10 21:00:18138
initial.commit09911bf2008-07-26 23:55:29139 // ensure waiting to write
140 if (!waiting_connect_) {
141 if (!output_state_.is_pending) {
[email protected]c1afbd2c2008-10-13 19:19:36142 if (!ProcessOutgoingMessages(NULL, 0))
initial.commit09911bf2008-07-26 23:55:29143 return false;
initial.commit09911bf2008-07-26 23:55:29144 }
145 }
146
147 return true;
148}
149
erikchenc04ab34c2015-07-27 20:28:20150void ChannelWin::FlushPrelimQueue() {
151 DCHECK_NE(peer_pid_, base::kNullProcessId);
152
153 // Due to the possibly re-entrant nature of ProcessMessageForDelivery(), it
154 // is critical that |prelim_queue_| appears empty.
155 std::queue<Message*> prelim_queue;
156 prelim_queue_.swap(prelim_queue);
157
158 while (!prelim_queue.empty()) {
159 Message* m = prelim_queue.front();
erikchenf81b10a2015-10-06 21:46:37160 bool success = ProcessMessageForDelivery(m);
161 prelim_queue.pop();
162
163 if (!success)
164 break;
165 }
166
167 // Delete any unprocessed messages.
168 while (!prelim_queue.empty()) {
169 Message* m = prelim_queue.front();
170 delete m;
erikchenc04ab34c2015-07-27 20:28:20171 prelim_queue.pop();
172 }
173}
174
erikchen27aa7d82015-06-16 21:21:04175AttachmentBroker* ChannelWin::GetAttachmentBroker() {
erikchen5708aae2015-09-14 17:45:12176 return AttachmentBroker::GetGlobal();
erikchen27aa7d82015-06-16 21:21:04177}
178
[email protected]2f60c9b2014-06-06 20:13:51179base::ProcessId ChannelWin::GetPeerPID() const {
180 return peer_pid_;
181}
182
[email protected]64860882014-08-04 23:44:17183base::ProcessId ChannelWin::GetSelfPID() const {
184 return GetCurrentProcessId();
185}
186
[email protected]313c00e52011-08-09 06:46:06187// static
[email protected]2f60c9b2014-06-06 20:13:51188bool ChannelWin::IsNamedServerInitialized(
[email protected]313c00e52011-08-09 06:46:06189 const std::string& channel_id) {
[email protected]5c41e6e12012-03-17 02:20:46190 if (WaitNamedPipe(PipeName(channel_id, NULL).c_str(), 1))
[email protected]313c00e52011-08-09 06:46:06191 return true;
192 // If ERROR_SEM_TIMEOUT occurred, the pipe exists but is handling another
193 // connection.
194 return GetLastError() == ERROR_SEM_TIMEOUT;
195}
196
[email protected]2f60c9b2014-06-06 20:13:51197ChannelWin::ReadState ChannelWin::ReadData(
[email protected]215f6fd2012-03-03 08:55:45198 char* buffer,
199 int buffer_len,
200 int* /* bytes_read */) {
rvargas8c2d75c2014-09-26 19:50:26201 if (!pipe_.IsValid())
[email protected]215f6fd2012-03-03 08:55:45202 return READ_FAILED;
203
204 DWORD bytes_read = 0;
rvargas8c2d75c2014-09-26 19:50:26205 BOOL ok = ReadFile(pipe_.Get(), buffer, buffer_len,
[email protected]215f6fd2012-03-03 08:55:45206 &bytes_read, &input_state_.context.overlapped);
207 if (!ok) {
208 DWORD err = GetLastError();
209 if (err == ERROR_IO_PENDING) {
210 input_state_.is_pending = true;
211 return READ_PENDING;
212 }
213 LOG(ERROR) << "pipe error: " << err;
214 return READ_FAILED;
215 }
216
217 // We could return READ_SUCCEEDED here. But the way that this code is
218 // structured we instead go back to the message loop. Our completion port
219 // will be signalled even in the "synchronously completed" state.
220 //
221 // This allows us to potentially process some outgoing messages and
222 // interleave other work on this thread when we're getting hammered with
223 // input messages. Potentially, this could be tuned to be more efficient
224 // with some testing.
225 input_state_.is_pending = true;
226 return READ_PENDING;
227}
228
erikchende9412b82015-07-27 18:26:14229bool ChannelWin::ShouldDispatchInputMessage(Message* msg) {
[email protected]05908782012-04-03 08:49:43230 // Make sure we get a hello when client validation is required.
231 if (validate_client_)
232 return IsHelloMessage(*msg);
[email protected]215f6fd2012-03-03 08:55:45233 return true;
234}
235
erikchende9412b82015-07-27 18:26:14236bool ChannelWin::GetNonBrokeredAttachments(Message* msg) {
237 return true;
238}
239
[email protected]2f60c9b2014-06-06 20:13:51240void ChannelWin::HandleInternalMessage(const Message& msg) {
[email protected]dc875dc2013-10-15 00:07:00241 DCHECK_EQ(msg.type(), static_cast<unsigned>(Channel::HELLO_MESSAGE_TYPE));
[email protected]215f6fd2012-03-03 08:55:45242 // The hello message contains one parameter containing the PID.
brettwbd4d7112015-06-03 04:29:25243 base::PickleIterator it(msg);
tfarina10a5c062015-09-04 18:47:57244 int32_t claimed_pid;
[email protected]7edae3d02012-12-17 20:23:47245 bool failed = !it.ReadInt(&claimed_pid);
246
247 if (!failed && validate_client_) {
tfarina10a5c062015-09-04 18:47:57248 int32_t secret;
[email protected]7edae3d02012-12-17 20:23:47249 failed = it.ReadInt(&secret) ? (secret != client_secret_) : true;
250 }
251
252 if (failed) {
[email protected]5c41e6e12012-03-17 02:20:46253 NOTREACHED();
[email protected]5c41e6e12012-03-17 02:20:46254 Close();
255 listener()->OnChannelError();
256 return;
257 }
[email protected]7edae3d02012-12-17 20:23:47258
[email protected]0a6fc4b2012-04-05 02:38:34259 peer_pid_ = claimed_pid;
[email protected]7edae3d02012-12-17 20:23:47260 // Validation completed.
[email protected]05908782012-04-03 08:49:43261 validate_client_ = false;
erikchenc04ab34c2015-07-27 20:28:20262
[email protected]5c41e6e12012-03-17 02:20:46263 listener()->OnChannelConnected(claimed_pid);
erikchenf81b10a2015-10-06 21:46:37264
265 FlushPrelimQueue();
erikchen3e0f4d32016-05-16 18:47:54266
267 if (IsAttachmentBrokerEndpoint() &&
268 AttachmentBroker::GetGlobal()->IsPrivilegedBroker()) {
269 AttachmentBroker::GetGlobal()->ReceivedPeerPid(claimed_pid);
270 }
[email protected]215f6fd2012-03-03 08:55:45271}
272
erikchen3c175a32015-07-28 23:16:48273base::ProcessId ChannelWin::GetSenderPID() {
274 return GetPeerPID();
275}
276
erikchen8c73f832015-07-30 22:26:08277bool ChannelWin::IsAttachmentBrokerEndpoint() {
278 return is_attachment_broker_endpoint();
279}
280
[email protected]2f60c9b2014-06-06 20:13:51281bool ChannelWin::DidEmptyInputBuffers() {
[email protected]d805c6a2012-03-08 12:30:28282 // We don't need to do anything here.
[email protected]215f6fd2012-03-03 08:55:45283 return true;
284}
285
[email protected]313c00e52011-08-09 06:46:06286// static
tfarina10a5c062015-09-04 18:47:57287const base::string16 ChannelWin::PipeName(const std::string& channel_id,
288 int32_t* secret) {
[email protected]c2391b82011-05-06 17:39:07289 std::string name("\\\\.\\pipe\\chrome.");
[email protected]5c41e6e12012-03-17 02:20:46290
291 // Prevent the shared secret from ending up in the pipe name.
292 size_t index = channel_id.find_first_of('\\');
293 if (index != std::string::npos) {
294 if (secret) // Retrieve the secret if asked for.
295 base::StringToInt(channel_id.substr(index + 1), secret);
thestige5c64d92014-11-07 01:19:24296 return base::ASCIIToUTF16(name.append(channel_id.substr(0, index - 1)));
[email protected]5c41e6e12012-03-17 02:20:46297 }
298
299 // This case is here to support predictable named pipes in tests.
300 if (secret)
301 *secret = 0;
thestige5c64d92014-11-07 01:19:24302 return base::ASCIIToUTF16(name.append(channel_id));
initial.commit09911bf2008-07-26 23:55:29303}
304
[email protected]2f60c9b2014-06-06 20:13:51305bool ChannelWin::CreatePipe(const IPC::ChannelHandle &channel_handle,
rvargas8c2d75c2014-09-26 19:50:26306 Mode mode) {
307 DCHECK(!pipe_.IsValid());
[email protected]905cda812013-12-20 09:04:55308 base::string16 pipe_name;
[email protected]a7c03d4f32012-01-24 02:36:05309 // If we already have a valid pipe for channel just copy it.
310 if (channel_handle.pipe.handle) {
rvargas8c2d75c2014-09-26 19:50:26311 // TODO(rvargas) crbug.com/415294: ChannelHandle should either go away in
312 // favor of two independent entities (name/file), or it should be a move-
313 // only type with a base::File member. In any case, this code should not
314 // call DuplicateHandle.
[email protected]a7c03d4f32012-01-24 02:36:05315 DCHECK(channel_handle.name.empty());
316 pipe_name = L"Not Available"; // Just used for LOG
317 // Check that the given pipe confirms to the specified mode. We can
318 // only check for PIPE_TYPE_MESSAGE & PIPE_SERVER_END flags since the
319 // other flags (PIPE_TYPE_BYTE, and PIPE_CLIENT_END) are defined as 0.
320 DWORD flags = 0;
321 GetNamedPipeInfo(channel_handle.pipe.handle, &flags, NULL, NULL, NULL);
322 DCHECK(!(flags & PIPE_TYPE_MESSAGE));
323 if (((mode & MODE_SERVER_FLAG) && !(flags & PIPE_SERVER_END)) ||
324 ((mode & MODE_CLIENT_FLAG) && (flags & PIPE_SERVER_END))) {
325 LOG(WARNING) << "Inconsistent open mode. Mode :" << mode;
326 return false;
327 }
rvargas8c2d75c2014-09-26 19:50:26328 HANDLE local_handle;
[email protected]a7c03d4f32012-01-24 02:36:05329 if (!DuplicateHandle(GetCurrentProcess(),
330 channel_handle.pipe.handle,
331 GetCurrentProcess(),
rvargas8c2d75c2014-09-26 19:50:26332 &local_handle,
[email protected]a7c03d4f32012-01-24 02:36:05333 0,
334 FALSE,
335 DUPLICATE_SAME_ACCESS)) {
336 LOG(WARNING) << "DuplicateHandle failed. Error :" << GetLastError();
337 return false;
338 }
rvargas8c2d75c2014-09-26 19:50:26339 pipe_.Set(local_handle);
[email protected]a7c03d4f32012-01-24 02:36:05340 } else if (mode & MODE_SERVER_FLAG) {
341 DCHECK(!channel_handle.pipe.handle);
342 const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
343 FILE_FLAG_FIRST_PIPE_INSTANCE;
[email protected]5c41e6e12012-03-17 02:20:46344 pipe_name = PipeName(channel_handle.name, &client_secret_);
345 validate_client_ = !!client_secret_;
rvargas8c2d75c2014-09-26 19:50:26346 pipe_.Set(CreateNamedPipeW(pipe_name.c_str(),
347 open_mode,
348 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
349 1,
350 Channel::kReadBufferSize,
351 Channel::kReadBufferSize,
352 5000,
353 NULL));
[email protected]1707726c2011-02-03 20:35:09354 } else if (mode & MODE_CLIENT_FLAG) {
[email protected]a7c03d4f32012-01-24 02:36:05355 DCHECK(!channel_handle.pipe.handle);
[email protected]5c41e6e12012-03-17 02:20:46356 pipe_name = PipeName(channel_handle.name, &client_secret_);
rvargas8c2d75c2014-09-26 19:50:26357 pipe_.Set(CreateFileW(pipe_name.c_str(),
358 GENERIC_READ | GENERIC_WRITE,
359 0,
360 NULL,
361 OPEN_EXISTING,
forshaw4a94dff2014-12-16 21:32:53362 SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS |
rvargas8c2d75c2014-09-26 19:50:26363 FILE_FLAG_OVERLAPPED,
364 NULL));
[email protected]1707726c2011-02-03 20:35:09365 } else {
366 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:29367 }
[email protected]a7c03d4f32012-01-24 02:36:05368
rvargas8c2d75c2014-09-26 19:50:26369 if (!pipe_.IsValid()) {
initial.commit09911bf2008-07-26 23:55:29370 // If this process is being closed, the pipe may be gone already.
[email protected]8398bf12014-06-26 21:11:34371 PLOG(WARNING) << "Unable to create pipe \"" << pipe_name << "\" in "
372 << (mode & MODE_SERVER_FLAG ? "server" : "client") << " mode";
initial.commit09911bf2008-07-26 23:55:29373 return false;
374 }
375
376 // Create the Hello message to be sent when Connect is called
danakj03de39b22016-04-23 04:21:09377 std::unique_ptr<Message> m(new Message(MSG_ROUTING_NONE, HELLO_MESSAGE_TYPE,
378 IPC::Message::PRIORITY_NORMAL));
[email protected]5c41e6e12012-03-17 02:20:46379
380 // Don't send the secret to the untrusted process, and don't send a secret
381 // if the value is zero (for IPC backwards compatability).
tfarina10a5c062015-09-04 18:47:57382 int32_t secret = validate_client_ ? 0 : client_secret_;
[email protected]5c41e6e12012-03-17 02:20:46383 if (!m->WriteInt(GetCurrentProcessId()) ||
384 (secret && !m->WriteUInt32(secret))) {
rvargas8c2d75c2014-09-26 19:50:26385 pipe_.Close();
initial.commit09911bf2008-07-26 23:55:29386 return false;
387 }
388
erikchen5142dc72015-09-10 21:00:18389 OutputElement* element = new OutputElement(m.release());
390 output_queue_.push(element);
initial.commit09911bf2008-07-26 23:55:29391 return true;
392}
393
[email protected]2f60c9b2014-06-06 20:13:51394bool ChannelWin::Connect() {
erikchen90971902016-04-25 23:45:31395 WillConnect();
396
[email protected]19340722009-08-17 19:53:25397 DLOG_IF(WARNING, thread_check_.get()) << "Connect called more than once";
initial.commit09911bf2008-07-26 23:55:29398
[email protected]c1e4bff32009-01-29 00:07:06399 if (!thread_check_.get())
[email protected]327e52b2012-06-25 21:11:36400 thread_check_.reset(new base::ThreadChecker());
[email protected]c1e4bff32009-01-29 00:07:06401
rvargas8c2d75c2014-09-26 19:50:26402 if (!pipe_.IsValid())
initial.commit09911bf2008-07-26 23:55:29403 return false;
404
rvargas8c2d75c2014-09-26 19:50:26405 base::MessageLoopForIO::current()->RegisterIOHandler(pipe_.Get(), this);
[email protected]c1afbd2c2008-10-13 19:19:36406
initial.commit09911bf2008-07-26 23:55:29407 // Check to see if there is a client connected to our pipe...
408 if (waiting_connect_)
409 ProcessConnection();
410
411 if (!input_state_.is_pending) {
[email protected]c1afbd2c2008-10-13 19:19:36412 // Complete setup asynchronously. By not setting input_state_.is_pending
413 // to true, we indicate to OnIOCompleted that this is the special
414 // initialization signal.
fdoray471891b2016-06-06 22:20:09415 base::MessageLoopForIO::current()->PostTask(
[email protected]fd0a773a2013-04-30 20:55:03416 FROM_HERE,
fdoray471891b2016-06-06 22:20:09417 base::Bind(&ChannelWin::OnIOCompleted,
418 weak_factory_.GetWeakPtr(),
419 &input_state_.context,
420 0,
421 0));
initial.commit09911bf2008-07-26 23:55:29422 }
423
424 if (!waiting_connect_)
[email protected]c1afbd2c2008-10-13 19:19:36425 ProcessOutgoingMessages(NULL, 0);
initial.commit09911bf2008-07-26 23:55:29426 return true;
427}
428
[email protected]2f60c9b2014-06-06 20:13:51429bool ChannelWin::ProcessConnection() {
[email protected]c1e4bff32009-01-29 00:07:06430 DCHECK(thread_check_->CalledOnValidThread());
[email protected]17b89142008-11-07 21:52:15431 if (input_state_.is_pending)
[email protected]c1afbd2c2008-10-13 19:19:36432 input_state_.is_pending = false;
initial.commit09911bf2008-07-26 23:55:29433
434 // Do we have a client connected to our pipe?
rvargas8c2d75c2014-09-26 19:50:26435 if (!pipe_.IsValid())
[email protected]17b89142008-11-07 21:52:15436 return false;
437
rvargas8c2d75c2014-09-26 19:50:26438 BOOL ok = ConnectNamedPipe(pipe_.Get(), &input_state_.context.overlapped);
initial.commit09911bf2008-07-26 23:55:29439 DWORD err = GetLastError();
440 if (ok) {
441 // Uhm, the API documentation says that this function should never
442 // return success when used in overlapped mode.
443 NOTREACHED();
444 return false;
445 }
446
447 switch (err) {
448 case ERROR_IO_PENDING:
449 input_state_.is_pending = true;
initial.commit09911bf2008-07-26 23:55:29450 break;
451 case ERROR_PIPE_CONNECTED:
452 waiting_connect_ = false;
453 break;
[email protected]20aa32c2009-07-14 22:25:49454 case ERROR_NO_DATA:
455 // The pipe is being closed.
456 return false;
initial.commit09911bf2008-07-26 23:55:29457 default:
458 NOTREACHED();
459 return false;
460 }
461
462 return true;
463}
464
[email protected]2f60c9b2014-06-06 20:13:51465bool ChannelWin::ProcessOutgoingMessages(
[email protected]fd0a773a2013-04-30 20:55:03466 base::MessageLoopForIO::IOContext* context,
[email protected]514411fc2008-12-10 22:28:11467 DWORD bytes_written) {
initial.commit09911bf2008-07-26 23:55:29468 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
469 // no connection?
[email protected]c1e4bff32009-01-29 00:07:06470 DCHECK(thread_check_->CalledOnValidThread());
initial.commit09911bf2008-07-26 23:55:29471
472 if (output_state_.is_pending) {
[email protected]c1afbd2c2008-10-13 19:19:36473 DCHECK(context);
initial.commit09911bf2008-07-26 23:55:29474 output_state_.is_pending = false;
[email protected]c1afbd2c2008-10-13 19:19:36475 if (!context || bytes_written == 0) {
initial.commit09911bf2008-07-26 23:55:29476 DWORD err = GetLastError();
477 LOG(ERROR) << "pipe error: " << err;
478 return false;
479 }
[email protected]c1afbd2c2008-10-13 19:19:36480 // Message was sent.
[email protected]88ecb5f52014-01-21 14:29:36481 CHECK(!output_queue_.empty());
erikchen5142dc72015-09-10 21:00:18482 OutputElement* element = output_queue_.front();
initial.commit09911bf2008-07-26 23:55:29483 output_queue_.pop();
erikchen5142dc72015-09-10 21:00:18484 delete element;
initial.commit09911bf2008-07-26 23:55:29485 }
486
[email protected]17b89142008-11-07 21:52:15487 if (output_queue_.empty())
488 return true;
489
rvargas8c2d75c2014-09-26 19:50:26490 if (!pipe_.IsValid())
[email protected]17b89142008-11-07 21:52:15491 return false;
492
493 // Write to pipe...
erikchen5142dc72015-09-10 21:00:18494 OutputElement* element = output_queue_.front();
495 DCHECK(element->size() <= INT_MAX);
erikchen06faf0c2015-08-27 19:49:58496 BOOL ok = WriteFile(pipe_.Get(),
erikchen5142dc72015-09-10 21:00:18497 element->data(),
498 static_cast<uint32_t>(element->size()),
erikchen06faf0c2015-08-27 19:49:58499 NULL,
[email protected]17b89142008-11-07 21:52:15500 &output_state_.context.overlapped);
501 if (!ok) {
rvargascd742bcb2014-11-14 19:27:31502 DWORD write_error = GetLastError();
503 if (write_error == ERROR_IO_PENDING) {
[email protected]17b89142008-11-07 21:52:15504 output_state_.is_pending = true;
initial.commit09911bf2008-07-26 23:55:29505
erikchen5142dc72015-09-10 21:00:18506 const Message* m = element->get_message();
507 if (m) {
508 DVLOG(2) << "sent pending message @" << m << " on channel @" << this
509 << " with type " << m->type();
510 }
initial.commit09911bf2008-07-26 23:55:29511
[email protected]17b89142008-11-07 21:52:15512 return true;
initial.commit09911bf2008-07-26 23:55:29513 }
rvargascd742bcb2014-11-14 19:27:31514 LOG(ERROR) << "pipe error: " << write_error;
[email protected]17b89142008-11-07 21:52:15515 return false;
initial.commit09911bf2008-07-26 23:55:29516 }
517
erikchen5142dc72015-09-10 21:00:18518 const Message* m = element->get_message();
519 if (m) {
520 DVLOG(2) << "sent message @" << m << " on channel @" << this
521 << " with type " << m->type();
522 }
[email protected]17b89142008-11-07 21:52:15523
524 output_state_.is_pending = true;
initial.commit09911bf2008-07-26 23:55:29525 return true;
526}
527
[email protected]2f60c9b2014-06-06 20:13:51528void ChannelWin::OnIOCompleted(
[email protected]fd0a773a2013-04-30 20:55:03529 base::MessageLoopForIO::IOContext* context,
530 DWORD bytes_transfered,
531 DWORD error) {
[email protected]215f6fd2012-03-03 08:55:45532 bool ok = true;
[email protected]c1e4bff32009-01-29 00:07:06533 DCHECK(thread_check_->CalledOnValidThread());
[email protected]17b89142008-11-07 21:52:15534 if (context == &input_state_.context) {
initial.commit09911bf2008-07-26 23:55:29535 if (waiting_connect_) {
[email protected]17b89142008-11-07 21:52:15536 if (!ProcessConnection())
537 return;
initial.commit09911bf2008-07-26 23:55:29538 // We may have some messages queued up to send...
539 if (!output_queue_.empty() && !output_state_.is_pending)
[email protected]c1afbd2c2008-10-13 19:19:36540 ProcessOutgoingMessages(NULL, 0);
initial.commit09911bf2008-07-26 23:55:29541 if (input_state_.is_pending)
542 return;
543 // else, fall-through and look for incoming messages...
544 }
[email protected]215f6fd2012-03-03 08:55:45545
546 // We don't support recursion through OnMessageReceived yet!
initial.commit09911bf2008-07-26 23:55:29547 DCHECK(!processing_incoming_);
[email protected]997ec9f2012-11-21 04:44:14548 base::AutoReset<bool> auto_reset_processing_incoming(
549 &processing_incoming_, true);
[email protected]215f6fd2012-03-03 08:55:45550
551 // Process the new data.
552 if (input_state_.is_pending) {
553 // This is the normal case for everything except the initialization step.
554 input_state_.is_pending = false;
erikchende9412b82015-07-27 18:26:14555 if (!bytes_transfered) {
[email protected]215f6fd2012-03-03 08:55:45556 ok = false;
erikchende9412b82015-07-27 18:26:14557 } else if (pipe_.IsValid()) {
558 ok = (AsyncReadComplete(bytes_transfered) != DISPATCH_ERROR);
559 }
[email protected]215f6fd2012-03-03 08:55:45560 } else {
561 DCHECK(!bytes_transfered);
562 }
563
564 // Request more data.
565 if (ok)
erikchende9412b82015-07-27 18:26:14566 ok = (ProcessIncomingMessages() != DISPATCH_ERROR);
initial.commit09911bf2008-07-26 23:55:29567 } else {
[email protected]17b89142008-11-07 21:52:15568 DCHECK(context == &output_state_.context);
[email protected]65727eb2014-07-31 12:24:29569 CHECK(output_state_.is_pending);
[email protected]c1afbd2c2008-10-13 19:19:36570 ok = ProcessOutgoingMessages(context, bytes_transfered);
initial.commit09911bf2008-07-26 23:55:29571 }
rvargas8c2d75c2014-09-26 19:50:26572 if (!ok && pipe_.IsValid()) {
[email protected]17b89142008-11-07 21:52:15573 // We don't want to re-enter Close().
initial.commit09911bf2008-07-26 23:55:29574 Close();
[email protected]d805c6a2012-03-08 12:30:28575 listener()->OnChannelError();
initial.commit09911bf2008-07-26 23:55:29576 }
577}
578
[email protected]514411fc2008-12-10 22:28:11579//------------------------------------------------------------------------------
[email protected]2f60c9b2014-06-06 20:13:51580// Channel's methods
[email protected]514411fc2008-12-10 22:28:11581
[email protected]2f60c9b2014-06-06 20:13:51582// static
danakj03de39b22016-04-23 04:21:09583std::unique_ptr<Channel> Channel::Create(
584 const IPC::ChannelHandle& channel_handle,
585 Mode mode,
586 Listener* listener) {
587 return base::WrapUnique(new ChannelWin(channel_handle, mode, listener));
[email protected]514411fc2008-12-10 22:28:11588}
589
[email protected]313c00e52011-08-09 06:46:06590// static
591bool Channel::IsNamedServerInitialized(const std::string& channel_id) {
[email protected]2f60c9b2014-06-06 20:13:51592 return ChannelWin::IsNamedServerInitialized(channel_id);
[email protected]313c00e52011-08-09 06:46:06593}
594
[email protected]5c41e6e12012-03-17 02:20:46595// static
596std::string Channel::GenerateVerifiedChannelID(const std::string& prefix) {
597 // Windows pipes can be enumerated by low-privileged processes. So, we
598 // append a strong random value after the \ character. This value is not
599 // included in the pipe name, but sent as part of the client hello, to
600 // hijacking the pipe name to spoof the client.
601
602 std::string id = prefix;
603 if (!id.empty())
604 id.append(".");
605
606 int secret;
607 do { // Guarantee we get a non-zero value.
608 secret = base::RandInt(0, std::numeric_limits<int>::max());
609 } while (secret == 0);
610
611 id.append(GenerateUniqueRandomChannelID());
612 return id.append(base::StringPrintf("\\%d", secret));
613}
614
[email protected]514411fc2008-12-10 22:28:11615} // namespace IPC