Home | History | Annotate | Download | only in ipc
      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.
     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 
     49 Message::~Message() {
     50 }
     51 
     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 
     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 
     81 Message::Message(const char* data, int data_len)
     82     : base::Pickle(data, data_len) {
     83   Init();
     84 }
     85 
     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 
     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 
    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 
    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 
    118 void Message::EnsureMessageAttachmentSet() {
    119   if (attachment_set_.get() == NULL)
    120     attachment_set_ = new MessageAttachmentSet;
    121 }
    122 
    123 #ifdef IPC_MESSAGE_LOG_ENABLED
    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 
    130 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 
    139 void Message::set_received_time(int64_t time) const {
    140   received_time_ = time;
    141 }
    142 #endif
    143 
    144 Message::NextMessageInfo::NextMessageInfo()
    145     : message_size(0), message_found(false), pickle_end(nullptr),
    146       message_end(nullptr) {}
    147 Message::NextMessageInfo::~NextMessageInfo() {}
    148 
    149 Message::SerializedAttachmentIds
    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
    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 
    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 
    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 
    270 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 
    292 bool Message::HasAttachments() const {
    293   return attachment_set_.get() && !attachment_set_->empty();
    294 }
    295 
    296 bool Message::HasMojoHandles() const {
    297   return attachment_set_.get() && attachment_set_->num_mojo_handles() > 0;
    298 }
    299 
    300 bool Message::HasBrokerableAttachments() const {
    301   return attachment_set_.get() &&
    302          attachment_set_->num_brokerable_attachments() > 0;
    303 }
    304 
    305 }  // namespace IPC
    306