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.
5 #include "ipc/ipc_channel_reader.h"
9 #include "ipc/ipc_listener.h"
10 #include "ipc/ipc_logging.h"
11 #include "ipc/ipc_message.h"
12 #include "ipc/ipc_message_attachment_set.h"
13 #include "ipc/ipc_message_macros.h"
18 ChannelReader::ChannelReader(Listener
* listener
) : listener_(listener
) {
19 memset(input_buf_
, 0, sizeof(input_buf_
));
22 ChannelReader::~ChannelReader() {
23 DCHECK(blocked_ids_
.empty());
26 ChannelReader::DispatchState
ChannelReader::ProcessIncomingMessages() {
29 ReadState read_state
= ReadData(input_buf_
, Channel::kReadBufferSize
,
31 if (read_state
== READ_FAILED
)
32 return DISPATCH_ERROR
;
33 if (read_state
== READ_PENDING
)
34 return DISPATCH_FINISHED
;
36 DCHECK(bytes_read
> 0);
37 if (!TranslateInputData(input_buf_
, bytes_read
))
38 return DISPATCH_ERROR
;
40 DispatchState state
= DispatchMessages();
41 if (state
!= DISPATCH_FINISHED
)
46 ChannelReader::DispatchState
ChannelReader::AsyncReadComplete(int bytes_read
) {
47 if (!TranslateInputData(input_buf_
, bytes_read
))
48 return DISPATCH_ERROR
;
50 return DispatchMessages();
53 bool ChannelReader::IsInternalMessage(const Message
& m
) {
54 return m
.routing_id() == MSG_ROUTING_NONE
&&
55 m
.type() >= Channel::CLOSE_FD_MESSAGE_TYPE
&&
56 m
.type() <= Channel::HELLO_MESSAGE_TYPE
;
59 bool ChannelReader::IsHelloMessage(const Message
& m
) {
60 return m
.routing_id() == MSG_ROUTING_NONE
&&
61 m
.type() == Channel::HELLO_MESSAGE_TYPE
;
64 bool ChannelReader::TranslateInputData(const char* input_data
,
69 // Possibly combine with the overflow buffer to make a larger buffer.
70 if (input_overflow_buf_
.empty()) {
72 end
= input_data
+ input_data_len
;
74 if (input_overflow_buf_
.size() + input_data_len
>
75 Channel::kMaximumMessageSize
) {
76 input_overflow_buf_
.clear();
77 LOG(ERROR
) << "IPC message is too big";
80 input_overflow_buf_
.append(input_data
, input_data_len
);
81 p
= input_overflow_buf_
.data();
82 end
= p
+ input_overflow_buf_
.size();
85 // Dispatch all complete messages in the data buffer.
87 Message::NextMessageInfo info
= Message::FindNext(p
, end
);
88 if (info
.message_found
) {
89 int pickle_len
= static_cast<int>(info
.pickle_end
- p
);
90 Message
translated_message(p
, pickle_len
);
92 for (const auto& id
: info
.attachment_ids
)
93 translated_message
.AddPlaceholderBrokerableAttachmentWithId(id
);
95 if (!GetNonBrokeredAttachments(&translated_message
))
98 // If there are no queued messages, attempt to immediately dispatch the
99 // newly translated message.
100 if (queued_messages_
.empty()) {
101 DCHECK(blocked_ids_
.empty());
102 AttachmentIdSet blocked_ids
=
103 GetBrokeredAttachments(&translated_message
);
105 if (blocked_ids
.empty()) {
106 // Dispatch the message and continue the loop.
107 DispatchMessage(&translated_message
);
108 p
= info
.message_end
;
112 blocked_ids_
.swap(blocked_ids
);
113 StartObservingAttachmentBroker();
116 // Make a deep copy of |translated_message| to add to the queue.
117 scoped_ptr
<Message
> m(new Message(translated_message
));
118 queued_messages_
.push_back(m
.release());
119 p
= info
.message_end
;
121 // Last message is partial.
126 // Save any partial data in the overflow buffer.
127 input_overflow_buf_
.assign(p
, end
- p
);
129 if (input_overflow_buf_
.empty() && !DidEmptyInputBuffers())
134 ChannelReader::DispatchState
ChannelReader::DispatchMessages() {
135 while (!queued_messages_
.empty()) {
136 if (!blocked_ids_
.empty())
137 return DISPATCH_WAITING_ON_BROKER
;
139 Message
* m
= queued_messages_
.front();
141 AttachmentIdSet blocked_ids
= GetBrokeredAttachments(m
);
142 if (!blocked_ids
.empty()) {
143 blocked_ids_
.swap(blocked_ids
);
144 StartObservingAttachmentBroker();
145 return DISPATCH_WAITING_ON_BROKER
;
149 queued_messages_
.erase(queued_messages_
.begin());
151 return DISPATCH_FINISHED
;
154 void ChannelReader::CleanUp() {
155 if (!blocked_ids_
.empty()) {
156 StopObservingAttachmentBroker();
157 blocked_ids_
.clear();
161 void ChannelReader::DispatchMessage(Message
* m
) {
162 m
->set_sender_pid(GetSenderPID());
164 #ifdef IPC_MESSAGE_LOG_ENABLED
166 Logging::GetInstance()->GetMessageText(m
->type(), &name
, m
, NULL
);
167 TRACE_EVENT_WITH_FLOW1("ipc,toplevel",
168 "ChannelReader::DispatchInputData",
170 TRACE_EVENT_FLAG_FLOW_IN
,
173 TRACE_EVENT_WITH_FLOW2("ipc,toplevel",
174 "ChannelReader::DispatchInputData",
176 TRACE_EVENT_FLAG_FLOW_IN
,
177 "class", IPC_MESSAGE_ID_CLASS(m
->type()),
178 "line", IPC_MESSAGE_ID_LINE(m
->type()));
181 bool handled
= false;
182 if (IsInternalMessage(*m
)) {
183 HandleInternalMessage(*m
);
186 #if USE_ATTACHMENT_BROKER
187 if (!handled
&& IsAttachmentBrokerEndpoint() && GetAttachmentBroker()) {
188 handled
= GetAttachmentBroker()->OnMessageReceived(*m
);
190 #endif // USE_ATTACHMENT_BROKER
192 listener_
->OnMessageReceived(*m
);
193 if (m
->dispatch_error())
194 listener_
->OnBadMessageReceived(*m
);
197 ChannelReader::AttachmentIdSet
ChannelReader::GetBrokeredAttachments(
199 std::set
<BrokerableAttachment::AttachmentId
> blocked_ids
;
201 #if USE_ATTACHMENT_BROKER
202 MessageAttachmentSet
* set
= msg
->attachment_set();
203 std::vector
<const BrokerableAttachment
*> brokerable_attachments_copy
=
204 set
->PeekBrokerableAttachments();
205 for (const BrokerableAttachment
* attachment
: brokerable_attachments_copy
) {
206 if (attachment
->NeedsBrokering()) {
207 AttachmentBroker
* broker
= GetAttachmentBroker();
208 scoped_refptr
<BrokerableAttachment
> brokered_attachment
;
209 bool result
= broker
->GetAttachmentWithId(attachment
->GetIdentifier(),
210 &brokered_attachment
);
212 blocked_ids
.insert(attachment
->GetIdentifier());
216 set
->ReplacePlaceholderWithAttachment(brokered_attachment
);
219 #endif // USE_ATTACHMENT_BROKER
224 void ChannelReader::ReceivedBrokerableAttachmentWithId(
225 const BrokerableAttachment::AttachmentId
& id
) {
226 if (blocked_ids_
.empty())
229 auto it
= find(blocked_ids_
.begin(), blocked_ids_
.end(), id
);
230 if (it
!= blocked_ids_
.end())
231 blocked_ids_
.erase(it
);
233 if (blocked_ids_
.empty()) {
234 StopObservingAttachmentBroker();
239 void ChannelReader::StartObservingAttachmentBroker() {
240 #if USE_ATTACHMENT_BROKER
241 GetAttachmentBroker()->AddObserver(this);
242 #endif // USE_ATTACHMENT_BROKER
245 void ChannelReader::StopObservingAttachmentBroker() {
246 #if USE_ATTACHMENT_BROKER
247 GetAttachmentBroker()->RemoveObserver(this);
248 #endif // USE_ATTACHMENT_BROKER
251 } // namespace internal