• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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