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