ipc/chromium/src/chrome/common/mach_ipc_mac.mm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "chrome/common/mach_ipc_mac.h"
michael@0 6
michael@0 7 #import <Foundation/Foundation.h>
michael@0 8
michael@0 9 #include <stdio.h>
michael@0 10 #include "base/logging.h"
michael@0 11
michael@0 12 //==============================================================================
michael@0 13 MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
michael@0 14 Initialize(message_id);
michael@0 15 }
michael@0 16
michael@0 17 MachSendMessage::MachSendMessage(void *storage, size_t storage_length,
michael@0 18 int32_t message_id)
michael@0 19 : MachMessage(storage, storage_length) {
michael@0 20 Initialize(message_id);
michael@0 21 }
michael@0 22
michael@0 23 void MachSendMessage::Initialize(int32_t message_id) {
michael@0 24 Head()->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
michael@0 25
michael@0 26 // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage()
michael@0 27 Head()->msgh_local_port = MACH_PORT_NULL;
michael@0 28 Head()->msgh_reserved = 0;
michael@0 29 Head()->msgh_id = 0;
michael@0 30
michael@0 31 SetDescriptorCount(0); // start out with no descriptors
michael@0 32
michael@0 33 SetMessageID(message_id);
michael@0 34 SetData(NULL, 0); // client may add data later
michael@0 35 }
michael@0 36
michael@0 37 //==============================================================================
michael@0 38 MachMessage::MachMessage()
michael@0 39 : storage_(new MachMessageData), // Allocate storage_ ourselves
michael@0 40 storage_length_bytes_(sizeof(MachMessageData)),
michael@0 41 own_storage_(true) {
michael@0 42 memset(storage_, 0, storage_length_bytes_);
michael@0 43 }
michael@0 44
michael@0 45 //==============================================================================
michael@0 46 MachMessage::MachMessage(void *storage, size_t storage_length)
michael@0 47 : storage_(static_cast<MachMessageData*>(storage)),
michael@0 48 storage_length_bytes_(storage_length),
michael@0 49 own_storage_(false) {
michael@0 50 DCHECK(storage);
michael@0 51 DCHECK(storage_length >= kEmptyMessageSize);
michael@0 52 }
michael@0 53
michael@0 54 //==============================================================================
michael@0 55 MachMessage::~MachMessage() {
michael@0 56 if (own_storage_) {
michael@0 57 delete storage_;
michael@0 58 storage_ = NULL;
michael@0 59 }
michael@0 60 }
michael@0 61
michael@0 62 //==============================================================================
michael@0 63 // returns true if successful
michael@0 64 bool MachMessage::SetData(const void* data,
michael@0 65 int32_t data_length) {
michael@0 66 // Enforce the fact that it's only safe to call this method once on a
michael@0 67 // message.
michael@0 68 DCHECK(GetDataPacket()->data_length == 0);
michael@0 69
michael@0 70 // first check to make sure we have enough space
michael@0 71 int size = CalculateSize();
michael@0 72 int new_size = size + data_length;
michael@0 73
michael@0 74 if ((unsigned)new_size > storage_length_bytes_) {
michael@0 75 return false; // not enough space
michael@0 76 }
michael@0 77
michael@0 78 GetDataPacket()->data_length = EndianU32_NtoL(data_length);
michael@0 79 if (data) memcpy(GetDataPacket()->data, data, data_length);
michael@0 80
michael@0 81 // Update the Mach header with the new aligned size of the message.
michael@0 82 CalculateSize();
michael@0 83
michael@0 84 return true;
michael@0 85 }
michael@0 86
michael@0 87 //==============================================================================
michael@0 88 // calculates and returns the total size of the message
michael@0 89 // Currently, the entire message MUST fit inside of the MachMessage
michael@0 90 // messsage size <= EmptyMessageSize()
michael@0 91 int MachMessage::CalculateSize() {
michael@0 92 int size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t);
michael@0 93
michael@0 94 // add space for MessageDataPacket
michael@0 95 int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3;
michael@0 96 size += 2*sizeof(int32_t) + alignedDataLength;
michael@0 97
michael@0 98 // add space for descriptors
michael@0 99 size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor);
michael@0 100
michael@0 101 Head()->msgh_size = size;
michael@0 102
michael@0 103 return size;
michael@0 104 }
michael@0 105
michael@0 106 //==============================================================================
michael@0 107 MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
michael@0 108 int desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
michael@0 109 MessageDataPacket *packet =
michael@0 110 reinterpret_cast<MessageDataPacket*>(storage_->padding + desc_size);
michael@0 111
michael@0 112 return packet;
michael@0 113 }
michael@0 114
michael@0 115 //==============================================================================
michael@0 116 void MachMessage::SetDescriptor(int n,
michael@0 117 const MachMsgPortDescriptor &desc) {
michael@0 118 MachMsgPortDescriptor *desc_array =
michael@0 119 reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
michael@0 120 desc_array[n] = desc;
michael@0 121 }
michael@0 122
michael@0 123 //==============================================================================
michael@0 124 // returns true if successful otherwise there was not enough space
michael@0 125 bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
michael@0 126 // first check to make sure we have enough space
michael@0 127 int size = CalculateSize();
michael@0 128 int new_size = size + sizeof(MachMsgPortDescriptor);
michael@0 129
michael@0 130 if ((unsigned)new_size > storage_length_bytes_) {
michael@0 131 return false; // not enough space
michael@0 132 }
michael@0 133
michael@0 134 // unfortunately, we need to move the data to allow space for the
michael@0 135 // new descriptor
michael@0 136 u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
michael@0 137 bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
michael@0 138
michael@0 139 SetDescriptor(GetDescriptorCount(), desc);
michael@0 140 SetDescriptorCount(GetDescriptorCount() + 1);
michael@0 141
michael@0 142 CalculateSize();
michael@0 143
michael@0 144 return true;
michael@0 145 }
michael@0 146
michael@0 147 //==============================================================================
michael@0 148 void MachMessage::SetDescriptorCount(int n) {
michael@0 149 storage_->body.msgh_descriptor_count = n;
michael@0 150
michael@0 151 if (n > 0) {
michael@0 152 Head()->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
michael@0 153 } else {
michael@0 154 Head()->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
michael@0 155 }
michael@0 156 }
michael@0 157
michael@0 158 //==============================================================================
michael@0 159 MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
michael@0 160 if (n < GetDescriptorCount()) {
michael@0 161 MachMsgPortDescriptor *desc =
michael@0 162 reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
michael@0 163 return desc + n;
michael@0 164 }
michael@0 165
michael@0 166 return nil;
michael@0 167 }
michael@0 168
michael@0 169 //==============================================================================
michael@0 170 mach_port_t MachMessage::GetTranslatedPort(int n) {
michael@0 171 if (n < GetDescriptorCount()) {
michael@0 172 return GetDescriptor(n)->GetMachPort();
michael@0 173 }
michael@0 174 return MACH_PORT_NULL;
michael@0 175 }
michael@0 176
michael@0 177 #pragma mark -
michael@0 178
michael@0 179 //==============================================================================
michael@0 180 // create a new mach port for receiving messages and register a name for it
michael@0 181 ReceivePort::ReceivePort(const char *receive_port_name) {
michael@0 182 mach_port_t current_task = mach_task_self();
michael@0 183
michael@0 184 init_result_ = mach_port_allocate(current_task,
michael@0 185 MACH_PORT_RIGHT_RECEIVE,
michael@0 186 &port_);
michael@0 187
michael@0 188 if (init_result_ != KERN_SUCCESS)
michael@0 189 return;
michael@0 190
michael@0 191 init_result_ = mach_port_insert_right(current_task,
michael@0 192 port_,
michael@0 193 port_,
michael@0 194 MACH_MSG_TYPE_MAKE_SEND);
michael@0 195
michael@0 196 if (init_result_ != KERN_SUCCESS)
michael@0 197 return;
michael@0 198
michael@0 199 NSPort *ns_port = [NSMachPort portWithMachPort:port_];
michael@0 200 NSString *port_name = [NSString stringWithUTF8String:receive_port_name];
michael@0 201 [[NSMachBootstrapServer sharedInstance] registerPort:ns_port name:port_name];
michael@0 202 }
michael@0 203
michael@0 204 //==============================================================================
michael@0 205 // create a new mach port for receiving messages
michael@0 206 ReceivePort::ReceivePort() {
michael@0 207 mach_port_t current_task = mach_task_self();
michael@0 208
michael@0 209 init_result_ = mach_port_allocate(current_task,
michael@0 210 MACH_PORT_RIGHT_RECEIVE,
michael@0 211 &port_);
michael@0 212
michael@0 213 if (init_result_ != KERN_SUCCESS)
michael@0 214 return;
michael@0 215
michael@0 216 init_result_ = mach_port_insert_right(current_task,
michael@0 217 port_,
michael@0 218 port_,
michael@0 219 MACH_MSG_TYPE_MAKE_SEND);
michael@0 220 }
michael@0 221
michael@0 222 //==============================================================================
michael@0 223 // Given an already existing mach port, use it. We take ownership of the
michael@0 224 // port and deallocate it in our destructor.
michael@0 225 ReceivePort::ReceivePort(mach_port_t receive_port)
michael@0 226 : port_(receive_port),
michael@0 227 init_result_(KERN_SUCCESS) {
michael@0 228 }
michael@0 229
michael@0 230 //==============================================================================
michael@0 231 ReceivePort::~ReceivePort() {
michael@0 232 if (init_result_ == KERN_SUCCESS)
michael@0 233 mach_port_deallocate(mach_task_self(), port_);
michael@0 234 }
michael@0 235
michael@0 236 //==============================================================================
michael@0 237 kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
michael@0 238 mach_msg_timeout_t timeout) {
michael@0 239 if (!out_message) {
michael@0 240 return KERN_INVALID_ARGUMENT;
michael@0 241 }
michael@0 242
michael@0 243 // return any error condition encountered in constructor
michael@0 244 if (init_result_ != KERN_SUCCESS)
michael@0 245 return init_result_;
michael@0 246
michael@0 247 out_message->Head()->msgh_bits = 0;
michael@0 248 out_message->Head()->msgh_local_port = port_;
michael@0 249 out_message->Head()->msgh_remote_port = MACH_PORT_NULL;
michael@0 250 out_message->Head()->msgh_reserved = 0;
michael@0 251 out_message->Head()->msgh_id = 0;
michael@0 252
michael@0 253 kern_return_t result = mach_msg(out_message->Head(),
michael@0 254 MACH_RCV_MSG | MACH_RCV_TIMEOUT,
michael@0 255 0,
michael@0 256 out_message->MaxSize(),
michael@0 257 port_,
michael@0 258 timeout, // timeout in ms
michael@0 259 MACH_PORT_NULL);
michael@0 260
michael@0 261 return result;
michael@0 262 }
michael@0 263
michael@0 264 #pragma mark -
michael@0 265
michael@0 266 //==============================================================================
michael@0 267 // get a port with send rights corresponding to a named registered service
michael@0 268 MachPortSender::MachPortSender(const char *receive_port_name) {
michael@0 269 mach_port_t bootstrap_port = 0;
michael@0 270 init_result_ = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
michael@0 271
michael@0 272 if (init_result_ != KERN_SUCCESS)
michael@0 273 return;
michael@0 274
michael@0 275 init_result_ = bootstrap_look_up(bootstrap_port,
michael@0 276 const_cast<char*>(receive_port_name),
michael@0 277 &send_port_);
michael@0 278 }
michael@0 279
michael@0 280 //==============================================================================
michael@0 281 MachPortSender::MachPortSender(mach_port_t send_port)
michael@0 282 : send_port_(send_port),
michael@0 283 init_result_(KERN_SUCCESS) {
michael@0 284 }
michael@0 285
michael@0 286 //==============================================================================
michael@0 287 kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
michael@0 288 mach_msg_timeout_t timeout) {
michael@0 289 if (message.Head()->msgh_size == 0) {
michael@0 290 NOTREACHED();
michael@0 291 return KERN_INVALID_VALUE; // just for safety -- never should occur
michael@0 292 };
michael@0 293
michael@0 294 if (init_result_ != KERN_SUCCESS)
michael@0 295 return init_result_;
michael@0 296
michael@0 297 message.Head()->msgh_remote_port = send_port_;
michael@0 298
michael@0 299 kern_return_t result = mach_msg(message.Head(),
michael@0 300 MACH_SEND_MSG | MACH_SEND_TIMEOUT,
michael@0 301 message.Head()->msgh_size,
michael@0 302 0,
michael@0 303 MACH_PORT_NULL,
michael@0 304 timeout, // timeout in ms
michael@0 305 MACH_PORT_NULL);
michael@0 306
michael@0 307 return result;
michael@0 308 }

mercurial