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 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 306