1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef MOJO_PUBLIC_CPP_SYSTEM_INVITATION_H_
6 #define MOJO_PUBLIC_CPP_SYSTEM_INVITATION_H_
7 
8 #include <cstdint>
9 #include <string>
10 
11 #include "base/callback.h"
12 #include "base/component_export.h"
13 #include "base/macros.h"
14 #include "base/process/process_handle.h"
15 #include "base/strings/string_piece.h"
16 #include "mojo/public/c/system/invitation.h"
17 #include "mojo/public/cpp/platform/platform_channel_endpoint.h"
18 #include "mojo/public/cpp/platform/platform_channel_server_endpoint.h"
19 #include "mojo/public/cpp/system/handle.h"
20 #include "mojo/public/cpp/system/message_pipe.h"
21 #include "mojo/public/cpp/system/system_export.h"
22 
23 namespace mojo {
24 
25 // A callback which may be provided when sending an invitation to another
26 // process. In the event of any validation errors regarding messages from that
27 // process (reported via MojoNotifyBadMessage etc and related helpers), the
28 // callback will be invoked.
29 using ProcessErrorCallback = base::RepeatingCallback<void(const std::string&)>;
30 
31 // A strongly-typed representation of a |MojoHandle| for an invitation.
32 class InvitationHandle : public Handle {
33  public:
InvitationHandle()34   InvitationHandle() {}
InvitationHandle(MojoHandle value)35   explicit InvitationHandle(MojoHandle value) : Handle(value) {}
36 
37   // Copying and assignment allowed.
38 };
39 
40 static_assert(sizeof(InvitationHandle) == sizeof(Handle),
41               "Bad size for C++ InvitationHandle");
42 
43 using ScopedInvitationHandle = ScopedHandleBase<InvitationHandle>;
44 static_assert(sizeof(ScopedInvitationHandle) == sizeof(InvitationHandle),
45               "Bad size for C++ ScopedInvitationHandle");
46 
47 // An OutgoingInvitation is used to invite another process to join the calling
48 // process's IPC network.
49 //
50 // Typical use involves constructing a |PlatformChannel| and using one end to
51 // send the invitation (see |Send()| below) while passing the other to a child
52 // process.
53 //
54 // This may also be used with the server endpoint of a |NamedPlatformChannel|.
55 class MOJO_CPP_SYSTEM_EXPORT OutgoingInvitation {
56  public:
57   OutgoingInvitation();
58   OutgoingInvitation(OutgoingInvitation&& other);
59   ~OutgoingInvitation();
60 
61   OutgoingInvitation& operator=(OutgoingInvitation&& other);
62 
63   // Creates a new message pipe, attaching one end to this invitation and
64   // returning the other end to the caller. The invitee can extract the
65   // attached endpoint (see |IncomingInvitation|) thus establishing end-to-end
66   // Mojo communication.
67   //
68   // |name| is an arbitrary value that must be used by the invitee to extract
69   // the corresponding attached endpoint.
70   ScopedMessagePipeHandle AttachMessagePipe(base::StringPiece name);
71 
72   // Same as above but allows use of an integer name for convenience.
73   ScopedMessagePipeHandle AttachMessagePipe(uint64_t name);
74 
75   // Extracts an attached pipe. Note that this is not typically useful, but it
76   // is potentially necessary in cases where a caller wants to, e.g., abort
77   // launching another process and recover a pipe endpoint they had previously
78   // attached.
79   ScopedMessagePipeHandle ExtractMessagePipe(base::StringPiece name);
80 
81   // Same as above but allows use of an integer name for convenience.
82   ScopedMessagePipeHandle ExtractMessagePipe(uint64_t name);
83 
84   // Sends |invitation| to another process via |channel_endpoint|, which should
85   // correspond to the local endpoint taken from a |PlatformChannel|.
86   //
87   // |process_handle| is a handle to the destination process if known. If not
88   // provided, IPC may be limited on some platforms (namely Mac and Windows) due
89   // to an inability to transfer system handles across the boundary.
90   static void Send(OutgoingInvitation invitation,
91                    base::ProcessHandle target_process,
92                    PlatformChannelEndpoint channel_endpoint,
93                    const ProcessErrorCallback& error_callback = {});
94 
95   // Similar to above, but sends |invitation| via |server_endpoint|, which
96   // should correspond to a |PlatformChannelServerEndpoint| taken from a
97   // |NamedPlatformChannel|.
98   static void Send(OutgoingInvitation invitation,
99                    base::ProcessHandle target_process,
100                    PlatformChannelServerEndpoint server_endpoint,
101                    const ProcessErrorCallback& error_callback = {});
102 
103   // Similar to |Send()|, but targets a process which will accept the invitation
104   // with |IncomingInvitation::AcceptAsync()| instead of |Accept()|.
105   static void SendAsync(OutgoingInvitation invitation,
106                         base::ProcessHandle target_process,
107                         PlatformChannelEndpoint channel_endpoint,
108                         const ProcessErrorCallback& error_callback = {});
109 
110   // Sends an isolated invitation over |endpoint|. The process at the other
111   // endpoint must use |IncomingInvitation::AcceptIsolated()| to accept the
112   // invitation.
113   //
114   // Isolated invitations must be used in lieu of regular invitations in cases
115   // where both of the processes being connected already belong to independent
116   // multiprocess graphs.
117   //
118   // Such connections are limited in functionality:
119   //
120   //   * Platform handles may not be transferrable between the processes
121   //
122   //   * Pipes sent between the processes may not be subsequently transferred to
123   //     other processes in each others' process graph.
124   //
125   // Only one concurrent isolated connection is supported between any two
126   // processes.
127   //
128   // Unlike |Send()| above, isolated invitations automatically have a single
129   // message pipe attached and this is the only attachment allowed. The local
130   // end of the attached pipe is returned here.
131   //
132   // If |connection_name| is non-empty, any previously established isolated
133   // connection using the same name will be disconnected.
134   static ScopedMessagePipeHandle SendIsolated(
135       PlatformChannelEndpoint channel_endpoint,
136       base::StringPiece connection_name = {});
137 
138   // Similar to above but sends |invitation| via |server_endpoint|, which should
139   // correspond to a |PlatformChannelServerEndpoint| taken from a
140   // |NamedPlatformChannel|.
141   //
142   // If |connection_name| is non-empty, any previously established isolated
143   // connection using the same name will be disconnected.
144   static ScopedMessagePipeHandle SendIsolated(
145       PlatformChannelServerEndpoint server_endpoint,
146       base::StringPiece connection_name = {});
147 
148  private:
149   ScopedInvitationHandle handle_;
150 
151   DISALLOW_COPY_AND_ASSIGN(OutgoingInvitation);
152 };
153 
154 // An IncomingInvitation can be accepted by an invited process by calling
155 // |IncomingInvitation::Accept()|. Once accepted, the invitation can be used
156 // to extract attached message pipes by name.
157 class MOJO_CPP_SYSTEM_EXPORT IncomingInvitation {
158  public:
159   IncomingInvitation();
160   IncomingInvitation(IncomingInvitation&& other);
161   explicit IncomingInvitation(ScopedInvitationHandle handle);
162   ~IncomingInvitation();
163 
164   IncomingInvitation& operator=(IncomingInvitation&& other);
165 
166   // Accepts an incoming invitation from |channel_endpoint|. If the invitation
167   // was sent using one end of a |PlatformChannel|, |channel_endpoint| should be
168   // the other end of that channel. If the invitation was sent using a
169   // |PlatformChannelServerEndpoint|, then |channel_endpoint| should be created
170   // by |NamedPlatformChannel::ConnectToServer|.
171   //
172   // Note that this performs blocking I/O on the calling thread.
173   static IncomingInvitation Accept(
174       PlatformChannelEndpoint channel_endpoint,
175       MojoAcceptInvitationFlags flags = MOJO_ACCEPT_INVITATION_FLAG_NONE);
176 
177   // Like above, but does not perform any blocking I/O. Not all platforms and
178   // sandbox configurations are compatible with this API. In such cases, the
179   // synchronous |Accept()| above should be used.
180   static IncomingInvitation AcceptAsync(
181       PlatformChannelEndpoint channel_endpoint);
182 
183   // Accepts an incoming isolated invitation from |channel_endpoint|. See
184   // notes on |OutgoingInvitation::SendIsolated()|.
185   static ScopedMessagePipeHandle AcceptIsolated(
186       PlatformChannelEndpoint channel_endpoint);
187 
188   // Extracts an attached message pipe from this invitation. This may succeed
189   // even if no such pipe was attached, though the extracted pipe will
190   // eventually observe peer closure.
191   ScopedMessagePipeHandle ExtractMessagePipe(base::StringPiece name);
192 
193   // Same as above but allows use of an integer name for convenience.
194   ScopedMessagePipeHandle ExtractMessagePipe(uint64_t name);
195 
196  private:
197   ScopedInvitationHandle handle_;
198 
199   DISALLOW_COPY_AND_ASSIGN(IncomingInvitation);
200 };
201 
202 }  // namespace mojo
203 
204 #endif  // MOJO_PUBLIC_CPP_SYSTEM_INVITATION_H_
205