/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ // Copyright (c) 2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_COMMON_IPC_CHANNEL_WIN_H_ #define CHROME_COMMON_IPC_CHANNEL_WIN_H_ #include "chrome/common/ipc_channel.h" #include "chrome/common/ipc_channel_capability.h" #include "chrome/common/ipc_message.h" #include #include #include "base/message_loop.h" #include "base/task.h" #include "nsISupportsImpl.h" #include "mozilla/EventTargetCapability.h" #include "mozilla/Maybe.h" #include "mozilla/Mutex.h" #include "mozilla/Queue.h" #include "mozilla/UniquePtr.h" namespace IPC { class Channel::ChannelImpl : public MessageLoopForIO::IOHandler { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_EVENT_TARGET( ChannelImpl, IOThread().GetEventTarget()); using ChannelId = Channel::ChannelId; using ChannelHandle = Channel::ChannelHandle; // Mirror methods of Channel, see ipc_channel.h for description. ChannelImpl(const ChannelId& channel_id, Mode mode, Listener* listener); ChannelImpl(ChannelHandle pipe, Mode mode, Listener* listener); bool Connect() MOZ_EXCLUDES(SendMutex()); void Close() MOZ_EXCLUDES(SendMutex()); void StartAcceptingHandles(Mode mode) MOZ_EXCLUDES(SendMutex()); Listener* set_listener(Listener* listener) { IOThread().AssertOnCurrentThread(); chan_cap_.NoteOnIOThread(); Listener* old = listener_; listener_ = listener; return old; } // NOTE: `Send` may be called on threads other than the I/O thread. bool Send(mozilla::UniquePtr message) MOZ_EXCLUDES(SendMutex()); int32_t OtherPid() { IOThread().AssertOnCurrentThread(); chan_cap_.NoteOnIOThread(); return other_pid_; } // See the comment in ipc_channel.h for info on IsClosed() // NOTE: `IsClosed` may be called on threads other than the I/O thread. bool IsClosed() MOZ_EXCLUDES(SendMutex()) { mozilla::MutexAutoLock lock(SendMutex()); chan_cap_.NoteSendMutex(); return pipe_ == INVALID_HANDLE_VALUE; } private: ~ChannelImpl() { IOThread().AssertOnCurrentThread(); if (pipe_ != INVALID_HANDLE_VALUE || other_process_ != INVALID_HANDLE_VALUE) { Close(); } } void Init(Mode mode, Listener* listener) MOZ_REQUIRES(SendMutex(), IOThread()); void OutputQueuePush(mozilla::UniquePtr msg) MOZ_REQUIRES(SendMutex()); void OutputQueuePop() MOZ_REQUIRES(SendMutex()); const ChannelId PipeName(const ChannelId& channel_id, int32_t* secret) const; bool CreatePipe(const ChannelId& channel_id, Mode mode) MOZ_REQUIRES(SendMutex(), IOThread()); void SetOtherPid(int other_pid) MOZ_REQUIRES(IOThread()) MOZ_EXCLUDES(SendMutex()); bool EnqueueHelloMessage() MOZ_REQUIRES(SendMutex(), IOThread()); void CloseLocked() MOZ_REQUIRES(SendMutex(), IOThread()); bool ProcessConnection() MOZ_REQUIRES(SendMutex(), IOThread()); bool ProcessIncomingMessages(MessageLoopForIO::IOContext* context, DWORD bytes_read, bool was_pending) MOZ_REQUIRES(IOThread()); bool ProcessOutgoingMessages(MessageLoopForIO::IOContext* context, DWORD bytes_written, bool was_pending) MOZ_REQUIRES(SendMutex()); // Called on a Message immediately before it is sent/recieved to transfer // handles to the remote process, or accept handles from the remote process. bool AcceptHandles(Message& msg) MOZ_REQUIRES(IOThread()); bool TransferHandles(Message& msg) MOZ_REQUIRES(SendMutex()); // MessageLoop::IOHandler implementation. virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, DWORD bytes_transfered, DWORD error); const ChannelCapability::Thread& IOThread() const MOZ_RETURN_CAPABILITY(chan_cap_.IOThread()) { return chan_cap_.IOThread(); } ChannelCapability::Mutex& SendMutex() MOZ_RETURN_CAPABILITY(chan_cap_.SendMutex()) { return chan_cap_.SendMutex(); } private: // Compound capability of a Mutex and the IO thread. ChannelCapability chan_cap_; Mode mode_ MOZ_GUARDED_BY(IOThread()); struct State { explicit State(ChannelImpl* channel); ~State(); MessageLoopForIO::IOContext context; // When there is pending I/O, this holds a strong reference to the // ChannelImpl to prevent it from going away. RefPtr is_pending; }; State input_state_ MOZ_GUARDED_BY(IOThread()); State output_state_ MOZ_GUARDED_BY(SendMutex()); HANDLE pipe_ MOZ_GUARDED_BY(chan_cap_) = INVALID_HANDLE_VALUE; Listener* listener_ MOZ_GUARDED_BY(IOThread()) = nullptr; // Messages to be sent are queued here. mozilla::Queue, 64> output_queue_ MOZ_GUARDED_BY(SendMutex()); // If sending a message blocks then we use this iterator to keep track of // where in the message we are. It gets reset when the message is finished // sending. mozilla::Maybe partial_write_iter_ MOZ_GUARDED_BY(SendMutex()); // We read from the pipe into this buffer mozilla::UniquePtr input_buf_ MOZ_GUARDED_BY(IOThread()); size_t input_buf_offset_ MOZ_GUARDED_BY(IOThread()) = 0; // Large incoming messages that span multiple pipe buffers get built-up in the // buffers of this message. mozilla::UniquePtr incoming_message_ MOZ_GUARDED_BY(IOThread()); // Timer started when a MODE_SERVER channel begins waiting for a connection, // and cancelled when the connection completes. Will produce an error if no // connection occurs before the timeout. nsCOMPtr connect_timeout_ MOZ_GUARDED_BY(IOThread()); // Will be set to `true` until `Connect()` has been called, and, if in // server-mode, the client has connected. The `input_state_` is used to wait // for the client to connect in overlapped mode. bool waiting_connect_ MOZ_GUARDED_BY(chan_cap_) = true; // This flag is set when processing incoming messages. It is used to // avoid recursing through ProcessIncomingMessages, which could cause // problems. TODO(darin): make this unnecessary bool processing_incoming_ MOZ_GUARDED_BY(IOThread()) = false; // We keep track of the PID of the other side of this channel so that we can // record this when generating logs of IPC messages. int32_t other_pid_ MOZ_GUARDED_BY(chan_cap_) = -1; // This is a unique per-channel value used to authenticate the client end of // a connection. If the value is non-zero, the client passes it in the hello // and the host validates. (We don't send the zero value to preserve IPC // compatibility with existing clients that don't validate the channel.) int32_t shared_secret_ MOZ_GUARDED_BY(IOThread()) = 0; // In server-mode, we wait for the channel at the other side of the pipe to // send us back our shared secret, if we are using one. bool waiting_for_shared_secret_ MOZ_GUARDED_BY(IOThread()) = false; // Whether or not to accept handles from a remote process, and whether this // process is the privileged side of a IPC::Channel which can transfer // handles. bool accept_handles_ MOZ_GUARDED_BY(chan_cap_) = false; bool privileged_ MOZ_GUARDED_BY(chan_cap_) = false; // A privileged process handle used to transfer HANDLEs to and from the remote // process. This will only be used if `privileged_` is set. HANDLE other_process_ MOZ_GUARDED_BY(chan_cap_) = INVALID_HANDLE_VALUE; DISALLOW_COPY_AND_ASSIGN(ChannelImpl); }; } // namespace IPC #endif // CHROME_COMMON_IPC_CHANNEL_WIN_H_