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 if (!blocked_ids_
.empty())
24 StopObservingAttachmentBroker();
27 ChannelReader::DispatchState
ChannelReader::ProcessIncomingMessages() {
30 ReadState read_state
= ReadData(input_buf_
, Channel::kReadBufferSize
,
32 if (read_state
== READ_FAILED
)
33 return DISPATCH_ERROR
;
34 if (read_state
== READ_PENDING
)
35 return DISPATCH_FINISHED
;
37 DCHECK(bytes_read
> 0);
38 if (!TranslateInputData(input_buf_
, bytes_read
))
39 return DISPATCH_ERROR
;
41 DispatchState state
= DispatchMessages();
42 if (state
!= DISPATCH_FINISHED
)
47 ChannelReader::DispatchState
ChannelReader::AsyncReadComplete(int bytes_read
) {
48 if (!TranslateInputData(input_buf_
, bytes_read
))
49 return DISPATCH_ERROR
;
51 return DispatchMessages();
54 bool ChannelReader::IsInternalMessage(const Message
& m
) {
55 return m
.routing_id() == MSG_ROUTING_NONE
&&
56 m
.type() >= Channel::CLOSE_FD_MESSAGE_TYPE
&&
57 m
.type() <= Channel::HELLO_MESSAGE_TYPE
;
60 bool ChannelReader::IsHelloMessage(const Message
& m
) {
61 return m
.routing_id() == MSG_ROUTING_NONE
&&
62 m
.type() == Channel::HELLO_MESSAGE_TYPE
;
65 bool ChannelReader::TranslateInputData(const char* input_data
,
70 // Possibly combine with the overflow buffer to make a larger buffer.
71 if (input_overflow_buf_
.empty()) {
73 end
= input_data
+ input_data_len
;
75 if (input_overflow_buf_
.size() + input_data_len
>
76 Channel::kMaximumMessageSize
) {
77 input_overflow_buf_
.clear();
78 LOG(ERROR
) << "IPC message is too big";
81 input_overflow_buf_
.append(input_data
, input_data_len
);
82 p
= input_overflow_buf_
.data();
83 end
= p
+ input_overflow_buf_
.size();
86 // Dispatch all complete messages in the data buffer.
88 const char* message_tail
= Message::FindNext(p
, end
);
90 int len
= static_cast<int>(message_tail
- p
);
92 Message
translated_message(p
, len
);
93 if (!GetNonBrokeredAttachments(&translated_message
))
96 // If there are no queued messages, attempt to immediately dispatch the
97 // newly translated message.
98 if (queued_messages_
.empty()) {
99 DCHECK(blocked_ids_
.empty());
100 AttachmentIdSet blocked_ids
=
101 GetBrokeredAttachments(&translated_message
);
103 if (blocked_ids
.empty()) {
104 // Dispatch the message and continue the loop.
105 DispatchMessage(&translated_message
);
110 blocked_ids_
.swap(blocked_ids
);
111 StartObservingAttachmentBroker();
114 // Make a deep copy of |translated_message| to add to the queue.
115 scoped_ptr
<Message
> m(new Message(translated_message
));
116 queued_messages_
.push_back(m
.release());
119 // Last message is partial.
124 // Save any partial data in the overflow buffer.
125 input_overflow_buf_
.assign(p
, end
- p
);
127 if (input_overflow_buf_
.empty() && !DidEmptyInputBuffers())
132 ChannelReader::DispatchState
ChannelReader::DispatchMessages() {
133 while (!queued_messages_
.empty()) {
134 if (!blocked_ids_
.empty())
135 return DISPATCH_WAITING_ON_BROKER
;
137 Message
* m
= queued_messages_
.front();
139 AttachmentIdSet blocked_ids
= GetBrokeredAttachments(m
);
140 if (!blocked_ids
.empty()) {
141 blocked_ids_
.swap(blocked_ids
);
142 StartObservingAttachmentBroker();
143 return DISPATCH_WAITING_ON_BROKER
;
147 queued_messages_
.erase(queued_messages_
.begin());
149 return DISPATCH_FINISHED
;
152 void ChannelReader::DispatchMessage(Message
* m
) {
153 m
->set_sender_pid(GetSenderPID());
155 #ifdef IPC_MESSAGE_LOG_ENABLED
157 Logging::GetInstance()->GetMessageText(m
->type(), &name
, m
, NULL
);
158 TRACE_EVENT_WITH_FLOW1("ipc,toplevel",
159 "ChannelReader::DispatchInputData",
161 TRACE_EVENT_FLAG_FLOW_IN
,
164 TRACE_EVENT_WITH_FLOW2("ipc,toplevel",
165 "ChannelReader::DispatchInputData",
167 TRACE_EVENT_FLAG_FLOW_IN
,
168 "class", IPC_MESSAGE_ID_CLASS(m
->type()),
169 "line", IPC_MESSAGE_ID_LINE(m
->type()));
172 bool handled
= false;
173 if (IsInternalMessage(*m
)) {
174 HandleInternalMessage(*m
);
177 #if USE_ATTACHMENT_BROKER
178 if (!handled
&& IsAttachmentBrokerEndpoint() && GetAttachmentBroker()) {
179 handled
= GetAttachmentBroker()->OnMessageReceived(*m
);
181 #endif // USE_ATTACHMENT_BROKER
183 listener_
->OnMessageReceived(*m
);
184 if (m
->dispatch_error())
185 listener_
->OnBadMessageReceived(*m
);
188 ChannelReader::AttachmentIdSet
ChannelReader::GetBrokeredAttachments(
190 std::set
<BrokerableAttachment::AttachmentId
> blocked_ids
;
192 #if USE_ATTACHMENT_BROKER
193 MessageAttachmentSet
* set
= msg
->attachment_set();
194 for (const scoped_refptr
<BrokerableAttachment
>& attachment
:
195 set
->GetBrokerableAttachmentsForUpdating()) {
196 if (attachment
->NeedsBrokering()) {
197 AttachmentBroker
* broker
= GetAttachmentBroker();
198 scoped_refptr
<BrokerableAttachment
> brokered_attachment
;
199 bool result
= broker
->GetAttachmentWithId(attachment
->GetIdentifier(),
200 &brokered_attachment
);
202 blocked_ids
.insert(attachment
->GetIdentifier());
206 attachment
->PopulateWithAttachment(brokered_attachment
.get());
209 #endif // USE_ATTACHMENT_BROKER
214 void ChannelReader::ReceivedBrokerableAttachmentWithId(
215 const BrokerableAttachment::AttachmentId
& id
) {
216 if (blocked_ids_
.empty())
219 auto it
= find(blocked_ids_
.begin(), blocked_ids_
.end(), id
);
220 if (it
!= blocked_ids_
.end())
221 blocked_ids_
.erase(it
);
223 if (blocked_ids_
.empty()) {
224 StopObservingAttachmentBroker();
229 void ChannelReader::StartObservingAttachmentBroker() {
230 #if USE_ATTACHMENT_BROKER
231 GetAttachmentBroker()->AddObserver(this);
232 #endif // USE_ATTACHMENT_BROKER
235 void ChannelReader::StopObservingAttachmentBroker() {
236 #if USE_ATTACHMENT_BROKER
237 GetAttachmentBroker()->RemoveObserver(this);
238 #endif // USE_ATTACHMENT_BROKER
241 } // namespace internal