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