blob: 83ee495a81313f09ad1bfc675b29f4a685634b67 [file] [log] [blame]
Luis Hector Chavez645501c2016-12-28 10:56:26 -08001// 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_message.h"
6
7#include <limits.h>
8#include <stddef.h>
9#include <stdint.h>
10
11#include "base/atomic_sequence_num.h"
12#include "base/logging.h"
13#include "build/build_config.h"
14#include "ipc/attachment_broker.h"
15#include "ipc/ipc_message_attachment.h"
16#include "ipc/ipc_message_attachment_set.h"
17#include "ipc/placeholder_brokerable_attachment.h"
18
19#if defined(OS_POSIX)
20#include "base/file_descriptor_posix.h"
21#include "ipc/ipc_platform_file_attachment_posix.h"
22#endif
23
24namespace {
25
26base::StaticAtomicSequenceNumber g_ref_num;
27
28// Create a reference number for identifying IPC messages in traces. The return
29// values has the reference number stored in the upper 24 bits, leaving the low
30// 8 bits set to 0 for use as flags.
31inline uint32_t GetRefNumUpper24() {
32 base::trace_event::TraceLog* trace_log =
33 base::trace_event::TraceLog::GetInstance();
34 uint32_t pid = trace_log ? trace_log->process_id() : 0;
35 uint32_t count = g_ref_num.GetNext();
36 // The 24 bit hash is composed of 14 bits of the count and 10 bits of the
37 // Process ID. With the current trace event buffer cap, the 14-bit count did
38 // not appear to wrap during a trace. Note that it is not a big deal if
39 // collisions occur, as this is only used for debugging and trace analysis.
40 return ((pid << 14) | (count & 0x3fff)) << 8;
41}
42
43} // namespace
44
45namespace IPC {
46
47//------------------------------------------------------------------------------
48
49Message::~Message() {
50}
51
52Message::Message() : base::Pickle(sizeof(Header)) {
53 header()->routing = header()->type = 0;
54 header()->flags = GetRefNumUpper24();
55#if USE_ATTACHMENT_BROKER
56 header()->num_brokered_attachments = 0;
57#endif
58#if defined(OS_POSIX)
59 header()->num_fds = 0;
60 header()->pad = 0;
61#endif
62 Init();
63}
64
65Message::Message(int32_t routing_id, uint32_t type, PriorityValue priority)
66 : base::Pickle(sizeof(Header)) {
67 header()->routing = routing_id;
68 header()->type = type;
69 DCHECK((priority & 0xffffff00) == 0);
70 header()->flags = priority | GetRefNumUpper24();
71#if USE_ATTACHMENT_BROKER
72 header()->num_brokered_attachments = 0;
73#endif
74#if defined(OS_POSIX)
75 header()->num_fds = 0;
76 header()->pad = 0;
77#endif
78 Init();
79}
80
81Message::Message(const char* data, int data_len)
82 : base::Pickle(data, data_len) {
83 Init();
84}
85
86Message::Message(const Message& other) : base::Pickle(other) {
87 Init();
88 attachment_set_ = other.attachment_set_;
89 sender_pid_ = other.sender_pid_;
90}
91
92void Message::Init() {
93 dispatch_error_ = false;
94 sender_pid_ = base::kNullProcessId;
95#ifdef IPC_MESSAGE_LOG_ENABLED
96 received_time_ = 0;
97 dont_log_ = false;
98 log_data_ = NULL;
99#endif
100}
101
102Message& Message::operator=(const Message& other) {
103 *static_cast<base::Pickle*>(this) = other;
104 attachment_set_ = other.attachment_set_;
105 sender_pid_ = other.sender_pid_;
106 return *this;
107}
108
109void Message::SetHeaderValues(int32_t routing, uint32_t type, uint32_t flags) {
110 // This should only be called when the message is already empty.
111 DCHECK(payload_size() == 0);
112
113 header()->routing = routing;
114 header()->type = type;
115 header()->flags = flags;
116}
117
118void Message::EnsureMessageAttachmentSet() {
119 if (attachment_set_.get() == NULL)
120 attachment_set_ = new MessageAttachmentSet;
121}
122
123#ifdef IPC_MESSAGE_LOG_ENABLED
124void Message::set_sent_time(int64_t time) {
125 DCHECK((header()->flags & HAS_SENT_TIME_BIT) == 0);
126 header()->flags |= HAS_SENT_TIME_BIT;
127 WriteInt64(time);
128}
129
130int64_t Message::sent_time() const {
131 if ((header()->flags & HAS_SENT_TIME_BIT) == 0)
132 return 0;
133
134 const char* data = end_of_payload();
135 data -= sizeof(int64_t);
136 return *(reinterpret_cast<const int64_t*>(data));
137}
138
139void Message::set_received_time(int64_t time) const {
140 received_time_ = time;
141}
142#endif
143
144Message::NextMessageInfo::NextMessageInfo()
145 : message_size(0), message_found(false), pickle_end(nullptr),
146 message_end(nullptr) {}
147Message::NextMessageInfo::~NextMessageInfo() {}
148
149Message::SerializedAttachmentIds
150Message::SerializedIdsOfBrokerableAttachments() {
151 DCHECK(HasBrokerableAttachments());
152 std::vector<scoped_refptr<IPC::BrokerableAttachment>> attachments(
153 attachment_set_->GetBrokerableAttachments());
154 CHECK_LE(attachments.size(), std::numeric_limits<size_t>::max() /
155 BrokerableAttachment::kNonceSize);
156 size_t size = attachments.size() * BrokerableAttachment::kNonceSize;
157 char* buffer = static_cast<char*>(malloc(size));
158 for (size_t i = 0; i < attachments.size(); ++i) {
159 char* start_range = buffer + i * BrokerableAttachment::kNonceSize;
160 BrokerableAttachment::AttachmentId id = attachments[i]->GetIdentifier();
161 id.SerializeToBuffer(start_range, BrokerableAttachment::kNonceSize);
162 }
163 SerializedAttachmentIds ids;
164 ids.buffer = buffer;
165 ids.size = size;
166 return ids;
167}
168
169// static
170void Message::FindNext(const char* range_start,
171 const char* range_end,
172 NextMessageInfo* info) {
173 DCHECK(info);
174 info->message_found = false;
175 info->message_size = 0;
176
177 size_t pickle_size = 0;
178 if (!base::Pickle::PeekNext(sizeof(Header),
179 range_start, range_end, &pickle_size))
180 return;
181
182 bool have_entire_pickle =
183 static_cast<size_t>(range_end - range_start) >= pickle_size;
184
185#if USE_ATTACHMENT_BROKER
186 // TODO(dskiba): determine message_size when entire pickle is not available
187
188 if (!have_entire_pickle)
189 return;
190
191 const char* pickle_end = range_start + pickle_size;
192
193 // The data is not copied.
194 Message message(range_start, static_cast<int>(pickle_size));
195 size_t num_attachments = message.header()->num_brokered_attachments;
196
197 // Check for possible overflows.
198 size_t max_size_t = std::numeric_limits<size_t>::max();
199 if (num_attachments >= max_size_t / BrokerableAttachment::kNonceSize)
200 return;
201
202 size_t attachment_length = num_attachments * BrokerableAttachment::kNonceSize;
203 if (pickle_size > max_size_t - attachment_length)
204 return;
205
206 // Check whether the range includes the attachments.
207 size_t buffer_length = static_cast<size_t>(range_end - range_start);
208 if (buffer_length < attachment_length + pickle_size)
209 return;
210
211 for (size_t i = 0; i < num_attachments; ++i) {
212 const char* attachment_start =
213 pickle_end + i * BrokerableAttachment::kNonceSize;
214 BrokerableAttachment::AttachmentId id(attachment_start,
215 BrokerableAttachment::kNonceSize);
216 info->attachment_ids.push_back(id);
217 }
218 info->message_end =
219 pickle_end + num_attachments * BrokerableAttachment::kNonceSize;
220 info->message_size = info->message_end - range_start;
221#else
222 info->message_size = pickle_size;
223
224 if (!have_entire_pickle)
225 return;
226
227 const char* pickle_end = range_start + pickle_size;
228
229 info->message_end = pickle_end;
230#endif // USE_ATTACHMENT_BROKER
231
232 info->pickle_end = pickle_end;
233 info->message_found = true;
234}
235
236bool Message::AddPlaceholderBrokerableAttachmentWithId(
237 BrokerableAttachment::AttachmentId id) {
238 scoped_refptr<PlaceholderBrokerableAttachment> attachment(
239 new PlaceholderBrokerableAttachment(id));
240 return attachment_set()->AddAttachment(attachment);
241}
242
243bool Message::WriteAttachment(
244 scoped_refptr<base::Pickle::Attachment> attachment) {
245 bool brokerable;
246 size_t index;
247 bool success = attachment_set()->AddAttachment(
248 make_scoped_refptr(static_cast<MessageAttachment*>(attachment.get())),
249 &index, &brokerable);
250 DCHECK(success);
251
252 // NOTE: If you add more data to the pickle, make sure to update
253 // PickleSizer::AddAttachment.
254
255 // Write the type of descriptor.
256 WriteBool(brokerable);
257
258 // Write the index of the descriptor so that we don't have to
259 // keep the current descriptor as extra decoding state when deserialising.
260 WriteInt(static_cast<int>(index));
261
262#if USE_ATTACHMENT_BROKER
263 if (brokerable)
264 header()->num_brokered_attachments++;
265#endif
266
267 return success;
268}
269
270bool Message::ReadAttachment(
271 base::PickleIterator* iter,
272 scoped_refptr<base::Pickle::Attachment>* attachment) const {
273 bool brokerable;
274 if (!iter->ReadBool(&brokerable))
275 return false;
276
277 int index;
278 if (!iter->ReadInt(&index))
279 return false;
280
281 MessageAttachmentSet* attachment_set = attachment_set_.get();
282 if (!attachment_set)
283 return false;
284
285 *attachment = brokerable
286 ? attachment_set->GetBrokerableAttachmentAt(index)
287 : attachment_set->GetNonBrokerableAttachmentAt(index);
288
289 return nullptr != attachment->get();
290}
291
292bool Message::HasAttachments() const {
293 return attachment_set_.get() && !attachment_set_->empty();
294}
295
296bool Message::HasMojoHandles() const {
297 return attachment_set_.get() && attachment_set_->num_mojo_handles() > 0;
298}
299
300bool Message::HasBrokerableAttachments() const {
301 return attachment_set_.get() &&
302 attachment_set_->num_brokerable_attachments() > 0;
303}
304
305} // namespace IPC