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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ipc/chromium/src/chrome/common/mach_ipc_mac.mm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,308 @@
     1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
     1.5 +// Use of this source code is governed by a BSD-style license that can be
     1.6 +// found in the LICENSE file.
     1.7 +
     1.8 +#include "chrome/common/mach_ipc_mac.h"
     1.9 +
    1.10 +#import <Foundation/Foundation.h>
    1.11 +
    1.12 +#include <stdio.h>
    1.13 +#include "base/logging.h"
    1.14 +
    1.15 +//==============================================================================
    1.16 +MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
    1.17 +  Initialize(message_id);
    1.18 +}
    1.19 +
    1.20 +MachSendMessage::MachSendMessage(void *storage, size_t storage_length,
    1.21 +                                 int32_t message_id)
    1.22 +    : MachMessage(storage, storage_length) {
    1.23 +  Initialize(message_id);
    1.24 +}
    1.25 +
    1.26 +void MachSendMessage::Initialize(int32_t message_id) {
    1.27 +  Head()->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
    1.28 +
    1.29 +  // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage()
    1.30 +  Head()->msgh_local_port = MACH_PORT_NULL;
    1.31 +  Head()->msgh_reserved = 0;
    1.32 +  Head()->msgh_id = 0;
    1.33 +
    1.34 +  SetDescriptorCount(0);  // start out with no descriptors
    1.35 +
    1.36 +  SetMessageID(message_id);
    1.37 +  SetData(NULL, 0);       // client may add data later
    1.38 +}
    1.39 +
    1.40 +//==============================================================================
    1.41 +MachMessage::MachMessage()
    1.42 +    : storage_(new MachMessageData),  // Allocate storage_ ourselves
    1.43 +      storage_length_bytes_(sizeof(MachMessageData)),
    1.44 +      own_storage_(true) {
    1.45 +  memset(storage_, 0, storage_length_bytes_);
    1.46 +}
    1.47 +
    1.48 +//==============================================================================
    1.49 +MachMessage::MachMessage(void *storage, size_t storage_length)
    1.50 +    : storage_(static_cast<MachMessageData*>(storage)),
    1.51 +      storage_length_bytes_(storage_length),
    1.52 +      own_storage_(false) {
    1.53 +  DCHECK(storage);
    1.54 +  DCHECK(storage_length >= kEmptyMessageSize);
    1.55 +}
    1.56 +
    1.57 +//==============================================================================
    1.58 +MachMessage::~MachMessage() {
    1.59 +  if (own_storage_) {
    1.60 +    delete storage_;
    1.61 +    storage_ = NULL;
    1.62 +  }
    1.63 +}
    1.64 +
    1.65 +//==============================================================================
    1.66 +// returns true if successful
    1.67 +bool MachMessage::SetData(const void* data,
    1.68 +                          int32_t data_length) {
    1.69 +  // Enforce the fact that it's only safe to call this method once on a
    1.70 +  // message.
    1.71 +  DCHECK(GetDataPacket()->data_length == 0);
    1.72 +
    1.73 +  // first check to make sure we have enough space
    1.74 +  int size = CalculateSize();
    1.75 +  int new_size = size + data_length;
    1.76 +
    1.77 +  if ((unsigned)new_size > storage_length_bytes_) {
    1.78 +    return false;  // not enough space
    1.79 +  }
    1.80 +
    1.81 +  GetDataPacket()->data_length = EndianU32_NtoL(data_length);
    1.82 +  if (data) memcpy(GetDataPacket()->data, data, data_length);
    1.83 +
    1.84 +  // Update the Mach header with the new aligned size of the message.
    1.85 +  CalculateSize();
    1.86 +
    1.87 +  return true;
    1.88 +}
    1.89 +
    1.90 +//==============================================================================
    1.91 +// calculates and returns the total size of the message
    1.92 +// Currently, the entire message MUST fit inside of the MachMessage
    1.93 +//    messsage size <= EmptyMessageSize()
    1.94 +int MachMessage::CalculateSize() {
    1.95 +  int size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t);
    1.96 +
    1.97 +  // add space for MessageDataPacket
    1.98 +  int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3;
    1.99 +  size += 2*sizeof(int32_t) + alignedDataLength;
   1.100 +
   1.101 +  // add space for descriptors
   1.102 +  size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor);
   1.103 +
   1.104 +  Head()->msgh_size = size;
   1.105 +
   1.106 +  return size;
   1.107 +}
   1.108 +
   1.109 +//==============================================================================
   1.110 +MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
   1.111 +  int desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
   1.112 +  MessageDataPacket *packet =
   1.113 +    reinterpret_cast<MessageDataPacket*>(storage_->padding + desc_size);
   1.114 +
   1.115 +  return packet;
   1.116 +}
   1.117 +
   1.118 +//==============================================================================
   1.119 +void MachMessage::SetDescriptor(int n,
   1.120 +                                const MachMsgPortDescriptor &desc) {
   1.121 +  MachMsgPortDescriptor *desc_array =
   1.122 +    reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
   1.123 +  desc_array[n] = desc;
   1.124 +}
   1.125 +
   1.126 +//==============================================================================
   1.127 +// returns true if successful otherwise there was not enough space
   1.128 +bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
   1.129 +  // first check to make sure we have enough space
   1.130 +  int size = CalculateSize();
   1.131 +  int new_size = size + sizeof(MachMsgPortDescriptor);
   1.132 +
   1.133 +  if ((unsigned)new_size > storage_length_bytes_) {
   1.134 +    return false;  // not enough space
   1.135 +  }
   1.136 +
   1.137 +  // unfortunately, we need to move the data to allow space for the
   1.138 +  // new descriptor
   1.139 +  u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
   1.140 +  bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
   1.141 +
   1.142 +  SetDescriptor(GetDescriptorCount(), desc);
   1.143 +  SetDescriptorCount(GetDescriptorCount() + 1);
   1.144 +
   1.145 +  CalculateSize();
   1.146 +
   1.147 +  return true;
   1.148 +}
   1.149 +
   1.150 +//==============================================================================
   1.151 +void MachMessage::SetDescriptorCount(int n) {
   1.152 +  storage_->body.msgh_descriptor_count = n;
   1.153 +
   1.154 +  if (n > 0) {
   1.155 +    Head()->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
   1.156 +  } else {
   1.157 +    Head()->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
   1.158 +  }
   1.159 +}
   1.160 +
   1.161 +//==============================================================================
   1.162 +MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
   1.163 +  if (n < GetDescriptorCount()) {
   1.164 +    MachMsgPortDescriptor *desc =
   1.165 +        reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
   1.166 +    return desc + n;
   1.167 +  }
   1.168 +
   1.169 +  return nil;
   1.170 +}
   1.171 +
   1.172 +//==============================================================================
   1.173 +mach_port_t MachMessage::GetTranslatedPort(int n) {
   1.174 +  if (n < GetDescriptorCount()) {
   1.175 +    return GetDescriptor(n)->GetMachPort();
   1.176 +  }
   1.177 +  return MACH_PORT_NULL;
   1.178 +}
   1.179 +
   1.180 +#pragma mark -
   1.181 +
   1.182 +//==============================================================================
   1.183 +// create a new mach port for receiving messages and register a name for it
   1.184 +ReceivePort::ReceivePort(const char *receive_port_name) {
   1.185 +  mach_port_t current_task = mach_task_self();
   1.186 +
   1.187 +  init_result_ = mach_port_allocate(current_task,
   1.188 +                                    MACH_PORT_RIGHT_RECEIVE,
   1.189 +                                    &port_);
   1.190 +
   1.191 +  if (init_result_ != KERN_SUCCESS)
   1.192 +    return;
   1.193 +
   1.194 +  init_result_ = mach_port_insert_right(current_task,
   1.195 +                                        port_,
   1.196 +                                        port_,
   1.197 +                                        MACH_MSG_TYPE_MAKE_SEND);
   1.198 +
   1.199 +  if (init_result_ != KERN_SUCCESS)
   1.200 +    return;
   1.201 +
   1.202 +  NSPort *ns_port = [NSMachPort portWithMachPort:port_];
   1.203 +  NSString *port_name = [NSString stringWithUTF8String:receive_port_name];
   1.204 +  [[NSMachBootstrapServer sharedInstance] registerPort:ns_port name:port_name];
   1.205 +}
   1.206 +
   1.207 +//==============================================================================
   1.208 +// create a new mach port for receiving messages
   1.209 +ReceivePort::ReceivePort() {
   1.210 +  mach_port_t current_task = mach_task_self();
   1.211 +
   1.212 +  init_result_ = mach_port_allocate(current_task,
   1.213 +                                    MACH_PORT_RIGHT_RECEIVE,
   1.214 +                                    &port_);
   1.215 +
   1.216 +  if (init_result_ != KERN_SUCCESS)
   1.217 +    return;
   1.218 +
   1.219 +  init_result_ =   mach_port_insert_right(current_task,
   1.220 +                                          port_,
   1.221 +                                          port_,
   1.222 +                                          MACH_MSG_TYPE_MAKE_SEND);
   1.223 +}
   1.224 +
   1.225 +//==============================================================================
   1.226 +// Given an already existing mach port, use it.  We take ownership of the
   1.227 +// port and deallocate it in our destructor.
   1.228 +ReceivePort::ReceivePort(mach_port_t receive_port)
   1.229 +  : port_(receive_port),
   1.230 +    init_result_(KERN_SUCCESS) {
   1.231 +}
   1.232 +
   1.233 +//==============================================================================
   1.234 +ReceivePort::~ReceivePort() {
   1.235 +  if (init_result_ == KERN_SUCCESS)
   1.236 +    mach_port_deallocate(mach_task_self(), port_);
   1.237 +}
   1.238 +
   1.239 +//==============================================================================
   1.240 +kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
   1.241 +                                          mach_msg_timeout_t timeout) {
   1.242 +  if (!out_message) {
   1.243 +    return KERN_INVALID_ARGUMENT;
   1.244 +  }
   1.245 +
   1.246 +  // return any error condition encountered in constructor
   1.247 +  if (init_result_ != KERN_SUCCESS)
   1.248 +    return init_result_;
   1.249 +
   1.250 +  out_message->Head()->msgh_bits = 0;
   1.251 +  out_message->Head()->msgh_local_port = port_;
   1.252 +  out_message->Head()->msgh_remote_port = MACH_PORT_NULL;
   1.253 +  out_message->Head()->msgh_reserved = 0;
   1.254 +  out_message->Head()->msgh_id = 0;
   1.255 +
   1.256 +  kern_return_t result = mach_msg(out_message->Head(),
   1.257 +                                  MACH_RCV_MSG | MACH_RCV_TIMEOUT,
   1.258 +                                  0,
   1.259 +                                  out_message->MaxSize(),
   1.260 +                                  port_,
   1.261 +                                  timeout,              // timeout in ms
   1.262 +                                  MACH_PORT_NULL);
   1.263 +
   1.264 +  return result;
   1.265 +}
   1.266 +
   1.267 +#pragma mark -
   1.268 +
   1.269 +//==============================================================================
   1.270 +// get a port with send rights corresponding to a named registered service
   1.271 +MachPortSender::MachPortSender(const char *receive_port_name) {
   1.272 +  mach_port_t bootstrap_port = 0;
   1.273 +  init_result_ = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
   1.274 +
   1.275 +  if (init_result_ != KERN_SUCCESS)
   1.276 +    return;
   1.277 +
   1.278 +  init_result_ = bootstrap_look_up(bootstrap_port,
   1.279 +                    const_cast<char*>(receive_port_name),
   1.280 +                    &send_port_);
   1.281 +}
   1.282 +
   1.283 +//==============================================================================
   1.284 +MachPortSender::MachPortSender(mach_port_t send_port)
   1.285 +  : send_port_(send_port),
   1.286 +    init_result_(KERN_SUCCESS) {
   1.287 +}
   1.288 +
   1.289 +//==============================================================================
   1.290 +kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
   1.291 +                                          mach_msg_timeout_t timeout) {
   1.292 +  if (message.Head()->msgh_size == 0) {
   1.293 +    NOTREACHED();
   1.294 +    return KERN_INVALID_VALUE;    // just for safety -- never should occur
   1.295 +  };
   1.296 +
   1.297 +  if (init_result_ != KERN_SUCCESS)
   1.298 +    return init_result_;
   1.299 +
   1.300 +  message.Head()->msgh_remote_port = send_port_;
   1.301 +
   1.302 +  kern_return_t result = mach_msg(message.Head(),
   1.303 +                                  MACH_SEND_MSG | MACH_SEND_TIMEOUT,
   1.304 +                                  message.Head()->msgh_size,
   1.305 +                                  0,
   1.306 +                                  MACH_PORT_NULL,
   1.307 +                                  timeout,              // timeout in ms
   1.308 +                                  MACH_PORT_NULL);
   1.309 +
   1.310 +  return result;
   1.311 +}

mercurial