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 "base/atomic_sequence_num.h"
      8 #include "base/logging.h"
      9 #include "build/build_config.h"
     10 
     11 #if defined(OS_POSIX)
     12 #include "base/file_descriptor_posix.h"
     13 #include "ipc/file_descriptor_set_posix.h"
     14 #endif
     15 
     16 namespace {
     17 
     18 base::StaticAtomicSequenceNumber g_ref_num;
     19 
     20 // Create a reference number for identifying IPC messages in traces. The return
     21 // values has the reference number stored in the upper 24 bits, leaving the low
     22 // 8 bits set to 0 for use as flags.
     23 inline uint32 GetRefNumUpper24() {
     24   base::debug::TraceLog* trace_log = base::debug::TraceLog::GetInstance();
     25   int32 pid = trace_log ? trace_log->process_id() : 0;
     26   int32 count = g_ref_num.GetNext();
     27   // The 24 bit hash is composed of 14 bits of the count and 10 bits of the
     28   // Process ID. With the current trace event buffer cap, the 14-bit count did
     29   // not appear to wrap during a trace. Note that it is not a big deal if
     30   // collisions occur, as this is only used for debugging and trace analysis.
     31   return ((pid << 14) | (count & 0x3fff)) << 8;
     32 }
     33 
     34 }  // namespace
     35 
     36 namespace IPC {
     37 
     38 //------------------------------------------------------------------------------
     39 
     40 Message::~Message() {
     41 }
     42 
     43 Message::Message()
     44     : Pickle(sizeof(Header)) {
     45   header()->routing = header()->type = 0;
     46   header()->flags = GetRefNumUpper24();
     47 #if defined(OS_POSIX)
     48   header()->num_fds = 0;
     49   header()->pad = 0;
     50 #endif
     51   Init();
     52 }
     53 
     54 Message::Message(int32 routing_id, uint32 type, PriorityValue priority)
     55     : Pickle(sizeof(Header)) {
     56   header()->routing = routing_id;
     57   header()->type = type;
     58   DCHECK((priority & 0xffffff00) == 0);
     59   header()->flags = priority | GetRefNumUpper24();
     60 #if defined(OS_POSIX)
     61   header()->num_fds = 0;
     62   header()->pad = 0;
     63 #endif
     64   Init();
     65 }
     66 
     67 Message::Message(const char* data, int data_len) : Pickle(data, data_len) {
     68   Init();
     69 }
     70 
     71 Message::Message(const Message& other) : Pickle(other) {
     72   Init();
     73 #if defined(OS_POSIX)
     74   file_descriptor_set_ = other.file_descriptor_set_;
     75 #endif
     76 }
     77 
     78 void Message::Init() {
     79   dispatch_error_ = false;
     80 #ifdef IPC_MESSAGE_LOG_ENABLED
     81   received_time_ = 0;
     82   dont_log_ = false;
     83   log_data_ = NULL;
     84 #endif
     85 }
     86 
     87 Message& Message::operator=(const Message& other) {
     88   *static_cast<Pickle*>(this) = other;
     89 #if defined(OS_POSIX)
     90   file_descriptor_set_ = other.file_descriptor_set_;
     91 #endif
     92   return *this;
     93 }
     94 
     95 void Message::SetHeaderValues(int32 routing, uint32 type, uint32 flags) {
     96   // This should only be called when the message is already empty.
     97   DCHECK(payload_size() == 0);
     98 
     99   header()->routing = routing;
    100   header()->type = type;
    101   header()->flags = flags;
    102 }
    103 
    104 #ifdef IPC_MESSAGE_LOG_ENABLED
    105 void Message::set_sent_time(int64 time) {
    106   DCHECK((header()->flags & HAS_SENT_TIME_BIT) == 0);
    107   header()->flags |= HAS_SENT_TIME_BIT;
    108   WriteInt64(time);
    109 }
    110 
    111 int64 Message::sent_time() const {
    112   if ((header()->flags & HAS_SENT_TIME_BIT) == 0)
    113     return 0;
    114 
    115   const char* data = end_of_payload();
    116   data -= sizeof(int64);
    117   return *(reinterpret_cast<const int64*>(data));
    118 }
    119 
    120 void Message::set_received_time(int64 time) const {
    121   received_time_ = time;
    122 }
    123 #endif
    124 
    125 #if defined(OS_POSIX)
    126 bool Message::WriteFile(base::ScopedFD descriptor) {
    127   // We write the index of the descriptor so that we don't have to
    128   // keep the current descriptor as extra decoding state when deserialising.
    129   WriteInt(file_descriptor_set()->size());
    130   return file_descriptor_set()->AddToOwn(descriptor.Pass());
    131 }
    132 
    133 bool Message::WriteBorrowingFile(const base::PlatformFile& descriptor) {
    134   // We write the index of the descriptor so that we don't have to
    135   // keep the current descriptor as extra decoding state when deserialising.
    136   WriteInt(file_descriptor_set()->size());
    137   return file_descriptor_set()->AddToBorrow(descriptor);
    138 }
    139 
    140 bool Message::ReadFile(PickleIterator* iter, base::ScopedFD* descriptor) const {
    141   int descriptor_index;
    142   if (!ReadInt(iter, &descriptor_index))
    143     return false;
    144 
    145   FileDescriptorSet* file_descriptor_set = file_descriptor_set_.get();
    146   if (!file_descriptor_set)
    147     return false;
    148 
    149   base::PlatformFile file =
    150       file_descriptor_set->TakeDescriptorAt(descriptor_index);
    151   if (file < 0)
    152     return false;
    153 
    154   descriptor->reset(file);
    155   return true;
    156 }
    157 
    158 bool Message::HasFileDescriptors() const {
    159   return file_descriptor_set_.get() && !file_descriptor_set_->empty();
    160 }
    161 
    162 void Message::EnsureFileDescriptorSet() {
    163   if (file_descriptor_set_.get() == NULL)
    164     file_descriptor_set_ = new FileDescriptorSet;
    165 }
    166 
    167 #endif
    168 
    169 }  // namespace IPC
    170