// 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 IPC_IPC_CHANNEL_POSIX_H_ #define IPC_IPC_CHANNEL_POSIX_H_ #pragma once #include "ipc/ipc_channel.h" #include // for CMSG macros #include #include #include #include "base/message_loop.h" #include "ipc/file_descriptor_set_posix.h" #if !defined(OS_MACOSX) // On Linux, the seccomp sandbox makes it very expensive to call // recvmsg() and sendmsg(). The restriction on calling read() and write(), which // are cheap, is that we can't pass file descriptors over them. // // As we cannot anticipate when the sender will provide us with file // descriptors, we have to make the decision about whether we call read() or // recvmsg() before we actually make the call. The easiest option is to // create a dedicated socketpair() for exchanging file descriptors. // Mac can also run in IPC_USES_READWRITE mode if necessary, but at this time // doesn't take a performance hit from recvmsg and sendmsg, so it doesn't // make sense to waste resources on having the separate dedicated socketpair. // It is however useful for debugging between Linux and Mac to be able to turn // this switch 'on' on the Mac as well. // The HELLO message from the client to the server is always sent using // sendmsg because it will contain the file descriptor that the server // needs to send file descriptors in later messages. #define IPC_USES_READWRITE 1 #endif namespace IPC { class Channel::ChannelImpl : public MessageLoopForIO::Watcher { public: // Mirror methods of Channel, see ipc_channel.h for description. ChannelImpl(const IPC::ChannelHandle& channel_handle, Mode mode, Listener* listener); ~ChannelImpl(); bool Connect(); void Close(); void set_listener(Listener* listener) { listener_ = listener; } bool Send(Message* message); int GetClientFileDescriptor() const; bool AcceptsConnections() const; bool HasAcceptedConnection() const; void ResetToAcceptingConnectionState(); private: bool CreatePipe(const IPC::ChannelHandle& channel_handle); bool ProcessIncomingMessages(); bool ProcessOutgoingMessages(); bool AcceptConnection(); void ClosePipeOnError(); void QueueHelloMessage(); bool IsHelloMessage(const Message* m) const; // MessageLoopForIO::Watcher implementation. virtual void OnFileCanReadWithoutBlocking(int fd); virtual void OnFileCanWriteWithoutBlocking(int fd); Mode mode_; // After accepting one client connection on our server socket we want to // stop listening. MessageLoopForIO::FileDescriptorWatcher server_listen_connection_watcher_; MessageLoopForIO::FileDescriptorWatcher read_watcher_; MessageLoopForIO::FileDescriptorWatcher write_watcher_; // Indicates whether we're currently blocked waiting for a write to complete. bool is_blocked_on_write_; bool waiting_connect_; // If sending a message blocks then we use this variable // to keep track of where we are. size_t message_send_bytes_written_; // File descriptor we're listening on for new connections if we listen // for connections. int server_listen_pipe_; // The pipe used for communication. int pipe_; // For a server, the client end of our socketpair() -- the other end of our // pipe_ that is passed to the client. int client_pipe_; #if defined(IPC_USES_READWRITE) // Linux/BSD use a dedicated socketpair() for passing file descriptors. int fd_pipe_; int remote_fd_pipe_; #endif // The "name" of our pipe. On Windows this is the global identifier for // the pipe. On POSIX it's used as a key in a local map of file descriptors. std::string pipe_name_; Listener* listener_; // Messages to be sent are queued here. std::queue output_queue_; // We read from the pipe into this buffer char input_buf_[Channel::kReadBufferSize]; enum { // We assume a worst case: kReadBufferSize bytes of messages, where each // message has no payload and a full complement of descriptors. MAX_READ_FDS = (Channel::kReadBufferSize / sizeof(IPC::Message::Header)) * FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE, }; // This is a control message buffer large enough to hold kMaxReadFDs #if defined(OS_MACOSX) // TODO(agl): OSX appears to have non-constant CMSG macros! char input_cmsg_buf_[1024]; #else char input_cmsg_buf_[CMSG_SPACE(sizeof(int) * MAX_READ_FDS)]; #endif // Large messages that span multiple pipe buffers, get built-up using // this buffer. std::string input_overflow_buf_; std::vector input_overflow_fds_; // True if we are responsible for unlinking the unix domain socket file. bool must_unlink_; ScopedRunnableMethodFactory factory_; DISALLOW_IMPLICIT_CONSTRUCTORS(ChannelImpl); }; // The maximum length of the name of a pipe for MODE_NAMED_SERVER or // MODE_NAMED_CLIENT if you want to pass in your own socket. // The standard size on linux is 108, mac is 104. To maintain consistency // across platforms we standardize on the smaller value. static const size_t kMaxPipeNameLength = 104; } // namespace IPC #endif // IPC_IPC_CHANNEL_POSIX_H_