1 // Copyright 2016 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/edk/system/broker_host.h"
6 
7 #include <utility>
8 
9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/threading/thread_task_runner_handle.h"
13 #include "mojo/edk/embedder/named_platform_channel_pair.h"
14 #include "mojo/edk/embedder/named_platform_handle.h"
15 #include "mojo/edk/embedder/platform_handle_vector.h"
16 #include "mojo/edk/embedder/platform_shared_buffer.h"
17 #include "mojo/edk/system/broker_messages.h"
18 
19 namespace mojo {
20 namespace edk {
21 
BrokerHost(base::ProcessHandle client_process,ScopedPlatformHandle platform_handle)22 BrokerHost::BrokerHost(base::ProcessHandle client_process,
23                        ScopedPlatformHandle platform_handle)
24 #if defined(OS_WIN)
25     : client_process_(client_process)
26 #endif
27 {
28   CHECK(platform_handle.is_valid());
29 
30   base::MessageLoop::current()->AddDestructionObserver(this);
31 
32   channel_ = Channel::Create(this, ConnectionParams(std::move(platform_handle)),
33                              base::ThreadTaskRunnerHandle::Get());
34   channel_->Start();
35 }
36 
~BrokerHost()37 BrokerHost::~BrokerHost() {
38   // We're always destroyed on the creation thread, which is the IO thread.
39   base::MessageLoop::current()->RemoveDestructionObserver(this);
40 
41   if (channel_)
42     channel_->ShutDown();
43 }
44 
PrepareHandlesForClient(PlatformHandleVector * handles)45 bool BrokerHost::PrepareHandlesForClient(PlatformHandleVector* handles) {
46 #if defined(OS_WIN)
47   if (!Channel::Message::RewriteHandles(
48       base::GetCurrentProcessHandle(), client_process_, handles)) {
49     // NOTE: We only log an error here. We do not signal a logical error or
50     // prevent any message from being sent. The client should handle unexpected
51     // invalid handles appropriately.
52     DLOG(ERROR) << "Failed to rewrite one or more handles to broker client.";
53     return false;
54   }
55 #endif
56   return true;
57 }
58 
SendChannel(ScopedPlatformHandle handle)59 bool BrokerHost::SendChannel(ScopedPlatformHandle handle) {
60   CHECK(handle.is_valid());
61   CHECK(channel_);
62 
63 #if defined(OS_WIN)
64   InitData* data;
65   Channel::MessagePtr message =
66       CreateBrokerMessage(BrokerMessageType::INIT, 1, 0, &data);
67   data->pipe_name_length = 0;
68 #else
69   Channel::MessagePtr message =
70       CreateBrokerMessage(BrokerMessageType::INIT, 1, nullptr);
71 #endif
72   ScopedPlatformHandleVectorPtr handles;
73   handles.reset(new PlatformHandleVector(1));
74   handles->at(0) = handle.release();
75 
76   // This may legitimately fail on Windows if the client process is in another
77   // session, e.g., is an elevated process.
78   if (!PrepareHandlesForClient(handles.get()))
79     return false;
80 
81    message->SetHandles(std::move(handles));
82   channel_->Write(std::move(message));
83   return true;
84 }
85 
86 #if defined(OS_WIN)
87 
SendNamedChannel(const base::StringPiece16 & pipe_name)88 void BrokerHost::SendNamedChannel(const base::StringPiece16& pipe_name) {
89   InitData* data;
90   base::char16* name_data;
91   Channel::MessagePtr message = CreateBrokerMessage(
92       BrokerMessageType::INIT, 0, sizeof(*name_data) * pipe_name.length(),
93       &data, reinterpret_cast<void**>(&name_data));
94   data->pipe_name_length = static_cast<uint32_t>(pipe_name.length());
95   std::copy(pipe_name.begin(), pipe_name.end(), name_data);
96   channel_->Write(std::move(message));
97 }
98 
99 #endif  // defined(OS_WIN)
100 
OnBufferRequest(uint32_t num_bytes)101 void BrokerHost::OnBufferRequest(uint32_t num_bytes) {
102   scoped_refptr<PlatformSharedBuffer> read_only_buffer;
103   scoped_refptr<PlatformSharedBuffer> buffer =
104       PlatformSharedBuffer::Create(num_bytes);
105   if (buffer)
106     read_only_buffer = buffer->CreateReadOnlyDuplicate();
107   if (!read_only_buffer)
108     buffer = nullptr;
109 
110   Channel::MessagePtr message = CreateBrokerMessage(
111       BrokerMessageType::BUFFER_RESPONSE, buffer ? 2 : 0, nullptr);
112   if (buffer) {
113     ScopedPlatformHandleVectorPtr handles;
114     handles.reset(new PlatformHandleVector(2));
115     handles->at(0) = buffer->PassPlatformHandle().release();
116     handles->at(1) = read_only_buffer->PassPlatformHandle().release();
117     PrepareHandlesForClient(handles.get());
118     message->SetHandles(std::move(handles));
119   }
120 
121   channel_->Write(std::move(message));
122 }
123 
OnChannelMessage(const void * payload,size_t payload_size,ScopedPlatformHandleVectorPtr handles)124 void BrokerHost::OnChannelMessage(const void* payload,
125                                   size_t payload_size,
126                                   ScopedPlatformHandleVectorPtr handles) {
127   if (payload_size < sizeof(BrokerMessageHeader))
128     return;
129 
130   const BrokerMessageHeader* header =
131       static_cast<const BrokerMessageHeader*>(payload);
132   switch (header->type) {
133     case BrokerMessageType::BUFFER_REQUEST:
134       if (payload_size ==
135             sizeof(BrokerMessageHeader) + sizeof(BufferRequestData)) {
136         const BufferRequestData* request =
137             reinterpret_cast<const BufferRequestData*>(header + 1);
138         OnBufferRequest(request->size);
139       }
140       break;
141 
142     default:
143       LOG(ERROR) << "Unexpected broker message type: " << header->type;
144       break;
145   }
146 }
147 
OnChannelError()148 void BrokerHost::OnChannelError() { delete this; }
149 
WillDestroyCurrentMessageLoop()150 void BrokerHost::WillDestroyCurrentMessageLoop() { delete this; }
151 
152 }  // namespace edk
153 }  // namespace mojo
154