brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 1 | // 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 | |
avi | 42ebda4 | 2015-12-22 11:39:04 +0900 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 9 | #include <algorithm> |
| 10 | |
fdoray | f3a7ed5 | 2016-10-01 05:42:16 +0900 | [diff] [blame] | 11 | #include "base/logging.h" |
erikchen | 0bf1240 | 2015-11-07 06:12:36 +0900 | [diff] [blame] | 12 | #include "base/message_loop/message_loop.h" |
fdoray | f3a7ed5 | 2016-10-01 05:42:16 +0900 | [diff] [blame] | 13 | #include "base/threading/thread_task_runner_handle.h" |
tfarina@chromium.org | b6d8120 | 2012-11-16 07:22:17 +0900 | [diff] [blame] | 14 | #include "ipc/ipc_listener.h" |
jbates@chromium.org | 7cc8033 | 2012-09-18 12:41:29 +0900 | [diff] [blame] | 15 | #include "ipc/ipc_logging.h" |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 16 | #include "ipc/ipc_message.h" |
| 17 | #include "ipc/ipc_message_attachment_set.h" |
jbates@chromium.org | 7cc8033 | 2012-09-18 12:41:29 +0900 | [diff] [blame] | 18 | #include "ipc/ipc_message_macros.h" |
| 19 | |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 20 | namespace IPC { |
| 21 | namespace internal { |
| 22 | |
davidsz | 3bf38eb | 2017-05-12 18:19:23 +0900 | [diff] [blame] | 23 | #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED) |
tzik | 3b85c2b | 2016-03-29 13:56:02 +0900 | [diff] [blame] | 24 | |
| 25 | namespace { |
| 26 | std::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())); |
davidsz | 3bf38eb | 2017-05-12 18:19:23 +0900 | [diff] [blame] | 45 | #endif // BUILDFLAG(IPC_MESSAGE_LOG_ENABLED) |
tzik | 3b85c2b | 2016-03-29 13:56:02 +0900 | [diff] [blame] | 46 | |
dskiba | 905b9b9 | 2015-11-04 10:24:59 +0900 | [diff] [blame] | 47 | ChannelReader::ChannelReader(Listener* listener) |
| 48 | : listener_(listener), |
| 49 | max_input_buffer_size_(Channel::kMaximumReadBufferSize) { |
jhawkins@chromium.org | 4448a87 | 2012-03-13 05:45:03 +0900 | [diff] [blame] | 50 | memset(input_buf_, 0, sizeof(input_buf_)); |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 51 | } |
| 52 | |
| 53 | ChannelReader::~ChannelReader() { |
| 54 | } |
| 55 | |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 56 | ChannelReader::DispatchState ChannelReader::ProcessIncomingMessages() { |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 57 | 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) |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 62 | return DISPATCH_ERROR; |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 63 | if (read_state == READ_PENDING) |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 64 | return DISPATCH_FINISHED; |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 65 | |
| 66 | DCHECK(bytes_read > 0); |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 67 | if (!TranslateInputData(input_buf_, bytes_read)) |
| 68 | return DISPATCH_ERROR; |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 69 | } |
| 70 | } |
| 71 | |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 72 | ChannelReader::DispatchState ChannelReader::AsyncReadComplete(int bytes_read) { |
| 73 | if (!TranslateInputData(input_buf_, bytes_read)) |
| 74 | return DISPATCH_ERROR; |
| 75 | |
sammc | c54b4e9 | 2016-11-09 08:24:35 +0900 | [diff] [blame] | 76 | return DISPATCH_FINISHED; |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 77 | } |
| 78 | |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 79 | bool ChannelReader::IsInternalMessage(const Message& m) { |
hubbe@chromium.org | 683920d | 2013-10-15 09:07:00 +0900 | [diff] [blame] | 80 | 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.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 85 | bool ChannelReader::IsHelloMessage(const Message& m) { |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 86 | return m.routing_id() == MSG_ROUTING_NONE && |
hubbe@chromium.org | 683920d | 2013-10-15 09:07:00 +0900 | [diff] [blame] | 87 | m.type() == Channel::HELLO_MESSAGE_TYPE; |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 88 | } |
| 89 | |
erikchen | 133c289 | 2015-09-12 02:33:34 +0900 | [diff] [blame] | 90 | void ChannelReader::CleanUp() { |
erikchen | 133c289 | 2015-09-12 02:33:34 +0900 | [diff] [blame] | 91 | } |
| 92 | |
erikchen | 2c0e5dc | 2015-10-22 07:28:54 +0900 | [diff] [blame] | 93 | void ChannelReader::DispatchMessage(Message* m) { |
tzik | 3b85c2b | 2016-03-29 13:56:02 +0900 | [diff] [blame] | 94 | EMIT_TRACE_EVENT(*m); |
erikchen | 2c0e5dc | 2015-10-22 07:28:54 +0900 | [diff] [blame] | 95 | listener_->OnMessageReceived(*m); |
| 96 | HandleDispatchError(*m); |
| 97 | } |
| 98 | |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 99 | bool ChannelReader::TranslateInputData(const char* input_data, |
| 100 | int input_data_len) { |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 101 | 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 { |
dskiba | aa08dcb | 2015-10-01 02:24:30 +0900 | [diff] [blame] | 109 | if (!CheckMessageSize(input_overflow_buf_.size() + input_data_len)) |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 110 | return false; |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 111 | input_overflow_buf_.append(input_data, input_data_len); |
| 112 | p = input_overflow_buf_.data(); |
| 113 | end = p + input_overflow_buf_.size(); |
| 114 | } |
| 115 | |
dskiba | aa08dcb | 2015-10-01 02:24:30 +0900 | [diff] [blame] | 116 | size_t next_message_size = 0; |
| 117 | |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 118 | // Dispatch all complete messages in the data buffer. |
| 119 | while (p < end) { |
erikchen | c8dc3f5 | 2015-09-12 04:08:53 +0900 | [diff] [blame] | 120 | 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); |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 125 | |
sammc | c54b4e9 | 2016-11-09 08:24:35 +0900 | [diff] [blame] | 126 | if (!HandleTranslatedMessage(&translated_message)) |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 127 | return false; |
| 128 | |
erikchen | c8dc3f5 | 2015-09-12 04:08:53 +0900 | [diff] [blame] | 129 | p = info.message_end; |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 130 | } else { |
| 131 | // Last message is partial. |
dskiba | aa08dcb | 2015-10-01 02:24:30 +0900 | [diff] [blame] | 132 | next_message_size = info.message_size; |
| 133 | if (!CheckMessageSize(next_message_size)) |
| 134 | return false; |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 135 | break; |
| 136 | } |
| 137 | } |
| 138 | |
dskiba | 905b9b9 | 2015-11-04 10:24:59 +0900 | [diff] [blame] | 139 | // 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.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 144 | // Save any partial data in the overflow buffer. |
thakis | a9f80b9 | 2015-11-06 09:54:06 +0900 | [diff] [blame] | 145 | if (p != input_overflow_buf_.data()) |
| 146 | input_overflow_buf_.assign(p, end - p); |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 147 | |
dskiba | aa08dcb | 2015-10-01 02:24:30 +0900 | [diff] [blame] | 148 | 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. |
dskiba | 905b9b9 | 2015-11-04 10:24:59 +0900 | [diff] [blame] | 153 | if (next_message_buffer_size > input_overflow_buf_.capacity()) { |
| 154 | input_overflow_buf_.reserve(next_message_buffer_size); |
dskiba | aa08dcb | 2015-10-01 02:24:30 +0900 | [diff] [blame] | 155 | } |
| 156 | } |
| 157 | |
dskiba | 905b9b9 | 2015-11-04 10:24:59 +0900 | [diff] [blame] | 158 | // 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.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 177 | if (input_overflow_buf_.empty() && !DidEmptyInputBuffers()) |
| 178 | return false; |
| 179 | return true; |
| 180 | } |
| 181 | |
sammc | c54b4e9 | 2016-11-09 08:24:35 +0900 | [diff] [blame] | 182 | bool ChannelReader::HandleTranslatedMessage(Message* translated_message) { |
erikchen | 2c0e5dc | 2015-10-22 07:28:54 +0900 | [diff] [blame] | 183 | // Immediately handle internal messages. |
| 184 | if (IsInternalMessage(*translated_message)) { |
tzik | 3b85c2b | 2016-03-29 13:56:02 +0900 | [diff] [blame] | 185 | EMIT_TRACE_EVENT(*translated_message); |
erikchen | 2c0e5dc | 2015-10-22 07:28:54 +0900 | [diff] [blame] | 186 | HandleInternalMessage(*translated_message); |
| 187 | HandleDispatchError(*translated_message); |
| 188 | return true; |
| 189 | } |
| 190 | |
sammc | c54b4e9 | 2016-11-09 08:24:35 +0900 | [diff] [blame] | 191 | return HandleExternalMessage(translated_message); |
erikchen | 2c0e5dc | 2015-10-22 07:28:54 +0900 | [diff] [blame] | 192 | } |
| 193 | |
sammc | c54b4e9 | 2016-11-09 08:24:35 +0900 | [diff] [blame] | 194 | bool ChannelReader::HandleExternalMessage(Message* external_message) { |
sammc | 1458336 | 2016-11-23 12:17:35 +0900 | [diff] [blame] | 195 | if (!GetAttachments(external_message)) |
erikchen | 2c0e5dc | 2015-10-22 07:28:54 +0900 | [diff] [blame] | 196 | return false; |
| 197 | |
sammc | c54b4e9 | 2016-11-09 08:24:35 +0900 | [diff] [blame] | 198 | DispatchMessage(external_message); |
erikchen | 2c0e5dc | 2015-10-22 07:28:54 +0900 | [diff] [blame] | 199 | return true; |
| 200 | } |
| 201 | |
| 202 | void ChannelReader::HandleDispatchError(const Message& message) { |
| 203 | if (message.dispatch_error()) |
| 204 | listener_->OnBadMessageReceived(message); |
| 205 | } |
| 206 | |
dskiba | aa08dcb | 2015-10-01 02:24:30 +0900 | [diff] [blame] | 207 | bool 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.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 216 | } // namespace internal |
| 217 | } // namespace IPC |