michael@0: // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #ifndef CHROME_COMMON_IPC_CHANNEL_H_ michael@0: #define CHROME_COMMON_IPC_CHANNEL_H_ michael@0: michael@0: #include michael@0: #include "chrome/common/ipc_message.h" michael@0: michael@0: namespace IPC { michael@0: michael@0: //------------------------------------------------------------------------------ michael@0: michael@0: class Channel : public Message::Sender { michael@0: // Security tests need access to the pipe handle. michael@0: friend class ChannelTest; michael@0: michael@0: public: michael@0: // Implemented by consumers of a Channel to receive messages. michael@0: class Listener { michael@0: public: michael@0: virtual ~Listener() {} michael@0: michael@0: // Called when a message is received. michael@0: virtual void OnMessageReceived(const Message& message) = 0; michael@0: michael@0: // Called when the channel is connected and we have received the internal michael@0: // Hello message from the peer. michael@0: virtual void OnChannelConnected(int32_t peer_pid) {} michael@0: michael@0: // Called when an error is detected that causes the channel to close. michael@0: // This method is not called when a channel is closed normally. michael@0: virtual void OnChannelError() {} michael@0: michael@0: // If the listener has queued messages, swap them for |queue| like so michael@0: // swap(impl->my_queued_messages, queue); michael@0: virtual void GetQueuedMessages(std::queue& queue) {} michael@0: }; michael@0: michael@0: enum Mode { michael@0: MODE_SERVER, michael@0: MODE_CLIENT michael@0: }; michael@0: michael@0: enum { michael@0: // The maximum message size in bytes. Attempting to receive a michael@0: // message of this size or bigger results in a channel error. michael@0: kMaximumMessageSize = 256 * 1024 * 1024, michael@0: michael@0: // Ammount of data to read at once from the pipe. michael@0: kReadBufferSize = 4 * 1024 michael@0: }; michael@0: michael@0: // Initialize a Channel. michael@0: // michael@0: // |channel_id| identifies the communication Channel. michael@0: // |mode| specifies whether this Channel is to operate in server mode or michael@0: // client mode. In server mode, the Channel is responsible for setting up the michael@0: // IPC object, whereas in client mode, the Channel merely connects to the michael@0: // already established IPC object. michael@0: // |listener| receives a callback on the current thread for each newly michael@0: // received message. michael@0: // michael@0: Channel(const std::wstring& channel_id, Mode mode, Listener* listener); michael@0: michael@0: // XXX it would nice not to have yet more platform-specific code in michael@0: // here but it's just not worth the trouble. michael@0: # if defined(OS_POSIX) michael@0: // Connect to a pre-created channel |fd| as |mode|. michael@0: Channel(int fd, Mode mode, Listener* listener); michael@0: # elif defined(OS_WIN) michael@0: // Connect to a pre-created channel as |mode|. Clients connect to michael@0: // the pre-existing server pipe, and servers take over |server_pipe|. michael@0: Channel(const std::wstring& channel_id, void* server_pipe, michael@0: Mode mode, Listener* listener); michael@0: # endif michael@0: michael@0: ~Channel(); michael@0: michael@0: // Connect the pipe. On the server side, this will initiate michael@0: // waiting for connections. On the client, it attempts to michael@0: // connect to a pre-existing pipe. Note, calling Connect() michael@0: // will not block the calling thread and may complete michael@0: // asynchronously. michael@0: bool Connect(); michael@0: michael@0: // Close this Channel explicitly. May be called multiple times. michael@0: void Close(); michael@0: michael@0: // Modify the Channel's listener. michael@0: Listener* set_listener(Listener* listener); michael@0: michael@0: // Send a message over the Channel to the listener on the other end. michael@0: // michael@0: // |message| must be allocated using operator new. This object will be michael@0: // deleted once the contents of the Message have been sent. michael@0: // michael@0: // If you Send() a message on a Close()'d channel, we delete the message michael@0: // immediately. michael@0: virtual bool Send(Message* message); michael@0: michael@0: // Unsound_IsClosed() and Unsound_NumQueuedMessages() are safe to call from michael@0: // any thread, but the value returned may be out of date, because we don't michael@0: // use any synchronization when reading or writing it. michael@0: bool Unsound_IsClosed() const; michael@0: uint32_t Unsound_NumQueuedMessages() const; michael@0: michael@0: #if defined(OS_POSIX) michael@0: // On POSIX an IPC::Channel wraps a socketpair(), this method returns the michael@0: // FD # for the client end of the socket and the equivalent FD# to use for michael@0: // mapping it into the Child process. michael@0: // This method may only be called on the server side of a channel. michael@0: // michael@0: // If the kTestingChannelID flag is specified on the command line then michael@0: // a named FIFO is used as the channel transport mechanism rather than a michael@0: // socketpair() in which case this method returns -1 for both parameters. michael@0: void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const; michael@0: michael@0: // Return the file descriptor for communication with the peer. michael@0: int GetFileDescriptor() const; michael@0: michael@0: // Reset the file descriptor for communication with the peer. michael@0: void ResetFileDescriptor(int fd); michael@0: michael@0: // Close the client side of the socketpair. michael@0: void CloseClientFileDescriptor(); michael@0: michael@0: #elif defined(OS_WIN) michael@0: // Return the server pipe handle. michael@0: void* GetServerPipeHandle() const; michael@0: #endif // defined(OS_POSIX) michael@0: michael@0: private: michael@0: // PIMPL to which all channel calls are delegated. michael@0: class ChannelImpl; michael@0: ChannelImpl *channel_impl_; michael@0: michael@0: enum { michael@0: #if defined(OS_MACOSX) michael@0: // If the channel receives a message that contains file descriptors, then michael@0: // it will reply back with this message, indicating that the message has michael@0: // been received. The sending channel can then close any descriptors that michael@0: // had been marked as auto_close. This works around a sendmsg() bug on BSD michael@0: // where the kernel can eagerly close file descriptors that are in message michael@0: // queues but not yet delivered. michael@0: RECEIVED_FDS_MESSAGE_TYPE = kuint16max - 1, michael@0: #endif michael@0: michael@0: // The Hello message is internal to the Channel class. It is sent michael@0: // by the peer when the channel is connected. The message contains michael@0: // just the process id (pid). The message has a special routing_id michael@0: // (MSG_ROUTING_NONE) and type (HELLO_MESSAGE_TYPE). michael@0: HELLO_MESSAGE_TYPE = kuint16max // Maximum value of message type (uint16_t), michael@0: // to avoid conflicting with normal michael@0: // message types, which are enumeration michael@0: // constants starting from 0. michael@0: }; michael@0: }; michael@0: michael@0: } // namespace IPC michael@0: michael@0: #endif // CHROME_COMMON_IPC_CHANNEL_H_