blob: e999028a6f3b6e2cd39cae48e13d2e1e7c8c4e71 [file] [log] [blame]
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +09001// Copyright (c) 2012 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/ipc_channel_reader.h"
6
avi42ebda42015-12-22 11:39:04 +09007#include <stddef.h>
8
erikchenf295bbc2015-07-28 03:26:14 +09009#include <algorithm>
10
fdorayf3a7ed52016-10-01 05:42:16 +090011#include "base/logging.h"
erikchen0bf12402015-11-07 06:12:36 +090012#include "base/message_loop/message_loop.h"
fdorayf3a7ed52016-10-01 05:42:16 +090013#include "base/threading/thread_task_runner_handle.h"
tfarina@chromium.orgb6d81202012-11-16 07:22:17 +090014#include "ipc/ipc_listener.h"
jbates@chromium.org7cc80332012-09-18 12:41:29 +090015#include "ipc/ipc_logging.h"
erikchenf295bbc2015-07-28 03:26:14 +090016#include "ipc/ipc_message.h"
17#include "ipc/ipc_message_attachment_set.h"
jbates@chromium.org7cc80332012-09-18 12:41:29 +090018#include "ipc/ipc_message_macros.h"
19
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +090020namespace IPC {
21namespace internal {
22
davidsz3bf38eb2017-05-12 18:19:23 +090023#if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
tzik3b85c2b2016-03-29 13:56:02 +090024
25namespace {
26std::string GetMessageText(const Message& message) {
27 std::string name;
28 Logging::GetInstance()->GetMessageText(
29 message.type(), &name, &message, nullptr);
30 return name;
31}
32} // namespace
33
34#define EMIT_TRACE_EVENT(message) \
35 TRACE_EVENT_WITH_FLOW1( \
36 "ipc,toplevel", "ChannelReader::DispatchInputData", \
37 (message).flags(), TRACE_EVENT_FLAG_FLOW_IN, "name", \
38 GetMessageText(message));
39#else
40#define EMIT_TRACE_EVENT(message) \
41 TRACE_EVENT_WITH_FLOW2("ipc,toplevel", "ChannelReader::DispatchInputData", \
42 (message).flags(), TRACE_EVENT_FLAG_FLOW_IN, "class", \
43 IPC_MESSAGE_ID_CLASS((message).type()), "line", \
44 IPC_MESSAGE_ID_LINE((message).type()));
davidsz3bf38eb2017-05-12 18:19:23 +090045#endif // BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
tzik3b85c2b2016-03-29 13:56:02 +090046
dskiba905b9b92015-11-04 10:24:59 +090047ChannelReader::ChannelReader(Listener* listener)
48 : listener_(listener),
49 max_input_buffer_size_(Channel::kMaximumReadBufferSize) {
jhawkins@chromium.org4448a872012-03-13 05:45:03 +090050 memset(input_buf_, 0, sizeof(input_buf_));
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +090051}
52
53ChannelReader::~ChannelReader() {
54}
55
erikchenf295bbc2015-07-28 03:26:14 +090056ChannelReader::DispatchState ChannelReader::ProcessIncomingMessages() {
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +090057 while (true) {
58 int bytes_read = 0;
59 ReadState read_state = ReadData(input_buf_, Channel::kReadBufferSize,
60 &bytes_read);
61 if (read_state == READ_FAILED)
erikchenf295bbc2015-07-28 03:26:14 +090062 return DISPATCH_ERROR;
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +090063 if (read_state == READ_PENDING)
erikchenf295bbc2015-07-28 03:26:14 +090064 return DISPATCH_FINISHED;
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +090065
66 DCHECK(bytes_read > 0);
erikchenf295bbc2015-07-28 03:26:14 +090067 if (!TranslateInputData(input_buf_, bytes_read))
68 return DISPATCH_ERROR;
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +090069 }
70}
71
erikchenf295bbc2015-07-28 03:26:14 +090072ChannelReader::DispatchState ChannelReader::AsyncReadComplete(int bytes_read) {
73 if (!TranslateInputData(input_buf_, bytes_read))
74 return DISPATCH_ERROR;
75
sammcc54b4e92016-11-09 08:24:35 +090076 return DISPATCH_FINISHED;
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +090077}
78
morrita@chromium.org15996aa2014-08-05 08:44:17 +090079bool ChannelReader::IsInternalMessage(const Message& m) {
hubbe@chromium.org683920d2013-10-15 09:07:00 +090080 return m.routing_id() == MSG_ROUTING_NONE &&
81 m.type() >= Channel::CLOSE_FD_MESSAGE_TYPE &&
82 m.type() <= Channel::HELLO_MESSAGE_TYPE;
83}
84
morrita@chromium.org15996aa2014-08-05 08:44:17 +090085bool ChannelReader::IsHelloMessage(const Message& m) {
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +090086 return m.routing_id() == MSG_ROUTING_NONE &&
hubbe@chromium.org683920d2013-10-15 09:07:00 +090087 m.type() == Channel::HELLO_MESSAGE_TYPE;
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +090088}
89
erikchen133c2892015-09-12 02:33:34 +090090void ChannelReader::CleanUp() {
erikchen133c2892015-09-12 02:33:34 +090091}
92
erikchen2c0e5dc2015-10-22 07:28:54 +090093void ChannelReader::DispatchMessage(Message* m) {
tzik3b85c2b2016-03-29 13:56:02 +090094 EMIT_TRACE_EVENT(*m);
erikchen2c0e5dc2015-10-22 07:28:54 +090095 listener_->OnMessageReceived(*m);
96 HandleDispatchError(*m);
97}
98
erikchenf295bbc2015-07-28 03:26:14 +090099bool ChannelReader::TranslateInputData(const char* input_data,
100 int input_data_len) {
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +0900101 const char* p;
102 const char* end;
103
104 // Possibly combine with the overflow buffer to make a larger buffer.
105 if (input_overflow_buf_.empty()) {
106 p = input_data;
107 end = input_data + input_data_len;
108 } else {
dskibaaa08dcb2015-10-01 02:24:30 +0900109 if (!CheckMessageSize(input_overflow_buf_.size() + input_data_len))
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +0900110 return false;
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +0900111 input_overflow_buf_.append(input_data, input_data_len);
112 p = input_overflow_buf_.data();
113 end = p + input_overflow_buf_.size();
114 }
115
dskibaaa08dcb2015-10-01 02:24:30 +0900116 size_t next_message_size = 0;
117
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +0900118 // Dispatch all complete messages in the data buffer.
119 while (p < end) {
erikchenc8dc3f52015-09-12 04:08:53 +0900120 Message::NextMessageInfo info;
121 Message::FindNext(p, end, &info);
122 if (info.message_found) {
123 int pickle_len = static_cast<int>(info.pickle_end - p);
124 Message translated_message(p, pickle_len);
erikchenf295bbc2015-07-28 03:26:14 +0900125
sammcc54b4e92016-11-09 08:24:35 +0900126 if (!HandleTranslatedMessage(&translated_message))
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +0900127 return false;
128
erikchenc8dc3f52015-09-12 04:08:53 +0900129 p = info.message_end;
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +0900130 } else {
131 // Last message is partial.
dskibaaa08dcb2015-10-01 02:24:30 +0900132 next_message_size = info.message_size;
133 if (!CheckMessageSize(next_message_size))
134 return false;
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +0900135 break;
136 }
137 }
138
dskiba905b9b92015-11-04 10:24:59 +0900139 // Account for the case where last message's byte is in the next data chunk.
140 size_t next_message_buffer_size = next_message_size ?
141 next_message_size + Channel::kReadBufferSize - 1:
142 0;
143
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +0900144 // Save any partial data in the overflow buffer.
thakisa9f80b92015-11-06 09:54:06 +0900145 if (p != input_overflow_buf_.data())
146 input_overflow_buf_.assign(p, end - p);
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +0900147
dskibaaa08dcb2015-10-01 02:24:30 +0900148 if (!input_overflow_buf_.empty()) {
149 // We have something in the overflow buffer, which means that we will
150 // append the next data chunk (instead of parsing it directly). So we
151 // resize the buffer to fit the next message, to avoid repeatedly
152 // growing the buffer as we receive all message' data chunks.
dskiba905b9b92015-11-04 10:24:59 +0900153 if (next_message_buffer_size > input_overflow_buf_.capacity()) {
154 input_overflow_buf_.reserve(next_message_buffer_size);
dskibaaa08dcb2015-10-01 02:24:30 +0900155 }
156 }
157
dskiba905b9b92015-11-04 10:24:59 +0900158 // Trim the buffer if we can
159 if (next_message_buffer_size < max_input_buffer_size_ &&
160 input_overflow_buf_.size() < max_input_buffer_size_ &&
161 input_overflow_buf_.capacity() > max_input_buffer_size_) {
162 // std::string doesn't really have a method to shrink capacity to
163 // a specific value, so we have to swap with another string.
164 std::string trimmed_buf;
165 trimmed_buf.reserve(max_input_buffer_size_);
166 if (trimmed_buf.capacity() > max_input_buffer_size_) {
167 // Since we don't control how much space reserve() actually reserves,
168 // we have to go other way around and change the max size to avoid
169 // getting into the outer if() again.
170 max_input_buffer_size_ = trimmed_buf.capacity();
171 }
172 trimmed_buf.assign(input_overflow_buf_.data(),
173 input_overflow_buf_.size());
174 input_overflow_buf_.swap(trimmed_buf);
175 }
176
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +0900177 if (input_overflow_buf_.empty() && !DidEmptyInputBuffers())
178 return false;
179 return true;
180}
181
sammcc54b4e92016-11-09 08:24:35 +0900182bool ChannelReader::HandleTranslatedMessage(Message* translated_message) {
erikchen2c0e5dc2015-10-22 07:28:54 +0900183 // Immediately handle internal messages.
184 if (IsInternalMessage(*translated_message)) {
tzik3b85c2b2016-03-29 13:56:02 +0900185 EMIT_TRACE_EVENT(*translated_message);
erikchen2c0e5dc2015-10-22 07:28:54 +0900186 HandleInternalMessage(*translated_message);
187 HandleDispatchError(*translated_message);
188 return true;
189 }
190
sammcc54b4e92016-11-09 08:24:35 +0900191 return HandleExternalMessage(translated_message);
erikchen2c0e5dc2015-10-22 07:28:54 +0900192}
193
sammcc54b4e92016-11-09 08:24:35 +0900194bool ChannelReader::HandleExternalMessage(Message* external_message) {
sammc14583362016-11-23 12:17:35 +0900195 if (!GetAttachments(external_message))
erikchen2c0e5dc2015-10-22 07:28:54 +0900196 return false;
197
sammcc54b4e92016-11-09 08:24:35 +0900198 DispatchMessage(external_message);
erikchen2c0e5dc2015-10-22 07:28:54 +0900199 return true;
200}
201
202void ChannelReader::HandleDispatchError(const Message& message) {
203 if (message.dispatch_error())
204 listener_->OnBadMessageReceived(message);
205}
206
dskibaaa08dcb2015-10-01 02:24:30 +0900207bool ChannelReader::CheckMessageSize(size_t size) {
208 if (size <= Channel::kMaximumMessageSize) {
209 return true;
210 }
211 input_overflow_buf_.clear();
212 LOG(ERROR) << "IPC message is too big: " << size;
213 return false;
214}
215
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +0900216} // namespace internal
217} // namespace IPC