Home | History | Annotate | Download | only in system
      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 #include "mojo/public/cpp/system/invitation.h"
      6 
      7 #include "base/numerics/safe_conversions.h"
      8 #include "build/build_config.h"
      9 #include "mojo/public/c/system/invitation.h"
     10 #include "mojo/public/c/system/platform_handle.h"
     11 #include "mojo/public/cpp/system/platform_handle.h"
     12 
     13 namespace mojo {
     14 
     15 namespace {
     16 
     17 static constexpr base::StringPiece kIsolatedPipeName = {"\0\0\0\0", 4};
     18 
     19 void ProcessHandleToMojoProcessHandle(base::ProcessHandle target_process,
     20                                       MojoPlatformProcessHandle* handle) {
     21   handle->struct_size = sizeof(*handle);
     22 #if defined(OS_WIN)
     23   handle->value =
     24       static_cast<uint64_t>(reinterpret_cast<uintptr_t>(target_process));
     25 #else
     26   handle->value = static_cast<uint64_t>(target_process);
     27 #endif
     28 }
     29 
     30 void PlatformHandleToTransportEndpoint(
     31     PlatformHandle platform_handle,
     32     MojoPlatformHandle* endpoint_handle,
     33     MojoInvitationTransportEndpoint* endpoint) {
     34   PlatformHandle::ToMojoPlatformHandle(std::move(platform_handle),
     35                                        endpoint_handle);
     36   CHECK_NE(endpoint_handle->type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
     37 
     38   endpoint->struct_size = sizeof(*endpoint);
     39   endpoint->num_platform_handles = 1;
     40   endpoint->platform_handles = endpoint_handle;
     41 }
     42 
     43 void RunErrorCallback(uintptr_t context,
     44                       const MojoProcessErrorDetails* details) {
     45   auto* callback = reinterpret_cast<ProcessErrorCallback*>(context);
     46   std::string error_message;
     47   if (details->error_message) {
     48     error_message =
     49         std::string(details->error_message, details->error_message_length - 1);
     50     callback->Run(error_message);
     51   } else if (details->flags & MOJO_PROCESS_ERROR_FLAG_DISCONNECTED) {
     52     delete callback;
     53   }
     54 }
     55 
     56 void SendInvitation(ScopedInvitationHandle invitation,
     57                     base::ProcessHandle target_process,
     58                     PlatformHandle endpoint_handle,
     59                     MojoInvitationTransportType transport_type,
     60                     MojoSendInvitationFlags flags,
     61                     const ProcessErrorCallback& error_callback,
     62                     base::StringPiece isolated_connection_name) {
     63   MojoPlatformProcessHandle process_handle;
     64   ProcessHandleToMojoProcessHandle(target_process, &process_handle);
     65 
     66   MojoPlatformHandle platform_handle;
     67   MojoInvitationTransportEndpoint endpoint;
     68   PlatformHandleToTransportEndpoint(std::move(endpoint_handle),
     69                                     &platform_handle, &endpoint);
     70   endpoint.type = transport_type;
     71 
     72   MojoProcessErrorHandler error_handler = nullptr;
     73   uintptr_t error_handler_context = 0;
     74   if (error_callback) {
     75     error_handler = &RunErrorCallback;
     76 
     77     // NOTE: The allocated callback is effectively owned by the error handler,
     78     // which will delete it on the final invocation for this context (i.e.
     79     // process disconnection).
     80     error_handler_context =
     81         reinterpret_cast<uintptr_t>(new ProcessErrorCallback(error_callback));
     82   }
     83 
     84   MojoSendInvitationOptions options;
     85   options.struct_size = sizeof(options);
     86   options.flags = flags;
     87   if (flags & MOJO_SEND_INVITATION_FLAG_ISOLATED) {
     88     options.isolated_connection_name = isolated_connection_name.data();
     89     options.isolated_connection_name_length =
     90         static_cast<uint32_t>(isolated_connection_name.size());
     91   }
     92   MojoResult result =
     93       MojoSendInvitation(invitation.get().value(), &process_handle, &endpoint,
     94                          error_handler, error_handler_context, &options);
     95   // If successful, the invitation handle is already closed for us.
     96   if (result == MOJO_RESULT_OK)
     97     ignore_result(invitation.release());
     98 }
     99 
    100 }  // namespace
    101 
    102 OutgoingInvitation::OutgoingInvitation() {
    103   MojoHandle invitation_handle;
    104   MojoResult result = MojoCreateInvitation(nullptr, &invitation_handle);
    105   DCHECK_EQ(result, MOJO_RESULT_OK);
    106 
    107   handle_.reset(InvitationHandle(invitation_handle));
    108 }
    109 
    110 OutgoingInvitation::OutgoingInvitation(OutgoingInvitation&& other) = default;
    111 
    112 OutgoingInvitation::~OutgoingInvitation() = default;
    113 
    114 OutgoingInvitation& OutgoingInvitation::operator=(OutgoingInvitation&& other) =
    115     default;
    116 
    117 ScopedMessagePipeHandle OutgoingInvitation::AttachMessagePipe(
    118     base::StringPiece name) {
    119   DCHECK(!name.empty());
    120   DCHECK(base::IsValueInRangeForNumericType<uint32_t>(name.size()));
    121   MojoHandle message_pipe_handle;
    122   MojoResult result = MojoAttachMessagePipeToInvitation(
    123       handle_.get().value(), name.data(), static_cast<uint32_t>(name.size()),
    124       nullptr, &message_pipe_handle);
    125   DCHECK_EQ(MOJO_RESULT_OK, result);
    126   return ScopedMessagePipeHandle(MessagePipeHandle(message_pipe_handle));
    127 }
    128 
    129 ScopedMessagePipeHandle OutgoingInvitation::AttachMessagePipe(uint64_t name) {
    130   return AttachMessagePipe(
    131       base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name)));
    132 }
    133 
    134 ScopedMessagePipeHandle OutgoingInvitation::ExtractMessagePipe(
    135     base::StringPiece name) {
    136   DCHECK(!name.empty());
    137   DCHECK(base::IsValueInRangeForNumericType<uint32_t>(name.size()));
    138   MojoHandle message_pipe_handle;
    139   MojoResult result = MojoExtractMessagePipeFromInvitation(
    140       handle_.get().value(), name.data(), static_cast<uint32_t>(name.size()),
    141       nullptr, &message_pipe_handle);
    142   DCHECK_EQ(MOJO_RESULT_OK, result);
    143   return ScopedMessagePipeHandle(MessagePipeHandle(message_pipe_handle));
    144 }
    145 
    146 ScopedMessagePipeHandle OutgoingInvitation::ExtractMessagePipe(uint64_t name) {
    147   return ExtractMessagePipe(
    148       base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name)));
    149 }
    150 
    151 // static
    152 void OutgoingInvitation::Send(OutgoingInvitation invitation,
    153                               base::ProcessHandle target_process,
    154                               PlatformChannelEndpoint channel_endpoint,
    155                               const ProcessErrorCallback& error_callback) {
    156   SendInvitation(std::move(invitation.handle_), target_process,
    157                  channel_endpoint.TakePlatformHandle(),
    158                  MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL,
    159                  MOJO_SEND_INVITATION_FLAG_NONE, error_callback, "");
    160 }
    161 
    162 // static
    163 void OutgoingInvitation::Send(OutgoingInvitation invitation,
    164                               base::ProcessHandle target_process,
    165                               PlatformChannelServerEndpoint server_endpoint,
    166                               const ProcessErrorCallback& error_callback) {
    167   SendInvitation(std::move(invitation.handle_), target_process,
    168                  server_endpoint.TakePlatformHandle(),
    169                  MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER,
    170                  MOJO_SEND_INVITATION_FLAG_NONE, error_callback, "");
    171 }
    172 
    173 // static
    174 ScopedMessagePipeHandle OutgoingInvitation::SendIsolated(
    175     PlatformChannelEndpoint channel_endpoint,
    176     base::StringPiece connection_name) {
    177   mojo::OutgoingInvitation invitation;
    178   ScopedMessagePipeHandle pipe =
    179       invitation.AttachMessagePipe(kIsolatedPipeName);
    180   SendInvitation(std::move(invitation.handle_), base::kNullProcessHandle,
    181                  channel_endpoint.TakePlatformHandle(),
    182                  MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL,
    183                  MOJO_SEND_INVITATION_FLAG_ISOLATED, ProcessErrorCallback(),
    184                  connection_name);
    185   return pipe;
    186 }
    187 
    188 // static
    189 ScopedMessagePipeHandle OutgoingInvitation::SendIsolated(
    190     PlatformChannelServerEndpoint server_endpoint,
    191     base::StringPiece connection_name) {
    192   mojo::OutgoingInvitation invitation;
    193   ScopedMessagePipeHandle pipe =
    194       invitation.AttachMessagePipe(kIsolatedPipeName);
    195   SendInvitation(std::move(invitation.handle_), base::kNullProcessHandle,
    196                  server_endpoint.TakePlatformHandle(),
    197                  MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER,
    198                  MOJO_SEND_INVITATION_FLAG_ISOLATED, ProcessErrorCallback(),
    199                  connection_name);
    200   return pipe;
    201 }
    202 
    203 IncomingInvitation::IncomingInvitation() = default;
    204 
    205 IncomingInvitation::IncomingInvitation(IncomingInvitation&& other) = default;
    206 
    207 IncomingInvitation::IncomingInvitation(ScopedInvitationHandle handle)
    208     : handle_(std::move(handle)) {}
    209 
    210 IncomingInvitation::~IncomingInvitation() = default;
    211 
    212 IncomingInvitation& IncomingInvitation::operator=(IncomingInvitation&& other) =
    213     default;
    214 
    215 // static
    216 IncomingInvitation IncomingInvitation::Accept(
    217     PlatformChannelEndpoint channel_endpoint) {
    218   MojoPlatformHandle endpoint_handle;
    219   PlatformHandle::ToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(),
    220                                        &endpoint_handle);
    221   CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
    222 
    223   MojoInvitationTransportEndpoint transport_endpoint;
    224   transport_endpoint.struct_size = sizeof(transport_endpoint);
    225   transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL;
    226   transport_endpoint.num_platform_handles = 1;
    227   transport_endpoint.platform_handles = &endpoint_handle;
    228 
    229   MojoHandle invitation_handle;
    230   MojoResult result =
    231       MojoAcceptInvitation(&transport_endpoint, nullptr, &invitation_handle);
    232   if (result != MOJO_RESULT_OK)
    233     return IncomingInvitation();
    234 
    235   return IncomingInvitation(
    236       ScopedInvitationHandle(InvitationHandle(invitation_handle)));
    237 }
    238 
    239 // static
    240 ScopedMessagePipeHandle IncomingInvitation::AcceptIsolated(
    241     PlatformChannelEndpoint channel_endpoint) {
    242   MojoPlatformHandle endpoint_handle;
    243   PlatformHandle::ToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(),
    244                                        &endpoint_handle);
    245   CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
    246 
    247   MojoInvitationTransportEndpoint transport_endpoint;
    248   transport_endpoint.struct_size = sizeof(transport_endpoint);
    249   transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL;
    250   transport_endpoint.num_platform_handles = 1;
    251   transport_endpoint.platform_handles = &endpoint_handle;
    252 
    253   MojoAcceptInvitationOptions options;
    254   options.struct_size = sizeof(options);
    255   options.flags = MOJO_ACCEPT_INVITATION_FLAG_ISOLATED;
    256 
    257   MojoHandle invitation_handle;
    258   MojoResult result =
    259       MojoAcceptInvitation(&transport_endpoint, &options, &invitation_handle);
    260   if (result != MOJO_RESULT_OK)
    261     return ScopedMessagePipeHandle();
    262 
    263   IncomingInvitation invitation{
    264       ScopedInvitationHandle(InvitationHandle(invitation_handle))};
    265   return invitation.ExtractMessagePipe(kIsolatedPipeName);
    266 }
    267 
    268 ScopedMessagePipeHandle IncomingInvitation::ExtractMessagePipe(
    269     base::StringPiece name) {
    270   DCHECK(!name.empty());
    271   DCHECK(base::IsValueInRangeForNumericType<uint32_t>(name.size()));
    272   DCHECK(handle_.is_valid());
    273   MojoHandle message_pipe_handle;
    274   MojoResult result = MojoExtractMessagePipeFromInvitation(
    275       handle_.get().value(), name.data(), static_cast<uint32_t>(name.size()),
    276       nullptr, &message_pipe_handle);
    277   DCHECK_EQ(MOJO_RESULT_OK, result);
    278   return ScopedMessagePipeHandle(MessagePipeHandle(message_pipe_handle));
    279 }
    280 
    281 ScopedMessagePipeHandle IncomingInvitation::ExtractMessagePipe(uint64_t name) {
    282   return ExtractMessagePipe(
    283       base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name)));
    284 }
    285 
    286 }  // namespace mojo
    287