1*9712c20fSFrederick Mayle// Copyright 2007 Google LLC 2*9712c20fSFrederick Mayle// 3*9712c20fSFrederick Mayle// Redistribution and use in source and binary forms, with or without 4*9712c20fSFrederick Mayle// modification, are permitted provided that the following conditions are 5*9712c20fSFrederick Mayle// met: 6*9712c20fSFrederick Mayle// 7*9712c20fSFrederick Mayle// * Redistributions of source code must retain the above copyright 8*9712c20fSFrederick Mayle// notice, this list of conditions and the following disclaimer. 9*9712c20fSFrederick Mayle// * Redistributions in binary form must reproduce the above 10*9712c20fSFrederick Mayle// copyright notice, this list of conditions and the following disclaimer 11*9712c20fSFrederick Mayle// in the documentation and/or other materials provided with the 12*9712c20fSFrederick Mayle// distribution. 13*9712c20fSFrederick Mayle// * Neither the name of Google LLC nor the names of its 14*9712c20fSFrederick Mayle// contributors may be used to endorse or promote products derived from 15*9712c20fSFrederick Mayle// this software without specific prior written permission. 16*9712c20fSFrederick Mayle// 17*9712c20fSFrederick Mayle// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18*9712c20fSFrederick Mayle// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19*9712c20fSFrederick Mayle// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20*9712c20fSFrederick Mayle// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21*9712c20fSFrederick Mayle// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22*9712c20fSFrederick Mayle// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23*9712c20fSFrederick Mayle// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24*9712c20fSFrederick Mayle// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25*9712c20fSFrederick Mayle// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26*9712c20fSFrederick Mayle// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27*9712c20fSFrederick Mayle// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28*9712c20fSFrederick Mayle// 29*9712c20fSFrederick Mayle// MachIPC.mm 30*9712c20fSFrederick Mayle// Wrapper for mach IPC calls 31*9712c20fSFrederick Mayle 32*9712c20fSFrederick Mayle#import <stdio.h> 33*9712c20fSFrederick Mayle#import "MachIPC.h" 34*9712c20fSFrederick Mayle#include "common/mac/bootstrap_compat.h" 35*9712c20fSFrederick Mayle 36*9712c20fSFrederick Maylenamespace google_breakpad { 37*9712c20fSFrederick Mayle//============================================================================== 38*9712c20fSFrederick MayleMachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() { 39*9712c20fSFrederick Mayle head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); 40*9712c20fSFrederick Mayle 41*9712c20fSFrederick Mayle // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage() 42*9712c20fSFrederick Mayle head.msgh_local_port = MACH_PORT_NULL; 43*9712c20fSFrederick Mayle head.msgh_reserved = 0; 44*9712c20fSFrederick Mayle head.msgh_id = 0; 45*9712c20fSFrederick Mayle 46*9712c20fSFrederick Mayle SetDescriptorCount(0); // start out with no descriptors 47*9712c20fSFrederick Mayle 48*9712c20fSFrederick Mayle SetMessageID(message_id); 49*9712c20fSFrederick Mayle SetData(NULL, 0); // client may add data later 50*9712c20fSFrederick Mayle} 51*9712c20fSFrederick Mayle 52*9712c20fSFrederick Mayle//============================================================================== 53*9712c20fSFrederick Mayle// returns true if successful 54*9712c20fSFrederick Maylebool MachMessage::SetData(void* data, 55*9712c20fSFrederick Mayle int32_t data_length) { 56*9712c20fSFrederick Mayle // first check to make sure we have enough space 57*9712c20fSFrederick Mayle size_t size = CalculateSize(); 58*9712c20fSFrederick Mayle size_t new_size = size + data_length; 59*9712c20fSFrederick Mayle 60*9712c20fSFrederick Mayle if (new_size > sizeof(MachMessage)) { 61*9712c20fSFrederick Mayle return false; // not enough space 62*9712c20fSFrederick Mayle } 63*9712c20fSFrederick Mayle 64*9712c20fSFrederick Mayle GetDataPacket()->data_length = EndianU32_NtoL(data_length); 65*9712c20fSFrederick Mayle if (data) memcpy(GetDataPacket()->data, data, data_length); 66*9712c20fSFrederick Mayle 67*9712c20fSFrederick Mayle CalculateSize(); 68*9712c20fSFrederick Mayle 69*9712c20fSFrederick Mayle return true; 70*9712c20fSFrederick Mayle} 71*9712c20fSFrederick Mayle 72*9712c20fSFrederick Mayle//============================================================================== 73*9712c20fSFrederick Mayle// calculates and returns the total size of the message 74*9712c20fSFrederick Mayle// Currently, the entire message MUST fit inside of the MachMessage 75*9712c20fSFrederick Mayle// messsage size <= sizeof(MachMessage) 76*9712c20fSFrederick Maylemach_msg_size_t MachMessage::CalculateSize() { 77*9712c20fSFrederick Mayle size_t size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t); 78*9712c20fSFrederick Mayle 79*9712c20fSFrederick Mayle // add space for MessageDataPacket 80*9712c20fSFrederick Mayle int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3; 81*9712c20fSFrederick Mayle size += 2*sizeof(int32_t) + alignedDataLength; 82*9712c20fSFrederick Mayle 83*9712c20fSFrederick Mayle // add space for descriptors 84*9712c20fSFrederick Mayle size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor); 85*9712c20fSFrederick Mayle 86*9712c20fSFrederick Mayle head.msgh_size = static_cast<mach_msg_size_t>(size); 87*9712c20fSFrederick Mayle 88*9712c20fSFrederick Mayle return head.msgh_size; 89*9712c20fSFrederick Mayle} 90*9712c20fSFrederick Mayle 91*9712c20fSFrederick Mayle//============================================================================== 92*9712c20fSFrederick MayleMachMessage::MessageDataPacket* MachMessage::GetDataPacket() { 93*9712c20fSFrederick Mayle size_t desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount(); 94*9712c20fSFrederick Mayle MessageDataPacket* packet = 95*9712c20fSFrederick Mayle reinterpret_cast<MessageDataPacket*>(padding + desc_size); 96*9712c20fSFrederick Mayle 97*9712c20fSFrederick Mayle return packet; 98*9712c20fSFrederick Mayle} 99*9712c20fSFrederick Mayle 100*9712c20fSFrederick Mayle//============================================================================== 101*9712c20fSFrederick Maylevoid MachMessage::SetDescriptor(int n, 102*9712c20fSFrederick Mayle const MachMsgPortDescriptor& desc) { 103*9712c20fSFrederick Mayle MachMsgPortDescriptor* desc_array = 104*9712c20fSFrederick Mayle reinterpret_cast<MachMsgPortDescriptor*>(padding); 105*9712c20fSFrederick Mayle desc_array[n] = desc; 106*9712c20fSFrederick Mayle} 107*9712c20fSFrederick Mayle 108*9712c20fSFrederick Mayle//============================================================================== 109*9712c20fSFrederick Mayle// returns true if successful otherwise there was not enough space 110*9712c20fSFrederick Maylebool MachMessage::AddDescriptor(const MachMsgPortDescriptor& desc) { 111*9712c20fSFrederick Mayle // first check to make sure we have enough space 112*9712c20fSFrederick Mayle int size = CalculateSize(); 113*9712c20fSFrederick Mayle size_t new_size = size + sizeof(MachMsgPortDescriptor); 114*9712c20fSFrederick Mayle 115*9712c20fSFrederick Mayle if (new_size > sizeof(MachMessage)) { 116*9712c20fSFrederick Mayle return false; // not enough space 117*9712c20fSFrederick Mayle } 118*9712c20fSFrederick Mayle 119*9712c20fSFrederick Mayle // unfortunately, we need to move the data to allow space for the 120*9712c20fSFrederick Mayle // new descriptor 121*9712c20fSFrederick Mayle u_int8_t* p = reinterpret_cast<u_int8_t*>(GetDataPacket()); 122*9712c20fSFrederick Mayle bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t)); 123*9712c20fSFrederick Mayle 124*9712c20fSFrederick Mayle SetDescriptor(GetDescriptorCount(), desc); 125*9712c20fSFrederick Mayle SetDescriptorCount(GetDescriptorCount() + 1); 126*9712c20fSFrederick Mayle 127*9712c20fSFrederick Mayle CalculateSize(); 128*9712c20fSFrederick Mayle 129*9712c20fSFrederick Mayle return true; 130*9712c20fSFrederick Mayle} 131*9712c20fSFrederick Mayle 132*9712c20fSFrederick Mayle//============================================================================== 133*9712c20fSFrederick Maylevoid MachMessage::SetDescriptorCount(int n) { 134*9712c20fSFrederick Mayle body.msgh_descriptor_count = n; 135*9712c20fSFrederick Mayle 136*9712c20fSFrederick Mayle if (n > 0) { 137*9712c20fSFrederick Mayle head.msgh_bits |= MACH_MSGH_BITS_COMPLEX; 138*9712c20fSFrederick Mayle } else { 139*9712c20fSFrederick Mayle head.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX; 140*9712c20fSFrederick Mayle } 141*9712c20fSFrederick Mayle} 142*9712c20fSFrederick Mayle 143*9712c20fSFrederick Mayle//============================================================================== 144*9712c20fSFrederick MayleMachMsgPortDescriptor* MachMessage::GetDescriptor(int n) { 145*9712c20fSFrederick Mayle if (n < GetDescriptorCount()) { 146*9712c20fSFrederick Mayle MachMsgPortDescriptor* desc = 147*9712c20fSFrederick Mayle reinterpret_cast<MachMsgPortDescriptor*>(padding); 148*9712c20fSFrederick Mayle return desc + n; 149*9712c20fSFrederick Mayle } 150*9712c20fSFrederick Mayle 151*9712c20fSFrederick Mayle return nil; 152*9712c20fSFrederick Mayle} 153*9712c20fSFrederick Mayle 154*9712c20fSFrederick Mayle//============================================================================== 155*9712c20fSFrederick Maylemach_port_t MachMessage::GetTranslatedPort(int n) { 156*9712c20fSFrederick Mayle if (n < GetDescriptorCount()) { 157*9712c20fSFrederick Mayle return GetDescriptor(n)->GetMachPort(); 158*9712c20fSFrederick Mayle } 159*9712c20fSFrederick Mayle return MACH_PORT_NULL; 160*9712c20fSFrederick Mayle} 161*9712c20fSFrederick Mayle 162*9712c20fSFrederick Mayle#pragma mark - 163*9712c20fSFrederick Mayle 164*9712c20fSFrederick Mayle//============================================================================== 165*9712c20fSFrederick Mayle// create a new mach port for receiving messages and register a name for it 166*9712c20fSFrederick MayleReceivePort::ReceivePort(const char* receive_port_name) { 167*9712c20fSFrederick Mayle mach_port_t current_task = mach_task_self(); 168*9712c20fSFrederick Mayle 169*9712c20fSFrederick Mayle init_result_ = mach_port_allocate(current_task, 170*9712c20fSFrederick Mayle MACH_PORT_RIGHT_RECEIVE, 171*9712c20fSFrederick Mayle &port_); 172*9712c20fSFrederick Mayle 173*9712c20fSFrederick Mayle if (init_result_ != KERN_SUCCESS) 174*9712c20fSFrederick Mayle return; 175*9712c20fSFrederick Mayle 176*9712c20fSFrederick Mayle init_result_ = mach_port_insert_right(current_task, 177*9712c20fSFrederick Mayle port_, 178*9712c20fSFrederick Mayle port_, 179*9712c20fSFrederick Mayle MACH_MSG_TYPE_MAKE_SEND); 180*9712c20fSFrederick Mayle 181*9712c20fSFrederick Mayle if (init_result_ != KERN_SUCCESS) 182*9712c20fSFrederick Mayle return; 183*9712c20fSFrederick Mayle 184*9712c20fSFrederick Mayle mach_port_t task_bootstrap_port = 0; 185*9712c20fSFrederick Mayle init_result_ = task_get_bootstrap_port(current_task, &task_bootstrap_port); 186*9712c20fSFrederick Mayle 187*9712c20fSFrederick Mayle if (init_result_ != KERN_SUCCESS) 188*9712c20fSFrederick Mayle return; 189*9712c20fSFrederick Mayle 190*9712c20fSFrederick Mayle init_result_ = breakpad::BootstrapRegister( 191*9712c20fSFrederick Mayle bootstrap_port, 192*9712c20fSFrederick Mayle const_cast<char*>(receive_port_name), 193*9712c20fSFrederick Mayle port_); 194*9712c20fSFrederick Mayle} 195*9712c20fSFrederick Mayle 196*9712c20fSFrederick Mayle//============================================================================== 197*9712c20fSFrederick Mayle// create a new mach port for receiving messages 198*9712c20fSFrederick MayleReceivePort::ReceivePort() { 199*9712c20fSFrederick Mayle mach_port_t current_task = mach_task_self(); 200*9712c20fSFrederick Mayle 201*9712c20fSFrederick Mayle init_result_ = mach_port_allocate(current_task, 202*9712c20fSFrederick Mayle MACH_PORT_RIGHT_RECEIVE, 203*9712c20fSFrederick Mayle &port_); 204*9712c20fSFrederick Mayle 205*9712c20fSFrederick Mayle if (init_result_ != KERN_SUCCESS) 206*9712c20fSFrederick Mayle return; 207*9712c20fSFrederick Mayle 208*9712c20fSFrederick Mayle init_result_ = mach_port_insert_right(current_task, 209*9712c20fSFrederick Mayle port_, 210*9712c20fSFrederick Mayle port_, 211*9712c20fSFrederick Mayle MACH_MSG_TYPE_MAKE_SEND); 212*9712c20fSFrederick Mayle} 213*9712c20fSFrederick Mayle 214*9712c20fSFrederick Mayle//============================================================================== 215*9712c20fSFrederick Mayle// Given an already existing mach port, use it. We take ownership of the 216*9712c20fSFrederick Mayle// port and deallocate it in our destructor. 217*9712c20fSFrederick MayleReceivePort::ReceivePort(mach_port_t receive_port) 218*9712c20fSFrederick Mayle : port_(receive_port), 219*9712c20fSFrederick Mayle init_result_(KERN_SUCCESS) { 220*9712c20fSFrederick Mayle} 221*9712c20fSFrederick Mayle 222*9712c20fSFrederick Mayle//============================================================================== 223*9712c20fSFrederick MayleReceivePort::~ReceivePort() { 224*9712c20fSFrederick Mayle if (init_result_ == KERN_SUCCESS) 225*9712c20fSFrederick Mayle mach_port_deallocate(mach_task_self(), port_); 226*9712c20fSFrederick Mayle} 227*9712c20fSFrederick Mayle 228*9712c20fSFrederick Mayle//============================================================================== 229*9712c20fSFrederick Maylekern_return_t ReceivePort::WaitForMessage(MachReceiveMessage* out_message, 230*9712c20fSFrederick Mayle mach_msg_timeout_t timeout) { 231*9712c20fSFrederick Mayle if (!out_message) { 232*9712c20fSFrederick Mayle return KERN_INVALID_ARGUMENT; 233*9712c20fSFrederick Mayle } 234*9712c20fSFrederick Mayle 235*9712c20fSFrederick Mayle // return any error condition encountered in constructor 236*9712c20fSFrederick Mayle if (init_result_ != KERN_SUCCESS) 237*9712c20fSFrederick Mayle return init_result_; 238*9712c20fSFrederick Mayle 239*9712c20fSFrederick Mayle out_message->head.msgh_bits = 0; 240*9712c20fSFrederick Mayle out_message->head.msgh_local_port = port_; 241*9712c20fSFrederick Mayle out_message->head.msgh_remote_port = MACH_PORT_NULL; 242*9712c20fSFrederick Mayle out_message->head.msgh_reserved = 0; 243*9712c20fSFrederick Mayle out_message->head.msgh_id = 0; 244*9712c20fSFrederick Mayle 245*9712c20fSFrederick Mayle mach_msg_option_t options = MACH_RCV_MSG; 246*9712c20fSFrederick Mayle if (timeout != MACH_MSG_TIMEOUT_NONE) 247*9712c20fSFrederick Mayle options |= MACH_RCV_TIMEOUT; 248*9712c20fSFrederick Mayle kern_return_t result = mach_msg(&out_message->head, 249*9712c20fSFrederick Mayle options, 250*9712c20fSFrederick Mayle 0, 251*9712c20fSFrederick Mayle sizeof(MachMessage), 252*9712c20fSFrederick Mayle port_, 253*9712c20fSFrederick Mayle timeout, // timeout in ms 254*9712c20fSFrederick Mayle MACH_PORT_NULL); 255*9712c20fSFrederick Mayle 256*9712c20fSFrederick Mayle return result; 257*9712c20fSFrederick Mayle} 258*9712c20fSFrederick Mayle 259*9712c20fSFrederick Mayle#pragma mark - 260*9712c20fSFrederick Mayle 261*9712c20fSFrederick Mayle//============================================================================== 262*9712c20fSFrederick Mayle// get a port with send rights corresponding to a named registered service 263*9712c20fSFrederick MayleMachPortSender::MachPortSender(const char* receive_port_name) { 264*9712c20fSFrederick Mayle mach_port_t task_bootstrap_port = 0; 265*9712c20fSFrederick Mayle init_result_ = task_get_bootstrap_port(mach_task_self(), 266*9712c20fSFrederick Mayle &task_bootstrap_port); 267*9712c20fSFrederick Mayle 268*9712c20fSFrederick Mayle if (init_result_ != KERN_SUCCESS) 269*9712c20fSFrederick Mayle return; 270*9712c20fSFrederick Mayle 271*9712c20fSFrederick Mayle init_result_ = bootstrap_look_up(task_bootstrap_port, 272*9712c20fSFrederick Mayle const_cast<char*>(receive_port_name), 273*9712c20fSFrederick Mayle &send_port_); 274*9712c20fSFrederick Mayle} 275*9712c20fSFrederick Mayle 276*9712c20fSFrederick Mayle//============================================================================== 277*9712c20fSFrederick MayleMachPortSender::MachPortSender(mach_port_t send_port) 278*9712c20fSFrederick Mayle : send_port_(send_port), 279*9712c20fSFrederick Mayle init_result_(KERN_SUCCESS) { 280*9712c20fSFrederick Mayle} 281*9712c20fSFrederick Mayle 282*9712c20fSFrederick Mayle//============================================================================== 283*9712c20fSFrederick Maylekern_return_t MachPortSender::SendMessage(MachSendMessage& message, 284*9712c20fSFrederick Mayle mach_msg_timeout_t timeout) { 285*9712c20fSFrederick Mayle if (message.head.msgh_size == 0) { 286*9712c20fSFrederick Mayle return KERN_INVALID_VALUE; // just for safety -- never should occur 287*9712c20fSFrederick Mayle }; 288*9712c20fSFrederick Mayle 289*9712c20fSFrederick Mayle if (init_result_ != KERN_SUCCESS) 290*9712c20fSFrederick Mayle return init_result_; 291*9712c20fSFrederick Mayle 292*9712c20fSFrederick Mayle message.head.msgh_remote_port = send_port_; 293*9712c20fSFrederick Mayle 294*9712c20fSFrederick Mayle kern_return_t result = mach_msg(&message.head, 295*9712c20fSFrederick Mayle MACH_SEND_MSG | MACH_SEND_TIMEOUT, 296*9712c20fSFrederick Mayle message.head.msgh_size, 297*9712c20fSFrederick Mayle 0, 298*9712c20fSFrederick Mayle MACH_PORT_NULL, 299*9712c20fSFrederick Mayle timeout, // timeout in ms 300*9712c20fSFrederick Mayle MACH_PORT_NULL); 301*9712c20fSFrederick Mayle 302*9712c20fSFrederick Mayle return result; 303*9712c20fSFrederick Mayle} 304*9712c20fSFrederick Mayle 305*9712c20fSFrederick Mayle} // namespace google_breakpad 306