| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef MOJO_PUBLIC_CPP_SYSTEM_INVITATION_H_ |
| #define MOJO_PUBLIC_CPP_SYSTEM_INVITATION_H_ |
| |
| #include <cstdint> |
| #include <string> |
| #include <string_view> |
| |
| #include "base/component_export.h" |
| #include "base/functional/callback.h" |
| #include "base/process/process_handle.h" |
| #include "mojo/public/c/system/invitation.h" |
| #include "mojo/public/cpp/platform/platform_channel_endpoint.h" |
| #include "mojo/public/cpp/platform/platform_channel_server_endpoint.h" |
| #include "mojo/public/cpp/system/handle.h" |
| #include "mojo/public/cpp/system/message_pipe.h" |
| #include "mojo/public/cpp/system/system_export.h" |
| |
| namespace mojo { |
| |
| // A callback which may be provided when sending an invitation to another |
| // process. In the event of any validation errors regarding messages from that |
| // process (reported via MojoNotifyBadMessage etc and related helpers), the |
| // callback will be invoked. |
| using ProcessErrorCallback = base::RepeatingCallback<void(const std::string&)>; |
| |
| // A strongly-typed representation of a |MojoHandle| for an invitation. |
| class InvitationHandle : public Handle { |
| public: |
| InvitationHandle() {} |
| explicit InvitationHandle(MojoHandle value) : Handle(value) {} |
| |
| // Copying and assignment allowed. |
| }; |
| |
| static_assert(sizeof(InvitationHandle) == sizeof(Handle), |
| "Bad size for C++ InvitationHandle"); |
| |
| using ScopedInvitationHandle = ScopedHandleBase<InvitationHandle>; |
| static_assert(sizeof(ScopedInvitationHandle) == sizeof(InvitationHandle), |
| "Bad size for C++ ScopedInvitationHandle"); |
| |
| // An OutgoingInvitation is used to invite another process to join the calling |
| // process's IPC network. |
| // |
| // Typical use involves constructing a |PlatformChannel| and using one end to |
| // send the invitation (see |Send()| below) while passing the other to a child |
| // process. |
| // |
| // This may also be used with the server endpoint of a |NamedPlatformChannel|. |
| class MOJO_CPP_SYSTEM_EXPORT OutgoingInvitation { |
| public: |
| OutgoingInvitation(); |
| OutgoingInvitation(OutgoingInvitation&& other); |
| |
| OutgoingInvitation(const OutgoingInvitation&) = delete; |
| OutgoingInvitation& operator=(const OutgoingInvitation&) = delete; |
| |
| ~OutgoingInvitation(); |
| |
| OutgoingInvitation& operator=(OutgoingInvitation&& other); |
| |
| void set_extra_flags(MojoSendInvitationFlags flags) { extra_flags_ = flags; } |
| |
| // Creates a new message pipe, attaching one end to this invitation and |
| // returning the other end to the caller. The invitee can extract the |
| // attached endpoint (see |IncomingInvitation|) thus establishing end-to-end |
| // Mojo communication. |
| // |
| // |name| is an arbitrary value that must be used by the invitee to extract |
| // the corresponding attached endpoint. |
| ScopedMessagePipeHandle AttachMessagePipe(std::string_view name); |
| |
| // Same as above but allows use of an integer name for convenience. |
| ScopedMessagePipeHandle AttachMessagePipe(uint64_t name); |
| |
| // Extracts an attached pipe. Note that this is not typically useful, but it |
| // is potentially necessary in cases where a caller wants to, e.g., abort |
| // launching another process and recover a pipe endpoint they had previously |
| // attached. |
| ScopedMessagePipeHandle ExtractMessagePipe(std::string_view name); |
| |
| // Same as above but allows use of an integer name for convenience. |
| ScopedMessagePipeHandle ExtractMessagePipe(uint64_t name); |
| |
| // Sends |invitation| to another process via |channel_endpoint|, which should |
| // correspond to the local endpoint taken from a |PlatformChannel|. |
| // |
| // |process_handle| is a handle to the destination process if known. If not |
| // provided, IPC may be limited on some platforms (namely Mac and Windows) due |
| // to an inability to transfer system handles across the boundary. |
| static void Send(OutgoingInvitation invitation, |
| base::ProcessHandle target_process, |
| PlatformChannelEndpoint channel_endpoint, |
| const ProcessErrorCallback& error_callback = {}); |
| |
| // Similar to above, but sends |invitation| via |server_endpoint|, which |
| // should correspond to a |PlatformChannelServerEndpoint| taken from a |
| // |NamedPlatformChannel|. |
| static void Send(OutgoingInvitation invitation, |
| base::ProcessHandle target_process, |
| PlatformChannelServerEndpoint server_endpoint, |
| const ProcessErrorCallback& error_callback = {}); |
| |
| // Similar to |Send()|, but targets a process which will accept the invitation |
| // with |IncomingInvitation::AcceptAsync()| instead of |Accept()|. |
| static void SendAsync(OutgoingInvitation invitation, |
| base::ProcessHandle target_process, |
| PlatformChannelEndpoint channel_endpoint, |
| const ProcessErrorCallback& error_callback = {}); |
| |
| // Sends an isolated invitation over |endpoint|. The process at the other |
| // endpoint must use |IncomingInvitation::AcceptIsolated()| to accept the |
| // invitation. |
| // |
| // Isolated invitations must be used in lieu of regular invitations in cases |
| // where both of the processes being connected already belong to independent |
| // multiprocess graphs. |
| // |
| // Such connections are limited in functionality: |
| // |
| // * Platform handles may not be transferrable between the processes |
| // |
| // * Pipes sent between the processes may not be subsequently transferred to |
| // other processes in each others' process graph. |
| // |
| // Only one concurrent isolated connection is supported between any two |
| // processes. |
| // |
| // Unlike |Send()| above, isolated invitations automatically have a single |
| // message pipe attached and this is the only attachment allowed. The local |
| // end of the attached pipe is returned here. |
| // |
| // If |connection_name| is non-empty, any previously established isolated |
| // connection using the same name will be disconnected. |
| static ScopedMessagePipeHandle SendIsolated( |
| PlatformChannelEndpoint channel_endpoint, |
| std::string_view connection_name = {}, |
| base::ProcessHandle target_process = base::kNullProcessHandle); |
| |
| // Similar to above but sends |invitation| via |server_endpoint|, which should |
| // correspond to a |PlatformChannelServerEndpoint| taken from a |
| // |NamedPlatformChannel|. |
| // |
| // If |connection_name| is non-empty, any previously established isolated |
| // connection using the same name will be disconnected. |
| static ScopedMessagePipeHandle SendIsolated( |
| PlatformChannelServerEndpoint server_endpoint, |
| std::string_view connection_name = {}, |
| base::ProcessHandle target_process = base::kNullProcessHandle); |
| |
| private: |
| MojoSendInvitationFlags extra_flags_ = MOJO_SEND_INVITATION_FLAG_NONE; |
| ScopedInvitationHandle handle_; |
| }; |
| |
| // An IncomingInvitation can be accepted by an invited process by calling |
| // |IncomingInvitation::Accept()|. Once accepted, the invitation can be used |
| // to extract attached message pipes by name. |
| class MOJO_CPP_SYSTEM_EXPORT IncomingInvitation { |
| public: |
| IncomingInvitation(); |
| IncomingInvitation(IncomingInvitation&& other); |
| explicit IncomingInvitation(ScopedInvitationHandle handle); |
| |
| IncomingInvitation(const IncomingInvitation&) = delete; |
| IncomingInvitation& operator=(const IncomingInvitation&) = delete; |
| |
| ~IncomingInvitation(); |
| |
| IncomingInvitation& operator=(IncomingInvitation&& other); |
| |
| bool is_valid() const { return handle_.is_valid(); } |
| |
| // Accepts an incoming invitation from |channel_endpoint|. If the invitation |
| // was sent using one end of a |PlatformChannel|, |channel_endpoint| should be |
| // the other end of that channel. If the invitation was sent using a |
| // |PlatformChannelServerEndpoint|, then |channel_endpoint| should be created |
| // by |NamedPlatformChannel::ConnectToServer|. |
| // |
| // Note that this performs blocking I/O on the calling thread. |
| static IncomingInvitation Accept( |
| PlatformChannelEndpoint channel_endpoint, |
| MojoAcceptInvitationFlags flags = MOJO_ACCEPT_INVITATION_FLAG_NONE); |
| |
| // Like above, but does not perform any blocking I/O. Not all platforms and |
| // sandbox configurations are compatible with this API. In such cases, the |
| // synchronous |Accept()| above should be used. |
| static IncomingInvitation AcceptAsync( |
| PlatformChannelEndpoint channel_endpoint); |
| |
| // Accepts an incoming isolated invitation from |channel_endpoint|. See |
| // notes on |OutgoingInvitation::SendIsolated()|. |
| static ScopedMessagePipeHandle AcceptIsolated( |
| PlatformChannelEndpoint channel_endpoint); |
| |
| // Extracts an attached message pipe from this invitation. This may succeed |
| // even if no such pipe was attached, though the extracted pipe will |
| // eventually observe peer closure. |
| ScopedMessagePipeHandle ExtractMessagePipe(std::string_view name); |
| |
| // Same as above but allows use of an integer name for convenience. |
| ScopedMessagePipeHandle ExtractMessagePipe(uint64_t name); |
| |
| private: |
| ScopedInvitationHandle handle_; |
| }; |
| |
| } // namespace mojo |
| |
| #endif // MOJO_PUBLIC_CPP_SYSTEM_INVITATION_H_ |