xref: /aosp_15_r20/external/cronet/ipc/ipc_channel_reader.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 The Chromium Authors
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 
7 #include <stddef.h>
8 
9 #include <algorithm>
10 
11 #include "base/logging.h"
12 #include "ipc/ipc_listener.h"
13 #include "ipc/ipc_logging.h"
14 #include "ipc/ipc_message.h"
15 #include "ipc/ipc_message_attachment_set.h"
16 #include "ipc/ipc_message_macros.h"
17 
18 namespace IPC {
19 namespace internal {
20 
21 #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
22 
23 namespace {
GetMessageText(const Message & message)24 std::string GetMessageText(const Message& message) {
25   std::string name;
26   Logging::GetInstance()->GetMessageText(
27       message.type(), &name, &message, nullptr);
28   return name;
29 }
30 }  // namespace
31 
32 #define EMIT_TRACE_EVENT(message)                                       \
33   TRACE_EVENT_WITH_FLOW1(                                               \
34       "ipc,toplevel", "ChannelReader::DispatchInputData",               \
35       (message).flags(), TRACE_EVENT_FLAG_FLOW_IN, "name",              \
36       GetMessageText(message));
37 #else
38 #define EMIT_TRACE_EVENT(message)                                              \
39   TRACE_EVENT_WITH_FLOW2("ipc,toplevel", "ChannelReader::DispatchInputData",   \
40                          (message).flags(), TRACE_EVENT_FLAG_FLOW_IN, "class", \
41                          IPC_MESSAGE_ID_CLASS((message).type()), "line",       \
42                          IPC_MESSAGE_ID_LINE((message).type()));
43 #endif  // BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
44 
ChannelReader(Listener * listener)45 ChannelReader::ChannelReader(Listener* listener)
46   : listener_(listener),
47     max_input_buffer_size_(Channel::kMaximumReadBufferSize) {
48   memset(input_buf_, 0, sizeof(input_buf_));
49 }
50 
51 ChannelReader::~ChannelReader() = default;
52 
ProcessIncomingMessages()53 ChannelReader::DispatchState ChannelReader::ProcessIncomingMessages() {
54   while (true) {
55     int bytes_read = 0;
56     ReadState read_state = ReadData(input_buf_, Channel::kReadBufferSize,
57                                     &bytes_read);
58     if (read_state == READ_FAILED)
59       return DISPATCH_ERROR;
60     if (read_state == READ_PENDING)
61       return DISPATCH_FINISHED;
62 
63     DCHECK(bytes_read > 0);
64     if (!TranslateInputData(input_buf_, bytes_read))
65       return DISPATCH_ERROR;
66   }
67 }
68 
AsyncReadComplete(int bytes_read)69 ChannelReader::DispatchState ChannelReader::AsyncReadComplete(int bytes_read) {
70   if (!TranslateInputData(input_buf_, bytes_read))
71     return DISPATCH_ERROR;
72 
73   return DISPATCH_FINISHED;
74 }
75 
IsInternalMessage(const Message & m)76 bool ChannelReader::IsInternalMessage(const Message& m) {
77   return m.routing_id() == MSG_ROUTING_NONE &&
78       m.type() >= Channel::CLOSE_FD_MESSAGE_TYPE &&
79       m.type() <= Channel::HELLO_MESSAGE_TYPE;
80 }
81 
IsHelloMessage(const Message & m)82 bool ChannelReader::IsHelloMessage(const Message& m) {
83   return m.routing_id() == MSG_ROUTING_NONE &&
84       m.type() == Channel::HELLO_MESSAGE_TYPE;
85 }
86 
CleanUp()87 void ChannelReader::CleanUp() {
88 }
89 
DispatchMessage(Message * m)90 void ChannelReader::DispatchMessage(Message* m) {
91   EMIT_TRACE_EVENT(*m);
92   listener_->OnMessageReceived(*m);
93   HandleDispatchError(*m);
94 }
95 
TranslateInputData(const char * input_data,int input_data_len)96 bool ChannelReader::TranslateInputData(const char* input_data,
97                                        int input_data_len) {
98   const char* p;
99   const char* end;
100 
101   // Possibly combine with the overflow buffer to make a larger buffer.
102   if (input_overflow_buf_.empty()) {
103     p = input_data;
104     end = input_data + input_data_len;
105   } else {
106     if (!CheckMessageSize(input_overflow_buf_.size() + input_data_len))
107       return false;
108     input_overflow_buf_.append(input_data, input_data_len);
109     p = input_overflow_buf_.data();
110     end = p + input_overflow_buf_.size();
111   }
112 
113   size_t next_message_size = 0;
114 
115   // Dispatch all complete messages in the data buffer.
116   while (p < end) {
117     Message::NextMessageInfo info;
118     Message::FindNext(p, end, &info);
119     if (info.message_found) {
120       int pickle_len = static_cast<int>(info.pickle_end - p);
121       Message translated_message(p, pickle_len);
122 
123       if (!HandleTranslatedMessage(&translated_message))
124         return false;
125 
126       p = info.message_end;
127     } else {
128       // Last message is partial.
129       next_message_size = info.message_size;
130       if (!CheckMessageSize(next_message_size))
131         return false;
132       break;
133     }
134   }
135 
136   // Account for the case where last message's byte is in the next data chunk.
137   size_t next_message_buffer_size = next_message_size ?
138       next_message_size + Channel::kReadBufferSize - 1:
139       0;
140 
141   // Save any partial data in the overflow buffer.
142   if (p != input_overflow_buf_.data())
143     input_overflow_buf_.assign(p, end - p);
144 
145   if (!input_overflow_buf_.empty()) {
146     // We have something in the overflow buffer, which means that we will
147     // append the next data chunk (instead of parsing it directly). So we
148     // resize the buffer to fit the next message, to avoid repeatedly
149     // growing the buffer as we receive all message' data chunks.
150     if (next_message_buffer_size > input_overflow_buf_.capacity()) {
151       input_overflow_buf_.reserve(next_message_buffer_size);
152     }
153   }
154 
155   // Trim the buffer if we can
156   if (next_message_buffer_size < max_input_buffer_size_ &&
157       input_overflow_buf_.size() < max_input_buffer_size_ &&
158       input_overflow_buf_.capacity() > max_input_buffer_size_) {
159     // std::string doesn't really have a method to shrink capacity to
160     // a specific value, so we have to swap with another string.
161     std::string trimmed_buf;
162     trimmed_buf.reserve(max_input_buffer_size_);
163     if (trimmed_buf.capacity() > max_input_buffer_size_) {
164       // Since we don't control how much space reserve() actually reserves,
165       // we have to go other way around and change the max size to avoid
166       // getting into the outer if() again.
167       max_input_buffer_size_ = trimmed_buf.capacity();
168     }
169     trimmed_buf.assign(input_overflow_buf_.data(),
170                        input_overflow_buf_.size());
171     input_overflow_buf_.swap(trimmed_buf);
172   }
173 
174   if (input_overflow_buf_.empty() && !DidEmptyInputBuffers())
175     return false;
176   return true;
177 }
178 
HandleTranslatedMessage(Message * translated_message)179 bool ChannelReader::HandleTranslatedMessage(Message* translated_message) {
180   // Immediately handle internal messages.
181   if (IsInternalMessage(*translated_message)) {
182     EMIT_TRACE_EVENT(*translated_message);
183     HandleInternalMessage(*translated_message);
184     HandleDispatchError(*translated_message);
185     return true;
186   }
187 
188   return HandleExternalMessage(translated_message);
189 }
190 
HandleExternalMessage(Message * external_message)191 bool ChannelReader::HandleExternalMessage(Message* external_message) {
192   if (!GetAttachments(external_message))
193     return false;
194 
195   DispatchMessage(external_message);
196   return true;
197 }
198 
HandleDispatchError(const Message & message)199 void ChannelReader::HandleDispatchError(const Message& message) {
200   if (message.dispatch_error())
201     listener_->OnBadMessageReceived(message);
202 }
203 
CheckMessageSize(size_t size)204 bool ChannelReader::CheckMessageSize(size_t size) {
205   if (size <= Channel::kMaximumMessageSize) {
206     return true;
207   }
208   input_overflow_buf_.clear();
209   LOG(ERROR) << "IPC message is too big: " << size;
210   return false;
211 }
212 
213 }  // namespace internal
214 }  // namespace IPC
215