blob: ad7ffb5f62be6cdbd39432819a37ea442d5dfc4e [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>
initial.commit09911bf2008-07-26 23:55:298
[email protected]5be7da242009-11-20 23:16:269#include "base/auto_reset.h"
[email protected]72b6f8e22011-11-12 21:16:4110#include "base/bind.h"
[email protected]c1afbd2c2008-10-13 19:19:3611#include "base/compiler_specific.h"
initial.commit09911bf2008-07-26 23:55:2912#include "base/logging.h"
[email protected]7edae3d02012-12-17 20:23:4713#include "base/pickle.h"
[email protected]e66ef602013-07-24 05:15:2414#include "base/process/process_handle.h"
[email protected]5c41e6e12012-03-17 02:20:4615#include "base/rand_util.h"
[email protected]4aa794a12013-06-11 06:32:1816#include "base/strings/string_number_conversions.h"
[email protected]906265872013-06-07 22:40:4517#include "base/strings/utf_string_conversions.h"
[email protected]327e52b2012-06-25 21:11:3618#include "base/threading/thread_checker.h"
[email protected]b90d7e802011-01-09 16:32:2019#include "base/win/scoped_handle.h"
[email protected]0ee990682012-11-17 19:20:0520#include "ipc/ipc_listener.h"
[email protected]946d1b22009-07-22 23:57:2121#include "ipc/ipc_logging.h"
erikcheneece6c32015-07-07 22:13:1122#include "ipc/ipc_message_attachment_set.h"
[email protected]946d1b22009-07-22 23:57:2123#include "ipc/ipc_message_utils.h"
initial.commit09911bf2008-07-26 23:55:2924
initial.commit09911bf2008-07-26 23:55:2925namespace IPC {
[email protected]935aa542010-10-15 01:59:1526
[email protected]2f60c9b2014-06-06 20:13:5127ChannelWin::State::State(ChannelWin* channel) : is_pending(false) {
[email protected]17b89142008-11-07 21:52:1528 memset(&context.overlapped, 0, sizeof(context.overlapped));
29 context.handler = channel;
initial.commit09911bf2008-07-26 23:55:2930}
31
[email protected]2f60c9b2014-06-06 20:13:5132ChannelWin::State::~State() {
anujk.sharma5a7ffe2f2015-01-22 05:39:3733 static_assert(offsetof(ChannelWin::State, context) == 0,
34 "ChannelWin::State should have context as its first data"
35 "member.");
initial.commit09911bf2008-07-26 23:55:2936}
37
erikchen27aa7d82015-06-16 21:21:0438ChannelWin::ChannelWin(const IPC::ChannelHandle& channel_handle,
39 Mode mode,
40 Listener* listener,
41 AttachmentBroker* broker)
[email protected]d805c6a2012-03-08 12:30:2842 : ChannelReader(listener),
[email protected]ba2194d2013-04-26 19:51:3043 input_state_(this),
44 output_state_(this),
[email protected]0a6fc4b2012-04-05 02:38:3445 peer_pid_(base::kNullProcessId),
[email protected]1707726c2011-02-03 20:35:0946 waiting_connect_(mode & MODE_SERVER_FLAG),
[email protected]c1afbd2c2008-10-13 19:19:3647 processing_incoming_(false),
[email protected]2d0faf12014-06-27 04:50:4348 validate_client_(false),
[email protected]65727eb2014-07-31 12:24:2949 client_secret_(0),
erikchenf1953822015-06-16 23:16:0450 broker_(broker),
51 weak_factory_(this) {
[email protected]c2391b82011-05-06 17:39:0752 CreatePipe(channel_handle, mode);
initial.commit09911bf2008-07-26 23:55:2953}
54
[email protected]2f60c9b2014-06-06 20:13:5155ChannelWin::~ChannelWin() {
[email protected]601858c02010-09-01 17:08:2056 Close();
57}
58
[email protected]2f60c9b2014-06-06 20:13:5159void ChannelWin::Close() {
rvargascd742bcb2014-11-14 19:27:3160 if (thread_check_.get())
[email protected]c1e4bff32009-01-29 00:07:0661 DCHECK(thread_check_->CalledOnValidThread());
[email protected]c1e4bff32009-01-29 00:07:0662
[email protected]74f87acf22009-10-14 22:10:4063 if (input_state_.is_pending || output_state_.is_pending)
rvargas8c2d75c2014-09-26 19:50:2664 CancelIo(pipe_.Get());
[email protected]ee78622d2008-10-13 21:25:5065
[email protected]17b89142008-11-07 21:52:1566 // Closing the handle at this point prevents us from issuing more requests
67 // form OnIOCompleted().
rvargas8c2d75c2014-09-26 19:50:2668 if (pipe_.IsValid())
69 pipe_.Close();
initial.commit09911bf2008-07-26 23:55:2970
[email protected]17b89142008-11-07 21:52:1571 // Make sure all IO has completed.
[email protected]17b89142008-11-07 21:52:1572 while (input_state_.is_pending || output_state_.is_pending) {
[email protected]fd0a773a2013-04-30 20:55:0373 base::MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this);
[email protected]17b89142008-11-07 21:52:1574 }
[email protected]17b89142008-11-07 21:52:1575
initial.commit09911bf2008-07-26 23:55:2976 while (!output_queue_.empty()) {
erikchen06faf0c2015-08-27 19:49:5877 Message* m = output_queue_.front();
initial.commit09911bf2008-07-26 23:55:2978 output_queue_.pop();
erikchen06faf0c2015-08-27 19:49:5879 delete m;
initial.commit09911bf2008-07-26 23:55:2980 }
81}
82
[email protected]2f60c9b2014-06-06 20:13:5183bool ChannelWin::Send(Message* message) {
[email protected]c1e4bff32009-01-29 00:07:0684 DCHECK(thread_check_->CalledOnValidThread());
[email protected]2a9d601b2010-10-19 23:50:0085 DVLOG(2) << "sending message @" << message << " on channel @" << this
86 << " with type " << message->type()
87 << " (" << output_queue_.size() << " in queue)";
initial.commit09911bf2008-07-26 23:55:2988
erikchenc04ab34c2015-07-27 20:28:2089 if (!prelim_queue_.empty()) {
90 prelim_queue_.push(message);
91 return true;
92 }
93
94 if (message->HasBrokerableAttachments() &&
95 peer_pid_ == base::kNullProcessId) {
96 prelim_queue_.push(message);
97 return true;
98 }
99
100 return ProcessMessageForDelivery(message);
101}
102
103bool ChannelWin::ProcessMessageForDelivery(Message* message) {
erikcheneece6c32015-07-07 22:13:11104 // Sending a brokerable attachment requires a call to Channel::Send(), so
erikchenc04ab34c2015-07-27 20:28:20105 // both Send() and ProcessMessageForDelivery() may be re-entrant. Brokered
106 // attachments must be sent before the Message itself.
erikcheneece6c32015-07-07 22:13:11107 if (message->HasBrokerableAttachments()) {
108 DCHECK(broker_);
erikchenc04ab34c2015-07-27 20:28:20109 DCHECK(peer_pid_ != base::kNullProcessId);
erikcheneece6c32015-07-07 22:13:11110 for (const BrokerableAttachment* attachment :
111 message->attachment_set()->PeekBrokerableAttachments()) {
erikchenc04ab34c2015-07-27 20:28:20112 if (!broker_->SendAttachmentToProcess(attachment, peer_pid_)) {
113 delete message;
erikcheneece6c32015-07-07 22:13:11114 return false;
erikchenc04ab34c2015-07-27 20:28:20115 }
erikcheneece6c32015-07-07 22:13:11116 }
117 }
118
initial.commit09911bf2008-07-26 23:55:29119#ifdef IPC_MESSAGE_LOG_ENABLED
[email protected]8e8bb6d2010-12-13 08:18:55120 Logging::GetInstance()->OnSendMessage(message, "");
initial.commit09911bf2008-07-26 23:55:29121#endif
122
yuhaoz9b8157d2015-08-18 22:21:35123 TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
124 "ChannelWin::ProcessMessageForDelivery",
125 message->flags(),
126 TRACE_EVENT_FLAG_FLOW_OUT);
erikchenc04ab34c2015-07-27 20:28:20127
128 // |output_queue_| takes ownership of |message|.
erikchen06faf0c2015-08-27 19:49:58129 output_queue_.push(message);
initial.commit09911bf2008-07-26 23:55:29130 // ensure waiting to write
131 if (!waiting_connect_) {
132 if (!output_state_.is_pending) {
[email protected]c1afbd2c2008-10-13 19:19:36133 if (!ProcessOutgoingMessages(NULL, 0))
initial.commit09911bf2008-07-26 23:55:29134 return false;
initial.commit09911bf2008-07-26 23:55:29135 }
136 }
137
138 return true;
139}
140
erikchenc04ab34c2015-07-27 20:28:20141void ChannelWin::FlushPrelimQueue() {
142 DCHECK_NE(peer_pid_, base::kNullProcessId);
143
144 // Due to the possibly re-entrant nature of ProcessMessageForDelivery(), it
145 // is critical that |prelim_queue_| appears empty.
146 std::queue<Message*> prelim_queue;
147 prelim_queue_.swap(prelim_queue);
148
149 while (!prelim_queue.empty()) {
150 Message* m = prelim_queue.front();
151 ProcessMessageForDelivery(m);
152 prelim_queue.pop();
153 }
154}
155
erikchen27aa7d82015-06-16 21:21:04156AttachmentBroker* ChannelWin::GetAttachmentBroker() {
157 return broker_;
158}
159
[email protected]2f60c9b2014-06-06 20:13:51160base::ProcessId ChannelWin::GetPeerPID() const {
161 return peer_pid_;
162}
163
[email protected]64860882014-08-04 23:44:17164base::ProcessId ChannelWin::GetSelfPID() const {
165 return GetCurrentProcessId();
166}
167
[email protected]313c00e52011-08-09 06:46:06168// static
[email protected]2f60c9b2014-06-06 20:13:51169bool ChannelWin::IsNamedServerInitialized(
[email protected]313c00e52011-08-09 06:46:06170 const std::string& channel_id) {
[email protected]5c41e6e12012-03-17 02:20:46171 if (WaitNamedPipe(PipeName(channel_id, NULL).c_str(), 1))
[email protected]313c00e52011-08-09 06:46:06172 return true;
173 // If ERROR_SEM_TIMEOUT occurred, the pipe exists but is handling another
174 // connection.
175 return GetLastError() == ERROR_SEM_TIMEOUT;
176}
177
[email protected]2f60c9b2014-06-06 20:13:51178ChannelWin::ReadState ChannelWin::ReadData(
[email protected]215f6fd2012-03-03 08:55:45179 char* buffer,
180 int buffer_len,
181 int* /* bytes_read */) {
rvargas8c2d75c2014-09-26 19:50:26182 if (!pipe_.IsValid())
[email protected]215f6fd2012-03-03 08:55:45183 return READ_FAILED;
184
185 DWORD bytes_read = 0;
rvargas8c2d75c2014-09-26 19:50:26186 BOOL ok = ReadFile(pipe_.Get(), buffer, buffer_len,
[email protected]215f6fd2012-03-03 08:55:45187 &bytes_read, &input_state_.context.overlapped);
188 if (!ok) {
189 DWORD err = GetLastError();
190 if (err == ERROR_IO_PENDING) {
191 input_state_.is_pending = true;
192 return READ_PENDING;
193 }
194 LOG(ERROR) << "pipe error: " << err;
195 return READ_FAILED;
196 }
197
198 // We could return READ_SUCCEEDED here. But the way that this code is
199 // structured we instead go back to the message loop. Our completion port
200 // will be signalled even in the "synchronously completed" state.
201 //
202 // This allows us to potentially process some outgoing messages and
203 // interleave other work on this thread when we're getting hammered with
204 // input messages. Potentially, this could be tuned to be more efficient
205 // with some testing.
206 input_state_.is_pending = true;
207 return READ_PENDING;
208}
209
erikchende9412b82015-07-27 18:26:14210bool ChannelWin::ShouldDispatchInputMessage(Message* msg) {
[email protected]05908782012-04-03 08:49:43211 // Make sure we get a hello when client validation is required.
212 if (validate_client_)
213 return IsHelloMessage(*msg);
[email protected]215f6fd2012-03-03 08:55:45214 return true;
215}
216
erikchende9412b82015-07-27 18:26:14217bool ChannelWin::GetNonBrokeredAttachments(Message* msg) {
218 return true;
219}
220
[email protected]2f60c9b2014-06-06 20:13:51221void ChannelWin::HandleInternalMessage(const Message& msg) {
[email protected]dc875dc2013-10-15 00:07:00222 DCHECK_EQ(msg.type(), static_cast<unsigned>(Channel::HELLO_MESSAGE_TYPE));
[email protected]215f6fd2012-03-03 08:55:45223 // The hello message contains one parameter containing the PID.
brettwbd4d7112015-06-03 04:29:25224 base::PickleIterator it(msg);
[email protected]7edae3d02012-12-17 20:23:47225 int32 claimed_pid;
226 bool failed = !it.ReadInt(&claimed_pid);
227
228 if (!failed && validate_client_) {
229 int32 secret;
230 failed = it.ReadInt(&secret) ? (secret != client_secret_) : true;
231 }
232
233 if (failed) {
[email protected]5c41e6e12012-03-17 02:20:46234 NOTREACHED();
[email protected]5c41e6e12012-03-17 02:20:46235 Close();
236 listener()->OnChannelError();
237 return;
238 }
[email protected]7edae3d02012-12-17 20:23:47239
[email protected]0a6fc4b2012-04-05 02:38:34240 peer_pid_ = claimed_pid;
[email protected]7edae3d02012-12-17 20:23:47241 // Validation completed.
[email protected]05908782012-04-03 08:49:43242 validate_client_ = false;
erikchenc04ab34c2015-07-27 20:28:20243
244 FlushPrelimQueue();
245
[email protected]5c41e6e12012-03-17 02:20:46246 listener()->OnChannelConnected(claimed_pid);
[email protected]215f6fd2012-03-03 08:55:45247}
248
erikchen3c175a32015-07-28 23:16:48249base::ProcessId ChannelWin::GetSenderPID() {
250 return GetPeerPID();
251}
252
erikchen8c73f832015-07-30 22:26:08253bool ChannelWin::IsAttachmentBrokerEndpoint() {
254 return is_attachment_broker_endpoint();
255}
256
[email protected]2f60c9b2014-06-06 20:13:51257bool ChannelWin::DidEmptyInputBuffers() {
[email protected]d805c6a2012-03-08 12:30:28258 // We don't need to do anything here.
[email protected]215f6fd2012-03-03 08:55:45259 return true;
260}
261
[email protected]313c00e52011-08-09 06:46:06262// static
[email protected]2f60c9b2014-06-06 20:13:51263const base::string16 ChannelWin::PipeName(
[email protected]5c41e6e12012-03-17 02:20:46264 const std::string& channel_id, int32* secret) {
[email protected]c2391b82011-05-06 17:39:07265 std::string name("\\\\.\\pipe\\chrome.");
[email protected]5c41e6e12012-03-17 02:20:46266
267 // Prevent the shared secret from ending up in the pipe name.
268 size_t index = channel_id.find_first_of('\\');
269 if (index != std::string::npos) {
270 if (secret) // Retrieve the secret if asked for.
271 base::StringToInt(channel_id.substr(index + 1), secret);
thestige5c64d92014-11-07 01:19:24272 return base::ASCIIToUTF16(name.append(channel_id.substr(0, index - 1)));
[email protected]5c41e6e12012-03-17 02:20:46273 }
274
275 // This case is here to support predictable named pipes in tests.
276 if (secret)
277 *secret = 0;
thestige5c64d92014-11-07 01:19:24278 return base::ASCIIToUTF16(name.append(channel_id));
initial.commit09911bf2008-07-26 23:55:29279}
280
[email protected]2f60c9b2014-06-06 20:13:51281bool ChannelWin::CreatePipe(const IPC::ChannelHandle &channel_handle,
rvargas8c2d75c2014-09-26 19:50:26282 Mode mode) {
283 DCHECK(!pipe_.IsValid());
[email protected]905cda812013-12-20 09:04:55284 base::string16 pipe_name;
[email protected]a7c03d4f32012-01-24 02:36:05285 // If we already have a valid pipe for channel just copy it.
286 if (channel_handle.pipe.handle) {
rvargas8c2d75c2014-09-26 19:50:26287 // TODO(rvargas) crbug.com/415294: ChannelHandle should either go away in
288 // favor of two independent entities (name/file), or it should be a move-
289 // only type with a base::File member. In any case, this code should not
290 // call DuplicateHandle.
[email protected]a7c03d4f32012-01-24 02:36:05291 DCHECK(channel_handle.name.empty());
292 pipe_name = L"Not Available"; // Just used for LOG
293 // Check that the given pipe confirms to the specified mode. We can
294 // only check for PIPE_TYPE_MESSAGE & PIPE_SERVER_END flags since the
295 // other flags (PIPE_TYPE_BYTE, and PIPE_CLIENT_END) are defined as 0.
296 DWORD flags = 0;
297 GetNamedPipeInfo(channel_handle.pipe.handle, &flags, NULL, NULL, NULL);
298 DCHECK(!(flags & PIPE_TYPE_MESSAGE));
299 if (((mode & MODE_SERVER_FLAG) && !(flags & PIPE_SERVER_END)) ||
300 ((mode & MODE_CLIENT_FLAG) && (flags & PIPE_SERVER_END))) {
301 LOG(WARNING) << "Inconsistent open mode. Mode :" << mode;
302 return false;
303 }
rvargas8c2d75c2014-09-26 19:50:26304 HANDLE local_handle;
[email protected]a7c03d4f32012-01-24 02:36:05305 if (!DuplicateHandle(GetCurrentProcess(),
306 channel_handle.pipe.handle,
307 GetCurrentProcess(),
rvargas8c2d75c2014-09-26 19:50:26308 &local_handle,
[email protected]a7c03d4f32012-01-24 02:36:05309 0,
310 FALSE,
311 DUPLICATE_SAME_ACCESS)) {
312 LOG(WARNING) << "DuplicateHandle failed. Error :" << GetLastError();
313 return false;
314 }
rvargas8c2d75c2014-09-26 19:50:26315 pipe_.Set(local_handle);
[email protected]a7c03d4f32012-01-24 02:36:05316 } else if (mode & MODE_SERVER_FLAG) {
317 DCHECK(!channel_handle.pipe.handle);
318 const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
319 FILE_FLAG_FIRST_PIPE_INSTANCE;
[email protected]5c41e6e12012-03-17 02:20:46320 pipe_name = PipeName(channel_handle.name, &client_secret_);
321 validate_client_ = !!client_secret_;
rvargas8c2d75c2014-09-26 19:50:26322 pipe_.Set(CreateNamedPipeW(pipe_name.c_str(),
323 open_mode,
324 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
325 1,
326 Channel::kReadBufferSize,
327 Channel::kReadBufferSize,
328 5000,
329 NULL));
[email protected]1707726c2011-02-03 20:35:09330 } else if (mode & MODE_CLIENT_FLAG) {
[email protected]a7c03d4f32012-01-24 02:36:05331 DCHECK(!channel_handle.pipe.handle);
[email protected]5c41e6e12012-03-17 02:20:46332 pipe_name = PipeName(channel_handle.name, &client_secret_);
rvargas8c2d75c2014-09-26 19:50:26333 pipe_.Set(CreateFileW(pipe_name.c_str(),
334 GENERIC_READ | GENERIC_WRITE,
335 0,
336 NULL,
337 OPEN_EXISTING,
forshaw4a94dff2014-12-16 21:32:53338 SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS |
rvargas8c2d75c2014-09-26 19:50:26339 FILE_FLAG_OVERLAPPED,
340 NULL));
[email protected]1707726c2011-02-03 20:35:09341 } else {
342 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:29343 }
[email protected]a7c03d4f32012-01-24 02:36:05344
rvargas8c2d75c2014-09-26 19:50:26345 if (!pipe_.IsValid()) {
initial.commit09911bf2008-07-26 23:55:29346 // If this process is being closed, the pipe may be gone already.
[email protected]8398bf12014-06-26 21:11:34347 PLOG(WARNING) << "Unable to create pipe \"" << pipe_name << "\" in "
348 << (mode & MODE_SERVER_FLAG ? "server" : "client") << " mode";
initial.commit09911bf2008-07-26 23:55:29349 return false;
350 }
351
352 // Create the Hello message to be sent when Connect is called
353 scoped_ptr<Message> m(new Message(MSG_ROUTING_NONE,
[email protected]753bb252013-11-04 22:28:12354 HELLO_MESSAGE_TYPE,
355 IPC::Message::PRIORITY_NORMAL));
[email protected]5c41e6e12012-03-17 02:20:46356
357 // Don't send the secret to the untrusted process, and don't send a secret
358 // if the value is zero (for IPC backwards compatability).
359 int32 secret = validate_client_ ? 0 : client_secret_;
360 if (!m->WriteInt(GetCurrentProcessId()) ||
361 (secret && !m->WriteUInt32(secret))) {
rvargas8c2d75c2014-09-26 19:50:26362 pipe_.Close();
initial.commit09911bf2008-07-26 23:55:29363 return false;
364 }
365
erikchen06faf0c2015-08-27 19:49:58366 output_queue_.push(m.release());
initial.commit09911bf2008-07-26 23:55:29367 return true;
368}
369
[email protected]2f60c9b2014-06-06 20:13:51370bool ChannelWin::Connect() {
[email protected]19340722009-08-17 19:53:25371 DLOG_IF(WARNING, thread_check_.get()) << "Connect called more than once";
initial.commit09911bf2008-07-26 23:55:29372
[email protected]c1e4bff32009-01-29 00:07:06373 if (!thread_check_.get())
[email protected]327e52b2012-06-25 21:11:36374 thread_check_.reset(new base::ThreadChecker());
[email protected]c1e4bff32009-01-29 00:07:06375
rvargas8c2d75c2014-09-26 19:50:26376 if (!pipe_.IsValid())
initial.commit09911bf2008-07-26 23:55:29377 return false;
378
rvargas8c2d75c2014-09-26 19:50:26379 base::MessageLoopForIO::current()->RegisterIOHandler(pipe_.Get(), this);
[email protected]c1afbd2c2008-10-13 19:19:36380
initial.commit09911bf2008-07-26 23:55:29381 // Check to see if there is a client connected to our pipe...
382 if (waiting_connect_)
383 ProcessConnection();
384
385 if (!input_state_.is_pending) {
[email protected]c1afbd2c2008-10-13 19:19:36386 // Complete setup asynchronously. By not setting input_state_.is_pending
387 // to true, we indicate to OnIOCompleted that this is the special
388 // initialization signal.
[email protected]fd0a773a2013-04-30 20:55:03389 base::MessageLoopForIO::current()->PostTask(
390 FROM_HERE,
[email protected]2f60c9b2014-06-06 20:13:51391 base::Bind(&ChannelWin::OnIOCompleted,
[email protected]fd0a773a2013-04-30 20:55:03392 weak_factory_.GetWeakPtr(),
393 &input_state_.context,
394 0,
395 0));
initial.commit09911bf2008-07-26 23:55:29396 }
397
398 if (!waiting_connect_)
[email protected]c1afbd2c2008-10-13 19:19:36399 ProcessOutgoingMessages(NULL, 0);
initial.commit09911bf2008-07-26 23:55:29400 return true;
401}
402
[email protected]2f60c9b2014-06-06 20:13:51403bool ChannelWin::ProcessConnection() {
[email protected]c1e4bff32009-01-29 00:07:06404 DCHECK(thread_check_->CalledOnValidThread());
[email protected]17b89142008-11-07 21:52:15405 if (input_state_.is_pending)
[email protected]c1afbd2c2008-10-13 19:19:36406 input_state_.is_pending = false;
initial.commit09911bf2008-07-26 23:55:29407
408 // Do we have a client connected to our pipe?
rvargas8c2d75c2014-09-26 19:50:26409 if (!pipe_.IsValid())
[email protected]17b89142008-11-07 21:52:15410 return false;
411
rvargas8c2d75c2014-09-26 19:50:26412 BOOL ok = ConnectNamedPipe(pipe_.Get(), &input_state_.context.overlapped);
initial.commit09911bf2008-07-26 23:55:29413 DWORD err = GetLastError();
414 if (ok) {
415 // Uhm, the API documentation says that this function should never
416 // return success when used in overlapped mode.
417 NOTREACHED();
418 return false;
419 }
420
421 switch (err) {
422 case ERROR_IO_PENDING:
423 input_state_.is_pending = true;
initial.commit09911bf2008-07-26 23:55:29424 break;
425 case ERROR_PIPE_CONNECTED:
426 waiting_connect_ = false;
427 break;
[email protected]20aa32c2009-07-14 22:25:49428 case ERROR_NO_DATA:
429 // The pipe is being closed.
430 return false;
initial.commit09911bf2008-07-26 23:55:29431 default:
432 NOTREACHED();
433 return false;
434 }
435
436 return true;
437}
438
[email protected]2f60c9b2014-06-06 20:13:51439bool ChannelWin::ProcessOutgoingMessages(
[email protected]fd0a773a2013-04-30 20:55:03440 base::MessageLoopForIO::IOContext* context,
[email protected]514411fc2008-12-10 22:28:11441 DWORD bytes_written) {
initial.commit09911bf2008-07-26 23:55:29442 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
443 // no connection?
[email protected]c1e4bff32009-01-29 00:07:06444 DCHECK(thread_check_->CalledOnValidThread());
initial.commit09911bf2008-07-26 23:55:29445
446 if (output_state_.is_pending) {
[email protected]c1afbd2c2008-10-13 19:19:36447 DCHECK(context);
initial.commit09911bf2008-07-26 23:55:29448 output_state_.is_pending = false;
[email protected]c1afbd2c2008-10-13 19:19:36449 if (!context || bytes_written == 0) {
initial.commit09911bf2008-07-26 23:55:29450 DWORD err = GetLastError();
451 LOG(ERROR) << "pipe error: " << err;
452 return false;
453 }
[email protected]c1afbd2c2008-10-13 19:19:36454 // Message was sent.
[email protected]88ecb5f52014-01-21 14:29:36455 CHECK(!output_queue_.empty());
erikchen06faf0c2015-08-27 19:49:58456 Message* m = output_queue_.front();
initial.commit09911bf2008-07-26 23:55:29457 output_queue_.pop();
erikchen06faf0c2015-08-27 19:49:58458 delete m;
initial.commit09911bf2008-07-26 23:55:29459 }
460
[email protected]17b89142008-11-07 21:52:15461 if (output_queue_.empty())
462 return true;
463
rvargas8c2d75c2014-09-26 19:50:26464 if (!pipe_.IsValid())
[email protected]17b89142008-11-07 21:52:15465 return false;
466
467 // Write to pipe...
erikchen06faf0c2015-08-27 19:49:58468 Message* m = output_queue_.front();
469 DCHECK(m->size() <= INT_MAX);
470 BOOL ok = WriteFile(pipe_.Get(),
471 m->data(),
472 static_cast<uint32>(m->size()),
473 NULL,
[email protected]17b89142008-11-07 21:52:15474 &output_state_.context.overlapped);
475 if (!ok) {
rvargascd742bcb2014-11-14 19:27:31476 DWORD write_error = GetLastError();
477 if (write_error == ERROR_IO_PENDING) {
[email protected]17b89142008-11-07 21:52:15478 output_state_.is_pending = true;
initial.commit09911bf2008-07-26 23:55:29479
erikchen06faf0c2015-08-27 19:49:58480 DVLOG(2) << "sent pending message @" << m << " on channel @" << this
481 << " with type " << m->type();
initial.commit09911bf2008-07-26 23:55:29482
[email protected]17b89142008-11-07 21:52:15483 return true;
initial.commit09911bf2008-07-26 23:55:29484 }
rvargascd742bcb2014-11-14 19:27:31485 LOG(ERROR) << "pipe error: " << write_error;
[email protected]17b89142008-11-07 21:52:15486 return false;
initial.commit09911bf2008-07-26 23:55:29487 }
488
erikchen06faf0c2015-08-27 19:49:58489 DVLOG(2) << "sent message @" << m << " on channel @" << this
490 << " with type " << m->type();
[email protected]17b89142008-11-07 21:52:15491
492 output_state_.is_pending = true;
initial.commit09911bf2008-07-26 23:55:29493 return true;
494}
495
[email protected]2f60c9b2014-06-06 20:13:51496void ChannelWin::OnIOCompleted(
[email protected]fd0a773a2013-04-30 20:55:03497 base::MessageLoopForIO::IOContext* context,
498 DWORD bytes_transfered,
499 DWORD error) {
[email protected]215f6fd2012-03-03 08:55:45500 bool ok = true;
[email protected]c1e4bff32009-01-29 00:07:06501 DCHECK(thread_check_->CalledOnValidThread());
[email protected]17b89142008-11-07 21:52:15502 if (context == &input_state_.context) {
initial.commit09911bf2008-07-26 23:55:29503 if (waiting_connect_) {
[email protected]17b89142008-11-07 21:52:15504 if (!ProcessConnection())
505 return;
initial.commit09911bf2008-07-26 23:55:29506 // We may have some messages queued up to send...
507 if (!output_queue_.empty() && !output_state_.is_pending)
[email protected]c1afbd2c2008-10-13 19:19:36508 ProcessOutgoingMessages(NULL, 0);
initial.commit09911bf2008-07-26 23:55:29509 if (input_state_.is_pending)
510 return;
511 // else, fall-through and look for incoming messages...
512 }
[email protected]215f6fd2012-03-03 08:55:45513
514 // We don't support recursion through OnMessageReceived yet!
initial.commit09911bf2008-07-26 23:55:29515 DCHECK(!processing_incoming_);
[email protected]997ec9f2012-11-21 04:44:14516 base::AutoReset<bool> auto_reset_processing_incoming(
517 &processing_incoming_, true);
[email protected]215f6fd2012-03-03 08:55:45518
519 // Process the new data.
520 if (input_state_.is_pending) {
521 // This is the normal case for everything except the initialization step.
522 input_state_.is_pending = false;
erikchende9412b82015-07-27 18:26:14523 if (!bytes_transfered) {
[email protected]215f6fd2012-03-03 08:55:45524 ok = false;
erikchende9412b82015-07-27 18:26:14525 } else if (pipe_.IsValid()) {
526 ok = (AsyncReadComplete(bytes_transfered) != DISPATCH_ERROR);
527 }
[email protected]215f6fd2012-03-03 08:55:45528 } else {
529 DCHECK(!bytes_transfered);
530 }
531
532 // Request more data.
533 if (ok)
erikchende9412b82015-07-27 18:26:14534 ok = (ProcessIncomingMessages() != DISPATCH_ERROR);
initial.commit09911bf2008-07-26 23:55:29535 } else {
[email protected]17b89142008-11-07 21:52:15536 DCHECK(context == &output_state_.context);
[email protected]65727eb2014-07-31 12:24:29537 CHECK(output_state_.is_pending);
[email protected]c1afbd2c2008-10-13 19:19:36538 ok = ProcessOutgoingMessages(context, bytes_transfered);
initial.commit09911bf2008-07-26 23:55:29539 }
rvargas8c2d75c2014-09-26 19:50:26540 if (!ok && pipe_.IsValid()) {
[email protected]17b89142008-11-07 21:52:15541 // We don't want to re-enter Close().
initial.commit09911bf2008-07-26 23:55:29542 Close();
[email protected]d805c6a2012-03-08 12:30:28543 listener()->OnChannelError();
initial.commit09911bf2008-07-26 23:55:29544 }
545}
546
[email protected]514411fc2008-12-10 22:28:11547//------------------------------------------------------------------------------
[email protected]2f60c9b2014-06-06 20:13:51548// Channel's methods
[email protected]514411fc2008-12-10 22:28:11549
[email protected]2f60c9b2014-06-06 20:13:51550// static
erikchen27aa7d82015-06-16 21:21:04551scoped_ptr<Channel> Channel::Create(const IPC::ChannelHandle& channel_handle,
552 Mode mode,
553 Listener* listener,
554 AttachmentBroker* broker) {
[email protected]2f60c9b2014-06-06 20:13:51555 return scoped_ptr<Channel>(
erikchen27aa7d82015-06-16 21:21:04556 new ChannelWin(channel_handle, mode, listener, broker));
[email protected]514411fc2008-12-10 22:28:11557}
558
[email protected]313c00e52011-08-09 06:46:06559// static
560bool Channel::IsNamedServerInitialized(const std::string& channel_id) {
[email protected]2f60c9b2014-06-06 20:13:51561 return ChannelWin::IsNamedServerInitialized(channel_id);
[email protected]313c00e52011-08-09 06:46:06562}
563
[email protected]5c41e6e12012-03-17 02:20:46564// static
565std::string Channel::GenerateVerifiedChannelID(const std::string& prefix) {
566 // Windows pipes can be enumerated by low-privileged processes. So, we
567 // append a strong random value after the \ character. This value is not
568 // included in the pipe name, but sent as part of the client hello, to
569 // hijacking the pipe name to spoof the client.
570
571 std::string id = prefix;
572 if (!id.empty())
573 id.append(".");
574
575 int secret;
576 do { // Guarantee we get a non-zero value.
577 secret = base::RandInt(0, std::numeric_limits<int>::max());
578 } while (secret == 0);
579
580 id.append(GenerateUniqueRandomChannelID());
581 return id.append(base::StringPrintf("\\%d", secret));
582}
583
[email protected]514411fc2008-12-10 22:28:11584} // namespace IPC