toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.mm

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.mm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,306 @@
     1.4 +// Copyright (c) 2007, Google Inc.
     1.5 +// All rights reserved.
     1.6 +//
     1.7 +// Redistribution and use in source and binary forms, with or without
     1.8 +// modification, are permitted provided that the following conditions are
     1.9 +// met:
    1.10 +//
    1.11 +//     * Redistributions of source code must retain the above copyright
    1.12 +// notice, this list of conditions and the following disclaimer.
    1.13 +//     * Redistributions in binary form must reproduce the above
    1.14 +// copyright notice, this list of conditions and the following disclaimer
    1.15 +// in the documentation and/or other materials provided with the
    1.16 +// distribution.
    1.17 +//     * Neither the name of Google Inc. nor the names of its
    1.18 +// contributors may be used to endorse or promote products derived from
    1.19 +// this software without specific prior written permission.
    1.20 +//
    1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.32 +//
    1.33 +//  MachIPC.mm
    1.34 +//  Wrapper for mach IPC calls
    1.35 +
    1.36 +#import <stdio.h>
    1.37 +#import "MachIPC.h"
    1.38 +#include "common/mac/bootstrap_compat.h"
    1.39 +
    1.40 +namespace google_breakpad {
    1.41 +//==============================================================================
    1.42 +MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
    1.43 +  head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
    1.44 +
    1.45 +  // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage()
    1.46 +  head.msgh_local_port = MACH_PORT_NULL;
    1.47 +  head.msgh_reserved = 0;
    1.48 +  head.msgh_id = 0;
    1.49 +
    1.50 +  SetDescriptorCount(0);  // start out with no descriptors
    1.51 +
    1.52 +  SetMessageID(message_id);
    1.53 +  SetData(NULL, 0);       // client may add data later
    1.54 +}
    1.55 +
    1.56 +//==============================================================================
    1.57 +// returns true if successful
    1.58 +bool MachMessage::SetData(void *data,
    1.59 +                          int32_t data_length) {
    1.60 +  // first check to make sure we have enough space
    1.61 +  size_t size = CalculateSize();
    1.62 +  size_t new_size = size + data_length;
    1.63 +  
    1.64 +  if (new_size > sizeof(MachMessage)) {
    1.65 +    return false;  // not enough space
    1.66 +  }
    1.67 +
    1.68 +  GetDataPacket()->data_length = EndianU32_NtoL(data_length);
    1.69 +  if (data) memcpy(GetDataPacket()->data, data, data_length);
    1.70 +
    1.71 +  CalculateSize();
    1.72 +
    1.73 +  return true;
    1.74 +}
    1.75 +
    1.76 +//==============================================================================
    1.77 +// calculates and returns the total size of the message
    1.78 +// Currently, the entire message MUST fit inside of the MachMessage
    1.79 +//    messsage size <= sizeof(MachMessage)
    1.80 +mach_msg_size_t MachMessage::CalculateSize() {
    1.81 +  size_t size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t);
    1.82 +  
    1.83 +  // add space for MessageDataPacket
    1.84 +  int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3;
    1.85 +  size += 2*sizeof(int32_t) + alignedDataLength;
    1.86 +  
    1.87 +  // add space for descriptors
    1.88 +  size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor);
    1.89 +  
    1.90 +  head.msgh_size = static_cast<mach_msg_size_t>(size);
    1.91 +  
    1.92 +  return head.msgh_size;
    1.93 +}
    1.94 +
    1.95 +//==============================================================================
    1.96 +MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
    1.97 +  size_t desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
    1.98 +  MessageDataPacket *packet =
    1.99 +    reinterpret_cast<MessageDataPacket*>(padding + desc_size);
   1.100 +
   1.101 +  return packet;
   1.102 +}
   1.103 +
   1.104 +//==============================================================================
   1.105 +void MachMessage::SetDescriptor(int n,
   1.106 +                                const MachMsgPortDescriptor &desc) {
   1.107 +  MachMsgPortDescriptor *desc_array =
   1.108 +    reinterpret_cast<MachMsgPortDescriptor*>(padding);
   1.109 +  desc_array[n] = desc;
   1.110 +}
   1.111 +
   1.112 +//==============================================================================
   1.113 +// returns true if successful otherwise there was not enough space
   1.114 +bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
   1.115 +  // first check to make sure we have enough space
   1.116 +  int size = CalculateSize();
   1.117 +  size_t new_size = size + sizeof(MachMsgPortDescriptor);
   1.118 +  
   1.119 +  if (new_size > sizeof(MachMessage)) {
   1.120 +    return false;  // not enough space
   1.121 +  }
   1.122 +
   1.123 +  // unfortunately, we need to move the data to allow space for the
   1.124 +  // new descriptor
   1.125 +  u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
   1.126 +  bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
   1.127 +  
   1.128 +  SetDescriptor(GetDescriptorCount(), desc);
   1.129 +  SetDescriptorCount(GetDescriptorCount() + 1);
   1.130 +
   1.131 +  CalculateSize();
   1.132 +  
   1.133 +  return true;
   1.134 +}
   1.135 +
   1.136 +//==============================================================================
   1.137 +void MachMessage::SetDescriptorCount(int n) {
   1.138 +  body.msgh_descriptor_count = n;
   1.139 +
   1.140 +  if (n > 0) {
   1.141 +    head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
   1.142 +  } else {
   1.143 +    head.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
   1.144 +  }
   1.145 +}
   1.146 +
   1.147 +//==============================================================================
   1.148 +MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
   1.149 +  if (n < GetDescriptorCount()) {
   1.150 +    MachMsgPortDescriptor *desc =
   1.151 +      reinterpret_cast<MachMsgPortDescriptor*>(padding);
   1.152 +    return desc + n;
   1.153 +  }
   1.154 +  
   1.155 +  return nil;
   1.156 +}
   1.157 +
   1.158 +//==============================================================================
   1.159 +mach_port_t MachMessage::GetTranslatedPort(int n) {
   1.160 +  if (n < GetDescriptorCount()) {
   1.161 +    return GetDescriptor(n)->GetMachPort();
   1.162 +  }
   1.163 +  return MACH_PORT_NULL;
   1.164 +}
   1.165 +
   1.166 +#pragma mark -
   1.167 +
   1.168 +//==============================================================================
   1.169 +// create a new mach port for receiving messages and register a name for it
   1.170 +ReceivePort::ReceivePort(const char *receive_port_name) {
   1.171 +  mach_port_t current_task = mach_task_self();
   1.172 +
   1.173 +  init_result_ = mach_port_allocate(current_task,
   1.174 +                                    MACH_PORT_RIGHT_RECEIVE,
   1.175 +                                    &port_);
   1.176 +
   1.177 +  if (init_result_ != KERN_SUCCESS)
   1.178 +    return;
   1.179 +    
   1.180 +  init_result_ = mach_port_insert_right(current_task,
   1.181 +                                        port_,
   1.182 +                                        port_,
   1.183 +                                        MACH_MSG_TYPE_MAKE_SEND);
   1.184 +
   1.185 +  if (init_result_ != KERN_SUCCESS)
   1.186 +    return;
   1.187 +
   1.188 +  mach_port_t task_bootstrap_port = 0;
   1.189 +  init_result_ = task_get_bootstrap_port(current_task, &task_bootstrap_port);
   1.190 +
   1.191 +  if (init_result_ != KERN_SUCCESS)
   1.192 +    return;
   1.193 +
   1.194 +  init_result_ = breakpad::BootstrapRegister(
   1.195 +      bootstrap_port,
   1.196 +      const_cast<char*>(receive_port_name),
   1.197 +      port_);
   1.198 +}
   1.199 +
   1.200 +//==============================================================================
   1.201 +// create a new mach port for receiving messages
   1.202 +ReceivePort::ReceivePort() {
   1.203 +  mach_port_t current_task = mach_task_self();
   1.204 +
   1.205 +  init_result_ = mach_port_allocate(current_task,
   1.206 +                                    MACH_PORT_RIGHT_RECEIVE,
   1.207 +                                    &port_);
   1.208 +
   1.209 +  if (init_result_ != KERN_SUCCESS)
   1.210 +    return;
   1.211 +
   1.212 +  init_result_ =   mach_port_insert_right(current_task,
   1.213 +                                          port_,
   1.214 +                                          port_,
   1.215 +                                          MACH_MSG_TYPE_MAKE_SEND);
   1.216 +}
   1.217 +
   1.218 +//==============================================================================
   1.219 +// Given an already existing mach port, use it.  We take ownership of the
   1.220 +// port and deallocate it in our destructor.
   1.221 +ReceivePort::ReceivePort(mach_port_t receive_port)
   1.222 +  : port_(receive_port),
   1.223 +    init_result_(KERN_SUCCESS) {
   1.224 +}
   1.225 +
   1.226 +//==============================================================================
   1.227 +ReceivePort::~ReceivePort() {
   1.228 +  if (init_result_ == KERN_SUCCESS)
   1.229 +    mach_port_deallocate(mach_task_self(), port_);
   1.230 +}
   1.231 +
   1.232 +//==============================================================================
   1.233 +kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
   1.234 +                                          mach_msg_timeout_t timeout) {
   1.235 +  if (!out_message) {
   1.236 +    return KERN_INVALID_ARGUMENT;
   1.237 +  }
   1.238 +
   1.239 +  // return any error condition encountered in constructor
   1.240 +  if (init_result_ != KERN_SUCCESS)
   1.241 +    return init_result_;
   1.242 +  
   1.243 +  out_message->head.msgh_bits = 0;
   1.244 +  out_message->head.msgh_local_port = port_;
   1.245 +  out_message->head.msgh_remote_port = MACH_PORT_NULL;
   1.246 +  out_message->head.msgh_reserved = 0;
   1.247 +  out_message->head.msgh_id = 0;
   1.248 +
   1.249 +  mach_msg_option_t options = MACH_RCV_MSG;
   1.250 +  if (timeout != MACH_MSG_TIMEOUT_NONE)
   1.251 +    options |= MACH_RCV_TIMEOUT;
   1.252 +  kern_return_t result = mach_msg(&out_message->head,
   1.253 +                                  options,
   1.254 +                                  0,
   1.255 +                                  sizeof(MachMessage),
   1.256 +                                  port_,
   1.257 +                                  timeout,              // timeout in ms
   1.258 +                                  MACH_PORT_NULL);
   1.259 +
   1.260 +  return result;
   1.261 +}
   1.262 +
   1.263 +#pragma mark -
   1.264 +
   1.265 +//==============================================================================
   1.266 +// get a port with send rights corresponding to a named registered service
   1.267 +MachPortSender::MachPortSender(const char *receive_port_name) {
   1.268 +  mach_port_t task_bootstrap_port = 0;
   1.269 +  init_result_ = task_get_bootstrap_port(mach_task_self(), 
   1.270 +                                         &task_bootstrap_port);
   1.271 +  
   1.272 +  if (init_result_ != KERN_SUCCESS)
   1.273 +    return;
   1.274 +
   1.275 +  init_result_ = bootstrap_look_up(task_bootstrap_port,
   1.276 +                    const_cast<char*>(receive_port_name),
   1.277 +                    &send_port_);
   1.278 +}
   1.279 +
   1.280 +//==============================================================================
   1.281 +MachPortSender::MachPortSender(mach_port_t send_port) 
   1.282 +  : send_port_(send_port),
   1.283 +    init_result_(KERN_SUCCESS) {
   1.284 +}
   1.285 +
   1.286 +//==============================================================================
   1.287 +kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
   1.288 +                                          mach_msg_timeout_t timeout) {
   1.289 +  if (message.head.msgh_size == 0) {
   1.290 +    return KERN_INVALID_VALUE;    // just for safety -- never should occur
   1.291 +  };
   1.292 +  
   1.293 +  if (init_result_ != KERN_SUCCESS)
   1.294 +    return init_result_;
   1.295 +  
   1.296 +  message.head.msgh_remote_port = send_port_;
   1.297 +
   1.298 +  kern_return_t result = mach_msg(&message.head,
   1.299 +                                  MACH_SEND_MSG | MACH_SEND_TIMEOUT,
   1.300 +                                  message.head.msgh_size,
   1.301 +                                  0,
   1.302 +                                  MACH_PORT_NULL,
   1.303 +                                  timeout,              // timeout in ms
   1.304 +                                  MACH_PORT_NULL);
   1.305 +
   1.306 +  return result;
   1.307 +}
   1.308 +
   1.309 +}  // namespace google_breakpad

mercurial