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