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_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
24 namespace {
25
26 base::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.
GetRefNumUpper24()31 inline 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
45 namespace IPC {
46
47 //------------------------------------------------------------------------------
48
~Message()49 Message::~Message() {
50 }
51
Message()52 Message::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
Message(int32_t routing_id,uint32_t type,PriorityValue priority)65 Message::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
Message(const char * data,int data_len)81 Message::Message(const char* data, int data_len)
82 : base::Pickle(data, data_len) {
83 Init();
84 }
85
Message(const Message & other)86 Message::Message(const Message& other) : base::Pickle(other) {
87 Init();
88 attachment_set_ = other.attachment_set_;
89 sender_pid_ = other.sender_pid_;
90 }
91
Init()92 void 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
operator =(const Message & other)102 Message& 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
SetHeaderValues(int32_t routing,uint32_t type,uint32_t flags)109 void 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
EnsureMessageAttachmentSet()118 void Message::EnsureMessageAttachmentSet() {
119 if (attachment_set_.get() == NULL)
120 attachment_set_ = new MessageAttachmentSet;
121 }
122
123 #ifdef IPC_MESSAGE_LOG_ENABLED
set_sent_time(int64_t time)124 void 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
sent_time() const130 int64_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
set_received_time(int64_t time) const139 void Message::set_received_time(int64_t time) const {
140 received_time_ = time;
141 }
142 #endif
143
NextMessageInfo()144 Message::NextMessageInfo::NextMessageInfo()
145 : message_size(0), message_found(false), pickle_end(nullptr),
146 message_end(nullptr) {}
~NextMessageInfo()147 Message::NextMessageInfo::~NextMessageInfo() {}
148
149 Message::SerializedAttachmentIds
SerializedIdsOfBrokerableAttachments()150 Message::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
FindNext(const char * range_start,const char * range_end,NextMessageInfo * info)170 void 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
AddPlaceholderBrokerableAttachmentWithId(BrokerableAttachment::AttachmentId id)236 bool Message::AddPlaceholderBrokerableAttachmentWithId(
237 BrokerableAttachment::AttachmentId id) {
238 scoped_refptr<PlaceholderBrokerableAttachment> attachment(
239 new PlaceholderBrokerableAttachment(id));
240 return attachment_set()->AddAttachment(attachment);
241 }
242
WriteAttachment(scoped_refptr<base::Pickle::Attachment> attachment)243 bool 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
ReadAttachment(base::PickleIterator * iter,scoped_refptr<base::Pickle::Attachment> * attachment) const270 bool 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
HasAttachments() const292 bool Message::HasAttachments() const {
293 return attachment_set_.get() && !attachment_set_->empty();
294 }
295
HasMojoHandles() const296 bool Message::HasMojoHandles() const {
297 return attachment_set_.get() && attachment_set_->num_mojo_handles() > 0;
298 }
299
HasBrokerableAttachments() const300 bool Message::HasBrokerableAttachments() const {
301 return attachment_set_.get() &&
302 attachment_set_->num_brokerable_attachments() > 0;
303 }
304
305 } // namespace IPC
306