| // Copyright 2008, Google Inc. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #ifndef CHROME_COMMON_IPC_CHANNEL_H__ |
| #define CHROME_COMMON_IPC_CHANNEL_H__ |
| |
| #include <queue> |
| |
| #include "base/message_loop.h" |
| #include "chrome/common/ipc_message.h" |
| |
| namespace IPC { |
| |
| //------------------------------------------------------------------------------ |
| |
| class Channel : public MessageLoop::Watcher, |
| public Message::Sender { |
| // Security tests need access to the pipe handle. |
| friend class ChannelTest; |
| |
| public: |
| // Implemented by consumers of a Channel to receive messages. |
| class Listener { |
| public: |
| // Called when a message is received. |
| virtual void OnMessageReceived(const Message& message) = 0; |
| |
| // Called when the channel is connected and we have received the internal |
| // Hello message from the peer. |
| virtual void OnChannelConnected(int32 peer_pid) {} |
| |
| // Called when an error is detected that causes the channel to close. |
| // This method is not called when a channel is closed normally. |
| virtual void OnChannelError() {} |
| }; |
| |
| enum Mode { |
| MODE_SERVER, |
| MODE_CLIENT |
| }; |
| |
| // The maximum message size in bytes. Attempting to receive a |
| // message of this size or bigger results in a channel error. |
| enum { |
| kMaximumMessageSize = 256 * 1024 * 1024 |
| }; |
| |
| // Initialize a Channel. |
| // |
| // @param channel_id |
| // Identifies the communication Channel. |
| // @param mode |
| // Specifies whether this Channel is to operate in server mode or client |
| // mode. In server mode, the Channel is responsible for setting up the |
| // IPC object, whereas in client mode, the Channel merely connects |
| // to the already established IPC object. |
| // @param listener |
| // Receives a callback on the current thread for each newly received |
| // message. |
| // |
| Channel(const std::wstring& channel_id, Mode mode, Listener* listener); |
| |
| ~Channel() { Close(); } |
| |
| // Connect the pipe. On the server side, this will initiate |
| // waiting for connections. On the client, it attempts to |
| // connect to a pre-existing pipe. Note, calling Connect() |
| // will not block the calling thread and may complete |
| // asynchronously. |
| bool Connect(); |
| |
| // Close this Channel explicitly. May be called multiple times. |
| void Close(); |
| |
| // Modify the Channel's listener. |
| void set_listener(Listener* listener) { listener_ = listener; } |
| |
| // Send a message over the Channel to the listener on the other end. |
| // |
| // @param message |
| // The Message to send, which must be allocated using operator new. This |
| // object will be deleted once the contents of the Message have been sent. |
| // |
| // FIXME bug 551500: the channel does not notice failures, so if the |
| // renderer crashes, it will silently succeed, leaking the parameter. |
| // At least the leak will be fixed by... |
| // |
| virtual bool Send(Message* message); |
| |
| // Process any pending incoming and outgoing messages. Wait for at most |
| // max_wait_msec for pending messages if there are none. Returns true if |
| // there were no pending messages or if pending messages were successfully |
| // processed. Returns false if there are pending messages that cannot be |
| // processed for some reason (e.g., because ProcessIncomingMessages would be |
| // re-entered). |
| // TODO(darin): Need a better way of dealing with the recursion problem. |
| bool ProcessPendingMessages(DWORD max_wait_msec); |
| |
| private: |
| const std::wstring PipeName(const std::wstring& channel_id) const; |
| bool CreatePipe(const std::wstring& channel_id, Mode mode); |
| bool ProcessConnection(); |
| bool ProcessIncomingMessages(); |
| bool ProcessOutgoingMessages(); |
| |
| // MessageLoop::Watcher implementation |
| virtual void OnObjectSignaled(HANDLE object); |
| |
| private: |
| enum { |
| BUF_SIZE = 4096 |
| }; |
| |
| struct State { |
| State(); |
| ~State(); |
| OVERLAPPED overlapped; |
| bool is_pending; |
| }; |
| |
| State input_state_; |
| State output_state_; |
| |
| HANDLE pipe_; |
| Listener* listener_; |
| |
| // Messages to be sent are queued here. |
| std::queue<Message*> output_queue_; |
| |
| // We read from the pipe into this buffer |
| char input_buf_[BUF_SIZE]; |
| |
| // Large messages that span multiple pipe buffers, get built-up using |
| // this buffer. |
| std::string input_overflow_buf_; |
| |
| // In server-mode, we have to wait for the client to connect before we |
| // can begin reading. We make use of the input_state_ when performing |
| // the connect operation in overlapped mode. |
| bool waiting_connect_; |
| |
| // 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_; |
| |
| // The Hello message is internal to the Channel class. It is sent |
| // by the peer when the channel is connected. The message contains |
| // just the process id (pid). The message has a special routing_id |
| // (MSG_ROUTING_NONE) and type (HELLO_MESSAGE_TYPE). |
| enum { |
| HELLO_MESSAGE_TYPE = MAXWORD // Maximum value of message type (WORD), |
| // to avoid conflicting with normal |
| // message types, which are enumeration |
| // constants starting from 0. |
| }; |
| }; |
| |
| } |
| |
| #endif // CHROME_COMMON_IPC_CHANNEL_H__ |