1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 7 #ifndef CHROME_COMMON_IPC_CHANNEL_H_ 8 #define CHROME_COMMON_IPC_CHANNEL_H_ 9 10 #include <cstdint> 11 #include <queue> 12 #include "base/basictypes.h" 13 #include "build/build_config.h" 14 #include "mozilla/UniquePtr.h" 15 #include "mozilla/UniquePtrExtensions.h" 16 #include "mozilla/WeakPtr.h" 17 #include "chrome/common/ipc_message.h" 18 19 #ifdef OS_WIN 20 # include <string> 21 #endif 22 23 namespace IPC { 24 25 class Message; 26 class MessageReader; 27 class MessageWriter; 28 29 //------------------------------------------------------------------------------ 30 31 class Channel { 32 // Security tests need access to the pipe handle. 33 friend class ChannelTest; 34 35 public: 36 // Windows channels use named objects and connect to them by name, 37 // but on Unix we use unnamed socketpairs and pass capabilities 38 // directly using SCM_RIGHTS messages. This type abstracts away 39 // that difference. 40 #ifdef OS_WIN 41 typedef std::wstring ChannelId; 42 #else 43 struct ChannelId {}; 44 #endif 45 46 // For channels which are created after initialization, handles to the pipe 47 // endpoints may be passed around directly using IPC messages. 48 using ChannelHandle = mozilla::UniqueFileHandle; 49 50 // Implemented by consumers of a Channel to receive messages. 51 // 52 // All listeners will only be called on the IO thread, and must be destroyed 53 // on the IO thread. 54 class Listener : public mozilla::SupportsWeakPtr { 55 public: 56 virtual ~Listener() = default; 57 58 // Called when a message is received. 59 virtual void OnMessageReceived(Message&& message) = 0; 60 61 // Called when the channel is connected and we have received the internal 62 // Hello message from the peer. OnChannelConnected(int32_t peer_pid)63 virtual void OnChannelConnected(int32_t peer_pid) {} 64 65 // Called when an error is detected that causes the channel to close. 66 // This method is not called when a channel is closed normally. OnChannelError()67 virtual void OnChannelError() {} 68 69 // If the listener has queued messages, swap them for |queue| like so 70 // swap(impl->my_queued_messages, queue); GetQueuedMessages(std::queue<Message> & queue)71 virtual void GetQueuedMessages(std::queue<Message>& queue) {} 72 }; 73 74 enum Mode { MODE_SERVER, MODE_CLIENT }; 75 76 enum { 77 78 // The maximum message size in bytes. Attempting to receive a 79 // message of this size or bigger results in a channel error. 80 // This is larger in fuzzing builds to allow the fuzzing of passing 81 // large data structures into DOM methods without crashing. 82 #ifndef FUZZING 83 kMaximumMessageSize = 256 * 1024 * 1024, 84 #else 85 kMaximumMessageSize = 1792 * 1024 * 1024, // 1.75GB 86 #endif 87 88 // Amount of data to read at once from the pipe. 89 kReadBufferSize = 4 * 1024, 90 91 // Maximum size of a message that we allow to be copied (rather than moved). 92 kMaxCopySize = 32 * 1024, 93 }; 94 95 // Initialize a Channel. 96 // 97 // |channel_id| identifies the communication Channel. 98 // |mode| specifies whether this Channel is to operate in server mode or 99 // client mode. In server mode, the Channel is responsible for setting up the 100 // IPC object, whereas in client mode, the Channel merely connects to the 101 // already established IPC object. 102 // |listener| receives a callback on the current thread for each newly 103 // received message. 104 // 105 Channel(const ChannelId& channel_id, Mode mode, Listener* listener); 106 107 // Initialize a pre-created channel |pipe| as |mode|. 108 Channel(ChannelHandle pipe, Mode mode, Listener* listener); 109 110 ~Channel(); 111 112 // Connect the pipe. On the server side, this will initiate 113 // waiting for connections. On the client, it attempts to 114 // connect to a pre-existing pipe. Note, calling Connect() 115 // will not block the calling thread and may complete 116 // asynchronously. 117 bool Connect(); 118 119 // Close this Channel explicitly. May be called multiple times. 120 void Close(); 121 122 // Modify the Channel's listener. 123 Listener* set_listener(Listener* listener); 124 125 // Send a message over the Channel to the listener on the other end. 126 // 127 // |message| must be allocated using operator new. This object will be 128 // deleted once the contents of the Message have been sent. 129 // 130 // If you Send() a message on a Close()'d channel, we delete the message 131 // immediately. 132 bool Send(mozilla::UniquePtr<Message> message); 133 134 // The PID which this channel has been opened with. This will be 135 // `-1` until `OnChannelConnected` has been called. 136 int32_t OtherPid() const; 137 138 // IsClosed() is safe to call from any thread, but the value returned may 139 // be out of date, because we don't use any synchronization when reading 140 // or writing it. 141 bool IsClosed() const; 142 143 #if defined(OS_POSIX) 144 // On POSIX an IPC::Channel wraps a socketpair(), this method returns the 145 // FD # for the client end of the socket and the equivalent FD# to use for 146 // mapping it into the Child process. 147 // This method may only be called on the server side of a channel. 148 // 149 // If the kTestingChannelID flag is specified on the command line then 150 // a named FIFO is used as the channel transport mechanism rather than a 151 // socketpair() in which case this method returns -1 for both parameters. 152 void GetClientFileDescriptorMapping(int* src_fd, int* dest_fd) const; 153 154 // Return the file descriptor for communication with the peer. 155 int GetFileDescriptor() const; 156 157 // Close the client side of the socketpair. 158 void CloseClientFileDescriptor(); 159 160 # if defined(OS_MACOSX) 161 // Configure the mach task_t for the peer task. 162 void SetOtherMachTask(task_t task); 163 164 // Tell this pipe to accept mach ports. Exactly one side of the IPC connection 165 // must be set as `MODE_SERVER` and that side will be responsible for 166 // transferring the rights between processes. 167 void StartAcceptingMachPorts(Mode mode); 168 # endif 169 170 #elif defined(OS_WIN) 171 // Tell this pipe to accept handles. Exactly one side of the IPC connection 172 // must be set as `MODE_SERVER`, and that side will be responsible for calling 173 // `DuplicateHandle` to transfer the handle between processes. 174 void StartAcceptingHandles(Mode mode); 175 #endif // defined(OS_POSIX) 176 177 // On Windows: Generates a channel ID that, if passed to the client 178 // as a shared secret, will validate the client's authenticity. 179 // Other platforms don't use channel IDs, so this returns the dummy 180 // ChannelId value. 181 static ChannelId GenerateVerifiedChannelID(); 182 183 // On Windows: Retrieves the initial channel ID passed to the 184 // current process by its parent. Other platforms don't do this; 185 // the dummy ChannelId value is returned instead. 186 static ChannelId ChannelIDForCurrentProcess(); 187 188 #if defined(MOZ_WIDGET_ANDROID) 189 // Used to set the first IPC file descriptor in the child process on Android. 190 // See ipc_channel_posix.cc for further details on how this is used. 191 static void SetClientChannelFd(int fd); 192 #endif // defined(MOZ_WIDGET_ANDROID) 193 194 // Create a new pair of pipe endpoints which can be used to establish a 195 // native IPC::Channel connection. 196 static bool CreateRawPipe(ChannelHandle* server, ChannelHandle* client); 197 198 private: 199 // PIMPL to which all channel calls are delegated. 200 class ChannelImpl; 201 ChannelImpl* channel_impl_; 202 203 enum { 204 #if defined(OS_MACOSX) 205 // If the channel receives a message that contains file descriptors, then 206 // it will reply back with this message, indicating that the message has 207 // been received. The sending channel can then close any descriptors that 208 // had been marked as auto_close. This works around a sendmsg() bug on BSD 209 // where the kernel can eagerly close file descriptors that are in message 210 // queues but not yet delivered. 211 RECEIVED_FDS_MESSAGE_TYPE = kuint16max - 1, 212 #endif 213 214 // The Hello message is internal to the Channel class. It is sent 215 // by the peer when the channel is connected. The message contains 216 // just the process id (pid). The message has a special routing_id 217 // (MSG_ROUTING_NONE) and type (HELLO_MESSAGE_TYPE). 218 HELLO_MESSAGE_TYPE = kuint16max // Maximum value of message type 219 // (uint16_t), to avoid conflicting with 220 // normal message types, which are 221 // enumeration constants starting from 0. 222 }; 223 }; 224 225 } // namespace IPC 226 227 #endif // CHROME_COMMON_IPC_CHANNEL_H_ 228