michael@0: // Copyright (c) 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_POSIX_H_ michael@0: #define CHROME_COMMON_IPC_CHANNEL_POSIX_H_ michael@0: michael@0: #include "chrome/common/ipc_channel.h" michael@0: michael@0: #include // for CMSG macros michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "base/message_loop.h" michael@0: #include "chrome/common/file_descriptor_set_posix.h" michael@0: michael@0: namespace IPC { michael@0: michael@0: // An implementation of ChannelImpl for POSIX systems that works via michael@0: // socketpairs. See the .cc file for an overview of the implementation. michael@0: class Channel::ChannelImpl : public MessageLoopForIO::Watcher { michael@0: public: michael@0: // Mirror methods of Channel, see ipc_channel.h for description. michael@0: ChannelImpl(const std::wstring& channel_id, Mode mode, Listener* listener); michael@0: ChannelImpl(int fd, Mode mode, Listener* listener); michael@0: ~ChannelImpl() { Close(); } michael@0: bool Connect(); michael@0: void Close(); michael@0: Listener* set_listener(Listener* listener) { michael@0: Listener* old = listener_; michael@0: listener_ = listener; michael@0: return old; michael@0: } michael@0: bool Send(Message* message); michael@0: void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const; michael@0: michael@0: void ResetFileDescriptor(int fd); michael@0: michael@0: int GetFileDescriptor() const { michael@0: return pipe_; michael@0: } michael@0: void CloseClientFileDescriptor(); michael@0: michael@0: // See the comment in ipc_channel.h for info on Unsound_IsClosed() and michael@0: // Unsound_NumQueuedMessages(). michael@0: bool Unsound_IsClosed() const; michael@0: uint32_t Unsound_NumQueuedMessages() const; michael@0: michael@0: private: michael@0: void Init(Mode mode, Listener* listener); michael@0: bool CreatePipe(const std::wstring& channel_id, Mode mode); michael@0: bool EnqueueHelloMessage(); michael@0: michael@0: bool ProcessIncomingMessages(); michael@0: bool ProcessOutgoingMessages(); michael@0: michael@0: // MessageLoopForIO::Watcher implementation. michael@0: virtual void OnFileCanReadWithoutBlocking(int fd); michael@0: virtual void OnFileCanWriteWithoutBlocking(int fd); michael@0: michael@0: #if defined(OS_MACOSX) michael@0: void CloseDescriptors(uint32_t pending_fd_id); michael@0: #endif michael@0: michael@0: void OutputQueuePush(Message* msg); michael@0: void OutputQueuePop(); michael@0: michael@0: Mode mode_; michael@0: michael@0: // After accepting one client connection on our server socket we want to michael@0: // stop listening. michael@0: MessageLoopForIO::FileDescriptorWatcher server_listen_connection_watcher_; michael@0: MessageLoopForIO::FileDescriptorWatcher read_watcher_; michael@0: MessageLoopForIO::FileDescriptorWatcher write_watcher_; michael@0: michael@0: // Indicates whether we're currently blocked waiting for a write to complete. michael@0: bool is_blocked_on_write_; michael@0: michael@0: // If sending a message blocks then we use this variable michael@0: // to keep track of where we are. michael@0: size_t message_send_bytes_written_; michael@0: michael@0: // If the kTestingChannelID flag is specified, we use a FIFO instead of michael@0: // a socketpair(). michael@0: bool uses_fifo_; michael@0: michael@0: int server_listen_pipe_; michael@0: int pipe_; michael@0: int client_pipe_; // The client end of our socketpair(). michael@0: michael@0: // The "name" of our pipe. On Windows this is the global identifier for michael@0: // the pipe. On POSIX it's used as a key in a local map of file descriptors. michael@0: std::string pipe_name_; michael@0: michael@0: Listener* listener_; michael@0: michael@0: // Messages to be sent are queued here. michael@0: std::queue output_queue_; michael@0: michael@0: // We read from the pipe into this buffer michael@0: char input_buf_[Channel::kReadBufferSize]; michael@0: michael@0: enum { michael@0: // We assume a worst case: kReadBufferSize bytes of messages, where each michael@0: // message has no payload and a full complement of descriptors. michael@0: MAX_READ_FDS = (Channel::kReadBufferSize / sizeof(IPC::Message::Header)) * michael@0: FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE michael@0: }; michael@0: michael@0: // This is a control message buffer large enough to hold kMaxReadFDs michael@0: #if defined(OS_MACOSX) || defined(OS_NETBSD) michael@0: // TODO(agl): OSX appears to have non-constant CMSG macros! michael@0: char input_cmsg_buf_[1024]; michael@0: #else michael@0: char input_cmsg_buf_[CMSG_SPACE(sizeof(int) * MAX_READ_FDS)]; michael@0: #endif michael@0: michael@0: // Large messages that span multiple pipe buffers, get built-up using michael@0: // this buffer. michael@0: std::string input_overflow_buf_; michael@0: std::vector input_overflow_fds_; michael@0: michael@0: // In server-mode, we have to wait for the client to connect before we michael@0: // can begin reading. We make use of the input_state_ when performing michael@0: // the connect operation in overlapped mode. michael@0: bool waiting_connect_; michael@0: michael@0: // This flag is set when processing incoming messages. It is used to michael@0: // avoid recursing through ProcessIncomingMessages, which could cause michael@0: // problems. TODO(darin): make this unnecessary michael@0: bool processing_incoming_; michael@0: michael@0: // This flag is set after we've closed the channel. michael@0: bool closed_; michael@0: michael@0: #if defined(OS_MACOSX) michael@0: struct PendingDescriptors { michael@0: uint32_t id; michael@0: scoped_refptr fds; michael@0: michael@0: PendingDescriptors() : id(0) { } michael@0: PendingDescriptors(uint32_t id, FileDescriptorSet *fds) michael@0: : id(id), michael@0: fds(fds) michael@0: { } michael@0: }; michael@0: michael@0: std::list pending_fds_; michael@0: michael@0: // A generation ID for RECEIVED_FD messages. michael@0: uint32_t last_pending_fd_id_; michael@0: #endif michael@0: michael@0: // This variable is updated so it matches output_queue_.size(), except we can michael@0: // read output_queue_length_ from any thread (if we're OK getting an michael@0: // occasional out-of-date or bogus value). We use output_queue_length_ to michael@0: // implement Unsound_NumQueuedMessages. michael@0: size_t output_queue_length_; michael@0: michael@0: ScopedRunnableMethodFactory factory_; michael@0: michael@0: DISALLOW_COPY_AND_ASSIGN(ChannelImpl); michael@0: }; michael@0: michael@0: } // namespace IPC michael@0: michael@0: #endif // CHROME_COMMON_IPC_CHANNEL_POSIX_H_