blob: 9dd26a6fc262856aab7b1920505da6e5da14fc3a [file] [log] [blame]
[email protected]64860882014-08-04 23:44:171// Copyright 2014 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 "ipc/mojo/ipc_message_pipe_reader.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/location.h"
10#include "base/logging.h"
11#include "base/message_loop/message_loop_proxy.h"
morritadcc28ab2015-01-10 01:49:2112#include "ipc/mojo/async_handle_waiter.h"
morritad68bedf42014-11-25 23:35:5713#include "ipc/mojo/ipc_channel_mojo.h"
[email protected]64860882014-08-04 23:44:1714
15namespace IPC {
16namespace internal {
17
morritad68bedf42014-11-25 23:35:5718MessagePipeReader::MessagePipeReader(mojo::ScopedMessagePipeHandle handle,
19 MessagePipeReader::Delegate* delegate)
morritadcc28ab2015-01-10 01:49:2120 : pipe_(handle.Pass()),
21 delegate_(delegate),
22 async_waiter_(
23 new AsyncHandleWaiter(base::Bind(&MessagePipeReader::PipeIsReady,
morritab4472142015-04-20 21:20:1224 base::Unretained(this)))),
25 pending_send_error_(MOJO_RESULT_OK) {
[email protected]64860882014-08-04 23:44:1726}
27
28MessagePipeReader::~MessagePipeReader() {
morritab4472142015-04-20 21:20:1229 // The pipe should be closed before deletion.
[email protected]64860882014-08-04 23:44:1730 CHECK(!IsValid());
morritab4472142015-04-20 21:20:1231 DCHECK_EQ(pending_send_error_, MOJO_RESULT_OK);
[email protected]64860882014-08-04 23:44:1732}
33
34void MessagePipeReader::Close() {
morritab4472142015-04-20 21:20:1235 // All pending errors should be signaled before Close().
36 DCHECK_EQ(pending_send_error_, MOJO_RESULT_OK);
morritadcc28ab2015-01-10 01:49:2137 async_waiter_.reset();
[email protected]64860882014-08-04 23:44:1738 pipe_.reset();
39 OnPipeClosed();
40}
41
42void MessagePipeReader::CloseWithError(MojoResult error) {
43 OnPipeError(error);
44 Close();
45}
46
morritab4472142015-04-20 21:20:1247void MessagePipeReader::CloseWithErrorIfPending() {
48 if (pending_send_error_ == MOJO_RESULT_OK)
49 return;
50 MojoResult error = pending_send_error_;
51 pending_send_error_ = MOJO_RESULT_OK;
52 CloseWithError(error);
53 return;
54}
55
56void MessagePipeReader::CloseWithErrorLater(MojoResult error) {
57 pending_send_error_ = error;
58}
59
morritad68bedf42014-11-25 23:35:5760bool MessagePipeReader::Send(scoped_ptr<Message> message) {
61 DCHECK(IsValid());
62
63 message->TraceMessageBegin();
64 std::vector<MojoHandle> handles;
65 MojoResult result = MOJO_RESULT_OK;
morrita4b5c28e22015-01-14 21:17:0666 result = ChannelMojo::ReadFromMessageAttachmentSet(message.get(), &handles);
morritad68bedf42014-11-25 23:35:5767 if (result == MOJO_RESULT_OK) {
68 result = MojoWriteMessage(handle(),
69 message->data(),
70 static_cast<uint32>(message->size()),
71 handles.empty() ? nullptr : &handles[0],
72 static_cast<uint32>(handles.size()),
73 MOJO_WRITE_MESSAGE_FLAG_NONE);
74 }
75
76 if (result != MOJO_RESULT_OK) {
77 std::for_each(handles.begin(), handles.end(), &MojoClose);
morritab4472142015-04-20 21:20:1278 // We cannot call CloseWithError() here as Send() is protected by
79 // ChannelMojo's lock and CloseWithError() could re-enter ChannelMojo. We
80 // cannot call CloseWithError() also because Send() can be called from
81 // non-UI thread while OnPipeError() expects to be called on IO thread.
82 CloseWithErrorLater(result);
morritad68bedf42014-11-25 23:35:5783 return false;
84 }
85
86 return true;
87}
88
morritad68bedf42014-11-25 23:35:5789void MessagePipeReader::OnMessageReceived() {
90 Message message(data_buffer().empty() ? "" : &data_buffer()[0],
91 static_cast<uint32>(data_buffer().size()));
92
93 std::vector<MojoHandle> handle_buffer;
94 TakeHandleBuffer(&handle_buffer);
morritad68bedf42014-11-25 23:35:5795 MojoResult write_result =
morrita4b5c28e22015-01-14 21:17:0696 ChannelMojo::WriteToMessageAttachmentSet(handle_buffer, &message);
morritad68bedf42014-11-25 23:35:5797 if (write_result != MOJO_RESULT_OK) {
98 CloseWithError(write_result);
99 return;
100 }
morritad68bedf42014-11-25 23:35:57101
102 message.TraceMessageEnd();
103 delegate_->OnMessageReceived(message);
[email protected]64860882014-08-04 23:44:17104}
105
morritad68bedf42014-11-25 23:35:57106void MessagePipeReader::OnPipeClosed() {
107 if (!delegate_)
[email protected]64860882014-08-04 23:44:17108 return;
morritad68bedf42014-11-25 23:35:57109 delegate_->OnPipeClosed(this);
110 delegate_ = nullptr;
111}
112
113void MessagePipeReader::OnPipeError(MojoResult error) {
114 if (!delegate_)
115 return;
116 delegate_->OnPipeError(this);
117}
118
119MojoResult MessagePipeReader::ReadMessageBytes() {
120 DCHECK(handle_buffer_.empty());
121
122 uint32_t num_bytes = static_cast<uint32_t>(data_buffer_.size());
123 uint32_t num_handles = 0;
124 MojoResult result = MojoReadMessage(pipe_.get().value(),
125 num_bytes ? &data_buffer_[0] : nullptr,
126 &num_bytes,
127 nullptr,
128 &num_handles,
129 MOJO_READ_MESSAGE_FLAG_NONE);
130 data_buffer_.resize(num_bytes);
131 handle_buffer_.resize(num_handles);
132 if (result == MOJO_RESULT_RESOURCE_EXHAUSTED) {
133 // MOJO_RESULT_RESOURCE_EXHAUSTED was asking the caller that
134 // it needs more bufer. So we re-read it with resized buffers.
135 result = MojoReadMessage(pipe_.get().value(),
136 num_bytes ? &data_buffer_[0] : nullptr,
137 &num_bytes,
138 num_handles ? &handle_buffer_[0] : nullptr,
139 &num_handles,
140 MOJO_READ_MESSAGE_FLAG_NONE);
141 }
142
143 DCHECK(0 == num_bytes || data_buffer_.size() == num_bytes);
144 DCHECK(0 == num_handles || handle_buffer_.size() == num_handles);
145 return result;
[email protected]64860882014-08-04 23:44:17146}
147
morritadcc28ab2015-01-10 01:49:21148void MessagePipeReader::ReadAvailableMessages() {
[email protected]64860882014-08-04 23:44:17149 while (pipe_.is_valid()) {
150 MojoResult read_result = ReadMessageBytes();
151 if (read_result == MOJO_RESULT_SHOULD_WAIT)
152 break;
153 if (read_result != MOJO_RESULT_OK) {
154 // FAILED_PRECONDITION means that all the received messages
155 // got consumed and the peer is already closed.
156 if (read_result != MOJO_RESULT_FAILED_PRECONDITION) {
157 DLOG(WARNING)
158 << "Pipe got error from ReadMessage(). Closing: " << read_result;
159 OnPipeError(read_result);
160 }
161
162 Close();
163 break;
164 }
165
166 OnMessageReceived();
167 }
168
[email protected]64860882014-08-04 23:44:17169}
170
morritadcc28ab2015-01-10 01:49:21171void MessagePipeReader::ReadMessagesThenWait() {
172 while (true) {
173 ReadAvailableMessages();
174 if (!pipe_.is_valid())
175 break;
176 // |Wait()| is safe to call only after all messages are read.
177 // If can fail with |MOJO_RESULT_ALREADY_EXISTS| otherwise.
178 // Also, we don't use MOJO_HANDLE_SIGNAL_WRITABLE here, expecting buffer in
179 // MessagePipe.
tkent5eab51f2015-03-25 04:40:10180 MojoResult result =
181 async_waiter_->Wait(pipe_.get().value(), MOJO_HANDLE_SIGNAL_READABLE);
morritadcc28ab2015-01-10 01:49:21182 // If the result is |MOJO_RESULT_ALREADY_EXISTS|, there could be messages
183 // that have been arrived after the last |ReadAvailableMessages()|.
184 // We have to consume then and retry in that case.
185 if (result != MOJO_RESULT_ALREADY_EXISTS) {
186 if (result != MOJO_RESULT_OK) {
morritaa3889aa2015-03-16 22:40:51187 LOG(ERROR) << "Failed to wait on the pipe. Result is " << result;
morritadcc28ab2015-01-10 01:49:21188 OnPipeError(result);
189 Close();
190 }
191
192 break;
193 }
194 }
morritad68bedf42014-11-25 23:35:57195}
[email protected]64860882014-08-04 23:44:17196
morritadcc28ab2015-01-10 01:49:21197void MessagePipeReader::PipeIsReady(MojoResult wait_result) {
morritab4472142015-04-20 21:20:12198 CloseWithErrorIfPending();
199 if (!IsValid()) {
200 // There was a pending error and it closed the pipe.
201 // We cannot do the work anymore.
202 return;
203 }
204
morritadcc28ab2015-01-10 01:49:21205 if (wait_result != MOJO_RESULT_OK) {
tkent5eab51f2015-03-25 04:40:10206 if (wait_result != MOJO_RESULT_ABORTED) {
207 // FAILED_PRECONDITION happens every time the peer is dead so
208 // it isn't worth polluting the log message.
209 LOG_IF(WARNING, wait_result != MOJO_RESULT_FAILED_PRECONDITION)
210 << "Pipe got error from the waiter. Closing: " << wait_result;
211 OnPipeError(wait_result);
212 }
morritadcc28ab2015-01-10 01:49:21213
214 Close();
morritad68bedf42014-11-25 23:35:57215 return;
morritadcc28ab2015-01-10 01:49:21216 }
217
218 ReadMessagesThenWait();
[email protected]64860882014-08-04 23:44:17219}
220
221void MessagePipeReader::DelayedDeleter::operator()(
222 MessagePipeReader* ptr) const {
223 ptr->Close();
224 base::MessageLoopProxy::current()->PostTask(
225 FROM_HERE, base::Bind(&DeleteNow, ptr));
226}
227
228} // namespace internal
229} // namespace IPC