Minor Python style clean-up
[chromium-blink-merge.git] / ipc / ipc_channel_win.cc
blob56dc4b7cba13ac59b41295d5e3607f83dea0d893
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 "ipc/ipc_channel_win.h"
7 #include <stdint.h>
8 #include <windows.h>
10 #include "base/auto_reset.h"
11 #include "base/bind.h"
12 #include "base/compiler_specific.h"
13 #include "base/logging.h"
14 #include "base/pickle.h"
15 #include "base/process/process_handle.h"
16 #include "base/rand_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/threading/thread_checker.h"
20 #include "base/win/scoped_handle.h"
21 #include "ipc/attachment_broker.h"
22 #include "ipc/ipc_listener.h"
23 #include "ipc/ipc_logging.h"
24 #include "ipc/ipc_message_attachment_set.h"
25 #include "ipc/ipc_message_utils.h"
27 namespace IPC {
29 ChannelWin::State::State(ChannelWin* channel) : is_pending(false) {
30 memset(&context.overlapped, 0, sizeof(context.overlapped));
31 context.handler = channel;
34 ChannelWin::State::~State() {
35 static_assert(offsetof(ChannelWin::State, context) == 0,
36 "ChannelWin::State should have context as its first data"
37 "member.");
40 ChannelWin::ChannelWin(const IPC::ChannelHandle& channel_handle,
41 Mode mode,
42 Listener* listener)
43 : ChannelReader(listener),
44 input_state_(this),
45 output_state_(this),
46 peer_pid_(base::kNullProcessId),
47 waiting_connect_(mode & MODE_SERVER_FLAG),
48 processing_incoming_(false),
49 validate_client_(false),
50 client_secret_(0),
51 weak_factory_(this) {
52 CreatePipe(channel_handle, mode);
55 ChannelWin::~ChannelWin() {
56 CleanUp();
57 Close();
60 void ChannelWin::Close() {
61 if (thread_check_.get())
62 DCHECK(thread_check_->CalledOnValidThread());
64 if (input_state_.is_pending || output_state_.is_pending)
65 CancelIo(pipe_.Get());
67 // Closing the handle at this point prevents us from issuing more requests
68 // form OnIOCompleted().
69 if (pipe_.IsValid())
70 pipe_.Close();
72 // Make sure all IO has completed.
73 while (input_state_.is_pending || output_state_.is_pending) {
74 base::MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this);
77 while (!output_queue_.empty()) {
78 OutputElement* element = output_queue_.front();
79 output_queue_.pop();
80 delete element;
84 bool ChannelWin::Send(Message* message) {
85 DCHECK(thread_check_->CalledOnValidThread());
86 DVLOG(2) << "sending message @" << message << " on channel @" << this
87 << " with type " << message->type()
88 << " (" << output_queue_.size() << " in queue)";
90 if (!prelim_queue_.empty()) {
91 prelim_queue_.push(message);
92 return true;
95 if (message->HasBrokerableAttachments() &&
96 peer_pid_ == base::kNullProcessId) {
97 prelim_queue_.push(message);
98 return true;
101 return ProcessMessageForDelivery(message);
104 bool ChannelWin::ProcessMessageForDelivery(Message* message) {
105 // Sending a brokerable attachment requires a call to Channel::Send(), so
106 // both Send() and ProcessMessageForDelivery() may be re-entrant. Brokered
107 // attachments must be sent before the Message itself.
108 if (message->HasBrokerableAttachments()) {
109 DCHECK(GetAttachmentBroker());
110 DCHECK(peer_pid_ != base::kNullProcessId);
111 for (const BrokerableAttachment* attachment :
112 message->attachment_set()->PeekBrokerableAttachments()) {
113 if (!GetAttachmentBroker()->SendAttachmentToProcess(attachment,
114 peer_pid_)) {
115 delete message;
116 return false;
121 #ifdef IPC_MESSAGE_LOG_ENABLED
122 Logging::GetInstance()->OnSendMessage(message, "");
123 #endif
125 TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
126 "ChannelWin::ProcessMessageForDelivery",
127 message->flags(),
128 TRACE_EVENT_FLAG_FLOW_OUT);
130 // |output_queue_| takes ownership of |message|.
131 OutputElement* element = new OutputElement(message);
132 output_queue_.push(element);
134 // TODO(erikchen): Serialize the brokerable attachments and add them to the
135 // output_queue_. http://crbug.com/493414.
137 // ensure waiting to write
138 if (!waiting_connect_) {
139 if (!output_state_.is_pending) {
140 if (!ProcessOutgoingMessages(NULL, 0))
141 return false;
145 return true;
148 void ChannelWin::FlushPrelimQueue() {
149 DCHECK_NE(peer_pid_, base::kNullProcessId);
151 // Due to the possibly re-entrant nature of ProcessMessageForDelivery(), it
152 // is critical that |prelim_queue_| appears empty.
153 std::queue<Message*> prelim_queue;
154 prelim_queue_.swap(prelim_queue);
156 while (!prelim_queue.empty()) {
157 Message* m = prelim_queue.front();
158 ProcessMessageForDelivery(m);
159 prelim_queue.pop();
163 AttachmentBroker* ChannelWin::GetAttachmentBroker() {
164 return AttachmentBroker::GetGlobal();
167 base::ProcessId ChannelWin::GetPeerPID() const {
168 return peer_pid_;
171 base::ProcessId ChannelWin::GetSelfPID() const {
172 return GetCurrentProcessId();
175 // static
176 bool ChannelWin::IsNamedServerInitialized(
177 const std::string& channel_id) {
178 if (WaitNamedPipe(PipeName(channel_id, NULL).c_str(), 1))
179 return true;
180 // If ERROR_SEM_TIMEOUT occurred, the pipe exists but is handling another
181 // connection.
182 return GetLastError() == ERROR_SEM_TIMEOUT;
185 ChannelWin::ReadState ChannelWin::ReadData(
186 char* buffer,
187 int buffer_len,
188 int* /* bytes_read */) {
189 if (!pipe_.IsValid())
190 return READ_FAILED;
192 DWORD bytes_read = 0;
193 BOOL ok = ReadFile(pipe_.Get(), buffer, buffer_len,
194 &bytes_read, &input_state_.context.overlapped);
195 if (!ok) {
196 DWORD err = GetLastError();
197 if (err == ERROR_IO_PENDING) {
198 input_state_.is_pending = true;
199 return READ_PENDING;
201 LOG(ERROR) << "pipe error: " << err;
202 return READ_FAILED;
205 // We could return READ_SUCCEEDED here. But the way that this code is
206 // structured we instead go back to the message loop. Our completion port
207 // will be signalled even in the "synchronously completed" state.
209 // This allows us to potentially process some outgoing messages and
210 // interleave other work on this thread when we're getting hammered with
211 // input messages. Potentially, this could be tuned to be more efficient
212 // with some testing.
213 input_state_.is_pending = true;
214 return READ_PENDING;
217 bool ChannelWin::ShouldDispatchInputMessage(Message* msg) {
218 // Make sure we get a hello when client validation is required.
219 if (validate_client_)
220 return IsHelloMessage(*msg);
221 return true;
224 bool ChannelWin::GetNonBrokeredAttachments(Message* msg) {
225 return true;
228 void ChannelWin::HandleInternalMessage(const Message& msg) {
229 DCHECK_EQ(msg.type(), static_cast<unsigned>(Channel::HELLO_MESSAGE_TYPE));
230 // The hello message contains one parameter containing the PID.
231 base::PickleIterator it(msg);
232 int32_t claimed_pid;
233 bool failed = !it.ReadInt(&claimed_pid);
235 if (!failed && validate_client_) {
236 int32_t secret;
237 failed = it.ReadInt(&secret) ? (secret != client_secret_) : true;
240 if (failed) {
241 NOTREACHED();
242 Close();
243 listener()->OnChannelError();
244 return;
247 peer_pid_ = claimed_pid;
248 // Validation completed.
249 validate_client_ = false;
251 FlushPrelimQueue();
253 listener()->OnChannelConnected(claimed_pid);
256 base::ProcessId ChannelWin::GetSenderPID() {
257 return GetPeerPID();
260 bool ChannelWin::IsAttachmentBrokerEndpoint() {
261 return is_attachment_broker_endpoint();
264 bool ChannelWin::DidEmptyInputBuffers() {
265 // We don't need to do anything here.
266 return true;
269 // static
270 const base::string16 ChannelWin::PipeName(const std::string& channel_id,
271 int32_t* secret) {
272 std::string name("\\\\.\\pipe\\chrome.");
274 // Prevent the shared secret from ending up in the pipe name.
275 size_t index = channel_id.find_first_of('\\');
276 if (index != std::string::npos) {
277 if (secret) // Retrieve the secret if asked for.
278 base::StringToInt(channel_id.substr(index + 1), secret);
279 return base::ASCIIToUTF16(name.append(channel_id.substr(0, index - 1)));
282 // This case is here to support predictable named pipes in tests.
283 if (secret)
284 *secret = 0;
285 return base::ASCIIToUTF16(name.append(channel_id));
288 bool ChannelWin::CreatePipe(const IPC::ChannelHandle &channel_handle,
289 Mode mode) {
290 DCHECK(!pipe_.IsValid());
291 base::string16 pipe_name;
292 // If we already have a valid pipe for channel just copy it.
293 if (channel_handle.pipe.handle) {
294 // TODO(rvargas) crbug.com/415294: ChannelHandle should either go away in
295 // favor of two independent entities (name/file), or it should be a move-
296 // only type with a base::File member. In any case, this code should not
297 // call DuplicateHandle.
298 DCHECK(channel_handle.name.empty());
299 pipe_name = L"Not Available"; // Just used for LOG
300 // Check that the given pipe confirms to the specified mode. We can
301 // only check for PIPE_TYPE_MESSAGE & PIPE_SERVER_END flags since the
302 // other flags (PIPE_TYPE_BYTE, and PIPE_CLIENT_END) are defined as 0.
303 DWORD flags = 0;
304 GetNamedPipeInfo(channel_handle.pipe.handle, &flags, NULL, NULL, NULL);
305 DCHECK(!(flags & PIPE_TYPE_MESSAGE));
306 if (((mode & MODE_SERVER_FLAG) && !(flags & PIPE_SERVER_END)) ||
307 ((mode & MODE_CLIENT_FLAG) && (flags & PIPE_SERVER_END))) {
308 LOG(WARNING) << "Inconsistent open mode. Mode :" << mode;
309 return false;
311 HANDLE local_handle;
312 if (!DuplicateHandle(GetCurrentProcess(),
313 channel_handle.pipe.handle,
314 GetCurrentProcess(),
315 &local_handle,
317 FALSE,
318 DUPLICATE_SAME_ACCESS)) {
319 LOG(WARNING) << "DuplicateHandle failed. Error :" << GetLastError();
320 return false;
322 pipe_.Set(local_handle);
323 } else if (mode & MODE_SERVER_FLAG) {
324 DCHECK(!channel_handle.pipe.handle);
325 const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
326 FILE_FLAG_FIRST_PIPE_INSTANCE;
327 pipe_name = PipeName(channel_handle.name, &client_secret_);
328 validate_client_ = !!client_secret_;
329 pipe_.Set(CreateNamedPipeW(pipe_name.c_str(),
330 open_mode,
331 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
333 Channel::kReadBufferSize,
334 Channel::kReadBufferSize,
335 5000,
336 NULL));
337 } else if (mode & MODE_CLIENT_FLAG) {
338 DCHECK(!channel_handle.pipe.handle);
339 pipe_name = PipeName(channel_handle.name, &client_secret_);
340 pipe_.Set(CreateFileW(pipe_name.c_str(),
341 GENERIC_READ | GENERIC_WRITE,
343 NULL,
344 OPEN_EXISTING,
345 SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS |
346 FILE_FLAG_OVERLAPPED,
347 NULL));
348 } else {
349 NOTREACHED();
352 if (!pipe_.IsValid()) {
353 // If this process is being closed, the pipe may be gone already.
354 PLOG(WARNING) << "Unable to create pipe \"" << pipe_name << "\" in "
355 << (mode & MODE_SERVER_FLAG ? "server" : "client") << " mode";
356 return false;
359 // Create the Hello message to be sent when Connect is called
360 scoped_ptr<Message> m(new Message(MSG_ROUTING_NONE,
361 HELLO_MESSAGE_TYPE,
362 IPC::Message::PRIORITY_NORMAL));
364 // Don't send the secret to the untrusted process, and don't send a secret
365 // if the value is zero (for IPC backwards compatability).
366 int32_t secret = validate_client_ ? 0 : client_secret_;
367 if (!m->WriteInt(GetCurrentProcessId()) ||
368 (secret && !m->WriteUInt32(secret))) {
369 pipe_.Close();
370 return false;
373 OutputElement* element = new OutputElement(m.release());
374 output_queue_.push(element);
375 return true;
378 bool ChannelWin::Connect() {
379 DLOG_IF(WARNING, thread_check_.get()) << "Connect called more than once";
381 if (!thread_check_.get())
382 thread_check_.reset(new base::ThreadChecker());
384 if (!pipe_.IsValid())
385 return false;
387 base::MessageLoopForIO::current()->RegisterIOHandler(pipe_.Get(), this);
389 // Check to see if there is a client connected to our pipe...
390 if (waiting_connect_)
391 ProcessConnection();
393 if (!input_state_.is_pending) {
394 // Complete setup asynchronously. By not setting input_state_.is_pending
395 // to true, we indicate to OnIOCompleted that this is the special
396 // initialization signal.
397 base::MessageLoopForIO::current()->PostTask(
398 FROM_HERE,
399 base::Bind(&ChannelWin::OnIOCompleted,
400 weak_factory_.GetWeakPtr(),
401 &input_state_.context,
403 0));
406 if (!waiting_connect_)
407 ProcessOutgoingMessages(NULL, 0);
408 return true;
411 bool ChannelWin::ProcessConnection() {
412 DCHECK(thread_check_->CalledOnValidThread());
413 if (input_state_.is_pending)
414 input_state_.is_pending = false;
416 // Do we have a client connected to our pipe?
417 if (!pipe_.IsValid())
418 return false;
420 BOOL ok = ConnectNamedPipe(pipe_.Get(), &input_state_.context.overlapped);
421 DWORD err = GetLastError();
422 if (ok) {
423 // Uhm, the API documentation says that this function should never
424 // return success when used in overlapped mode.
425 NOTREACHED();
426 return false;
429 switch (err) {
430 case ERROR_IO_PENDING:
431 input_state_.is_pending = true;
432 break;
433 case ERROR_PIPE_CONNECTED:
434 waiting_connect_ = false;
435 break;
436 case ERROR_NO_DATA:
437 // The pipe is being closed.
438 return false;
439 default:
440 NOTREACHED();
441 return false;
444 return true;
447 bool ChannelWin::ProcessOutgoingMessages(
448 base::MessageLoopForIO::IOContext* context,
449 DWORD bytes_written) {
450 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
451 // no connection?
452 DCHECK(thread_check_->CalledOnValidThread());
454 if (output_state_.is_pending) {
455 DCHECK(context);
456 output_state_.is_pending = false;
457 if (!context || bytes_written == 0) {
458 DWORD err = GetLastError();
459 LOG(ERROR) << "pipe error: " << err;
460 return false;
462 // Message was sent.
463 CHECK(!output_queue_.empty());
464 OutputElement* element = output_queue_.front();
465 output_queue_.pop();
466 delete element;
469 if (output_queue_.empty())
470 return true;
472 if (!pipe_.IsValid())
473 return false;
475 // Write to pipe...
476 OutputElement* element = output_queue_.front();
478 // TODO(erikchen): Temporary code to help track http://crbug.com/527588.
480 const Message* m = element->get_message();
481 if (m) {
482 Channel::MessageVerifier verifier = Channel::GetMessageVerifier();
483 if (verifier)
484 verifier(m);
488 DCHECK(element->size() <= INT_MAX);
489 BOOL ok = WriteFile(pipe_.Get(),
490 element->data(),
491 static_cast<uint32_t>(element->size()),
492 NULL,
493 &output_state_.context.overlapped);
494 if (!ok) {
495 DWORD write_error = GetLastError();
496 if (write_error == ERROR_IO_PENDING) {
497 output_state_.is_pending = true;
499 const Message* m = element->get_message();
500 if (m) {
501 DVLOG(2) << "sent pending message @" << m << " on channel @" << this
502 << " with type " << m->type();
505 return true;
507 LOG(ERROR) << "pipe error: " << write_error;
508 return false;
511 const Message* m = element->get_message();
512 if (m) {
513 DVLOG(2) << "sent message @" << m << " on channel @" << this
514 << " with type " << m->type();
517 output_state_.is_pending = true;
518 return true;
521 void ChannelWin::OnIOCompleted(
522 base::MessageLoopForIO::IOContext* context,
523 DWORD bytes_transfered,
524 DWORD error) {
525 bool ok = true;
526 DCHECK(thread_check_->CalledOnValidThread());
527 if (context == &input_state_.context) {
528 if (waiting_connect_) {
529 if (!ProcessConnection())
530 return;
531 // We may have some messages queued up to send...
532 if (!output_queue_.empty() && !output_state_.is_pending)
533 ProcessOutgoingMessages(NULL, 0);
534 if (input_state_.is_pending)
535 return;
536 // else, fall-through and look for incoming messages...
539 // We don't support recursion through OnMessageReceived yet!
540 DCHECK(!processing_incoming_);
541 base::AutoReset<bool> auto_reset_processing_incoming(
542 &processing_incoming_, true);
544 // Process the new data.
545 if (input_state_.is_pending) {
546 // This is the normal case for everything except the initialization step.
547 input_state_.is_pending = false;
548 if (!bytes_transfered) {
549 ok = false;
550 } else if (pipe_.IsValid()) {
551 ok = (AsyncReadComplete(bytes_transfered) != DISPATCH_ERROR);
553 } else {
554 DCHECK(!bytes_transfered);
557 // Request more data.
558 if (ok)
559 ok = (ProcessIncomingMessages() != DISPATCH_ERROR);
560 } else {
561 DCHECK(context == &output_state_.context);
562 CHECK(output_state_.is_pending);
563 ok = ProcessOutgoingMessages(context, bytes_transfered);
565 if (!ok && pipe_.IsValid()) {
566 // We don't want to re-enter Close().
567 Close();
568 listener()->OnChannelError();
572 //------------------------------------------------------------------------------
573 // Channel's methods
575 // static
576 scoped_ptr<Channel> Channel::Create(const IPC::ChannelHandle& channel_handle,
577 Mode mode,
578 Listener* listener,
579 AttachmentBroker* broker) {
580 return scoped_ptr<Channel>(
581 new ChannelWin(channel_handle, mode, listener));
584 // static
585 bool Channel::IsNamedServerInitialized(const std::string& channel_id) {
586 return ChannelWin::IsNamedServerInitialized(channel_id);
589 // static
590 std::string Channel::GenerateVerifiedChannelID(const std::string& prefix) {
591 // Windows pipes can be enumerated by low-privileged processes. So, we
592 // append a strong random value after the \ character. This value is not
593 // included in the pipe name, but sent as part of the client hello, to
594 // hijacking the pipe name to spoof the client.
596 std::string id = prefix;
597 if (!id.empty())
598 id.append(".");
600 int secret;
601 do { // Guarantee we get a non-zero value.
602 secret = base::RandInt(0, std::numeric_limits<int>::max());
603 } while (secret == 0);
605 id.append(GenerateUniqueRandomChannelID());
606 return id.append(base::StringPrintf("\\%d", secret));
609 } // namespace IPC