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/ipc_message_attachment.h" 15 #include "ipc/ipc_message_attachment_set.h" 16 17 #if defined(OS_POSIX) 18 #include "base/file_descriptor_posix.h" 19 #include "ipc/ipc_platform_file_attachment_posix.h" 20 #endif 21 22 namespace { 23 24 base::StaticAtomicSequenceNumber g_ref_num; 25 26 // Create a reference number for identifying IPC messages in traces. The return 27 // values has the reference number stored in the upper 24 bits, leaving the low 28 // 8 bits set to 0 for use as flags. 29 inline uint32_t GetRefNumUpper24() { 30 base::trace_event::TraceLog* trace_log = 31 base::trace_event::TraceLog::GetInstance(); 32 uint32_t pid = trace_log ? trace_log->process_id() : 0; 33 uint32_t count = g_ref_num.GetNext(); 34 // The 24 bit hash is composed of 14 bits of the count and 10 bits of the 35 // Process ID. With the current trace event buffer cap, the 14-bit count did 36 // not appear to wrap during a trace. Note that it is not a big deal if 37 // collisions occur, as this is only used for debugging and trace analysis. 38 return ((pid << 14) | (count & 0x3fff)) << 8; 39 } 40 41 } // namespace 42 43 namespace IPC { 44 45 //------------------------------------------------------------------------------ 46 47 Message::~Message() { 48 } 49 50 Message::Message() : base::Pickle(sizeof(Header)) { 51 header()->routing = header()->type = 0; 52 header()->flags = GetRefNumUpper24(); 53 #if defined(OS_POSIX) 54 header()->num_fds = 0; 55 header()->pad = 0; 56 #endif 57 Init(); 58 } 59 60 Message::Message(int32_t routing_id, uint32_t type, PriorityValue priority) 61 : base::Pickle(sizeof(Header)) { 62 header()->routing = routing_id; 63 header()->type = type; 64 DCHECK((priority & 0xffffff00) == 0); 65 header()->flags = priority | GetRefNumUpper24(); 66 #if defined(OS_POSIX) 67 header()->num_fds = 0; 68 header()->pad = 0; 69 #endif 70 Init(); 71 } 72 73 Message::Message(const char* data, int data_len) 74 : base::Pickle(data, data_len) { 75 Init(); 76 } 77 78 Message::Message(const Message& other) : base::Pickle(other) { 79 Init(); 80 attachment_set_ = other.attachment_set_; 81 } 82 83 void Message::Init() { 84 dispatch_error_ = false; 85 #ifdef IPC_MESSAGE_LOG_ENABLED 86 received_time_ = 0; 87 dont_log_ = false; 88 log_data_ = NULL; 89 #endif 90 } 91 92 Message& Message::operator=(const Message& other) { 93 *static_cast<base::Pickle*>(this) = other; 94 attachment_set_ = other.attachment_set_; 95 return *this; 96 } 97 98 void Message::SetHeaderValues(int32_t routing, uint32_t type, uint32_t flags) { 99 // This should only be called when the message is already empty. 100 DCHECK(payload_size() == 0); 101 102 header()->routing = routing; 103 header()->type = type; 104 header()->flags = flags; 105 } 106 107 void Message::EnsureMessageAttachmentSet() { 108 if (attachment_set_.get() == NULL) 109 attachment_set_ = new MessageAttachmentSet; 110 } 111 112 #ifdef IPC_MESSAGE_LOG_ENABLED 113 void Message::set_sent_time(int64_t time) { 114 DCHECK((header()->flags & HAS_SENT_TIME_BIT) == 0); 115 header()->flags |= HAS_SENT_TIME_BIT; 116 WriteInt64(time); 117 } 118 119 int64_t Message::sent_time() const { 120 if ((header()->flags & HAS_SENT_TIME_BIT) == 0) 121 return 0; 122 123 const char* data = end_of_payload(); 124 data -= sizeof(int64_t); 125 return *(reinterpret_cast<const int64_t*>(data)); 126 } 127 128 void Message::set_received_time(int64_t time) const { 129 received_time_ = time; 130 } 131 #endif 132 133 Message::NextMessageInfo::NextMessageInfo() 134 : message_size(0), message_found(false), pickle_end(nullptr), 135 message_end(nullptr) {} 136 Message::NextMessageInfo::~NextMessageInfo() {} 137 138 // static 139 void Message::FindNext(const char* range_start, 140 const char* range_end, 141 NextMessageInfo* info) { 142 DCHECK(info); 143 info->message_found = false; 144 info->message_size = 0; 145 146 size_t pickle_size = 0; 147 if (!base::Pickle::PeekNext(sizeof(Header), 148 range_start, range_end, &pickle_size)) 149 return; 150 151 bool have_entire_pickle = 152 static_cast<size_t>(range_end - range_start) >= pickle_size; 153 154 info->message_size = pickle_size; 155 156 if (!have_entire_pickle) 157 return; 158 159 const char* pickle_end = range_start + pickle_size; 160 161 info->message_end = pickle_end; 162 163 info->pickle_end = pickle_end; 164 info->message_found = true; 165 } 166 167 bool Message::WriteAttachment( 168 scoped_refptr<base::Pickle::Attachment> attachment) { 169 size_t index; 170 bool success = attachment_set()->AddAttachment( 171 make_scoped_refptr(static_cast<MessageAttachment*>(attachment.get())), 172 &index); 173 DCHECK(success); 174 175 // NOTE: If you add more data to the pickle, make sure to update 176 // PickleSizer::AddAttachment. 177 178 // Write the index of the descriptor so that we don't have to 179 // keep the current descriptor as extra decoding state when deserialising. 180 WriteInt(static_cast<int>(index)); 181 182 return success; 183 } 184 185 bool Message::ReadAttachment( 186 base::PickleIterator* iter, 187 scoped_refptr<base::Pickle::Attachment>* attachment) const { 188 int index; 189 if (!iter->ReadInt(&index)) 190 return false; 191 192 MessageAttachmentSet* attachment_set = attachment_set_.get(); 193 if (!attachment_set) 194 return false; 195 196 *attachment = attachment_set->GetAttachmentAt(index); 197 198 return nullptr != attachment->get(); 199 } 200 201 bool Message::HasAttachments() const { 202 return attachment_set_.get() && !attachment_set_->empty(); 203 } 204 205 } // namespace IPC 206