/thirdparty/breakpad/common/mac/MachIPC.mm
http://github.com/tomahawk-player/tomahawk · Objective C++ · 306 lines · 180 code · 60 blank · 66 comment · 28 complexity · bf520cb0081aa277ac096b18e1130b22 MD5 · raw file
- // Copyright (c) 2007, Google Inc.
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- //
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following disclaimer
- // in the documentation and/or other materials provided with the
- // distribution.
- // * Neither the name of Google Inc. nor the names of its
- // contributors may be used to endorse or promote products derived from
- // this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- //
- // MachIPC.mm
- // Wrapper for mach IPC calls
- #import <stdio.h>
- #import "MachIPC.h"
- #include "common/mac/bootstrap_compat.h"
- namespace google_breakpad {
- //==============================================================================
- MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
- head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
- // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage()
- head.msgh_local_port = MACH_PORT_NULL;
- head.msgh_reserved = 0;
- head.msgh_id = 0;
- SetDescriptorCount(0); // start out with no descriptors
- SetMessageID(message_id);
- SetData(NULL, 0); // client may add data later
- }
- //==============================================================================
- // returns true if successful
- bool MachMessage::SetData(void *data,
- int32_t data_length) {
- // first check to make sure we have enough space
- size_t size = CalculateSize();
- size_t new_size = size + data_length;
-
- if (new_size > sizeof(MachMessage)) {
- return false; // not enough space
- }
- GetDataPacket()->data_length = EndianU32_NtoL(data_length);
- if (data) memcpy(GetDataPacket()->data, data, data_length);
- CalculateSize();
- return true;
- }
- //==============================================================================
- // calculates and returns the total size of the message
- // Currently, the entire message MUST fit inside of the MachMessage
- // messsage size <= sizeof(MachMessage)
- mach_msg_size_t MachMessage::CalculateSize() {
- size_t size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t);
-
- // add space for MessageDataPacket
- int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3;
- size += 2*sizeof(int32_t) + alignedDataLength;
-
- // add space for descriptors
- size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor);
-
- head.msgh_size = static_cast<mach_msg_size_t>(size);
-
- return head.msgh_size;
- }
- //==============================================================================
- MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
- size_t desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
- MessageDataPacket *packet =
- reinterpret_cast<MessageDataPacket*>(padding + desc_size);
- return packet;
- }
- //==============================================================================
- void MachMessage::SetDescriptor(int n,
- const MachMsgPortDescriptor &desc) {
- MachMsgPortDescriptor *desc_array =
- reinterpret_cast<MachMsgPortDescriptor*>(padding);
- desc_array[n] = desc;
- }
- //==============================================================================
- // returns true if successful otherwise there was not enough space
- bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
- // first check to make sure we have enough space
- int size = CalculateSize();
- size_t new_size = size + sizeof(MachMsgPortDescriptor);
-
- if (new_size > sizeof(MachMessage)) {
- return false; // not enough space
- }
- // unfortunately, we need to move the data to allow space for the
- // new descriptor
- u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
- bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
-
- SetDescriptor(GetDescriptorCount(), desc);
- SetDescriptorCount(GetDescriptorCount() + 1);
- CalculateSize();
-
- return true;
- }
- //==============================================================================
- void MachMessage::SetDescriptorCount(int n) {
- body.msgh_descriptor_count = n;
- if (n > 0) {
- head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
- } else {
- head.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
- }
- }
- //==============================================================================
- MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
- if (n < GetDescriptorCount()) {
- MachMsgPortDescriptor *desc =
- reinterpret_cast<MachMsgPortDescriptor*>(padding);
- return desc + n;
- }
-
- return nil;
- }
- //==============================================================================
- mach_port_t MachMessage::GetTranslatedPort(int n) {
- if (n < GetDescriptorCount()) {
- return GetDescriptor(n)->GetMachPort();
- }
- return MACH_PORT_NULL;
- }
- #pragma mark -
- //==============================================================================
- // create a new mach port for receiving messages and register a name for it
- ReceivePort::ReceivePort(const char *receive_port_name) {
- mach_port_t current_task = mach_task_self();
- init_result_ = mach_port_allocate(current_task,
- MACH_PORT_RIGHT_RECEIVE,
- &port_);
- if (init_result_ != KERN_SUCCESS)
- return;
-
- init_result_ = mach_port_insert_right(current_task,
- port_,
- port_,
- MACH_MSG_TYPE_MAKE_SEND);
- if (init_result_ != KERN_SUCCESS)
- return;
- mach_port_t task_bootstrap_port = 0;
- init_result_ = task_get_bootstrap_port(current_task, &task_bootstrap_port);
- if (init_result_ != KERN_SUCCESS)
- return;
- init_result_ = breakpad::BootstrapRegister(
- bootstrap_port,
- const_cast<char*>(receive_port_name),
- port_);
- }
- //==============================================================================
- // create a new mach port for receiving messages
- ReceivePort::ReceivePort() {
- mach_port_t current_task = mach_task_self();
- init_result_ = mach_port_allocate(current_task,
- MACH_PORT_RIGHT_RECEIVE,
- &port_);
- if (init_result_ != KERN_SUCCESS)
- return;
- init_result_ = mach_port_insert_right(current_task,
- port_,
- port_,
- MACH_MSG_TYPE_MAKE_SEND);
- }
- //==============================================================================
- // Given an already existing mach port, use it. We take ownership of the
- // port and deallocate it in our destructor.
- ReceivePort::ReceivePort(mach_port_t receive_port)
- : port_(receive_port),
- init_result_(KERN_SUCCESS) {
- }
- //==============================================================================
- ReceivePort::~ReceivePort() {
- if (init_result_ == KERN_SUCCESS)
- mach_port_deallocate(mach_task_self(), port_);
- }
- //==============================================================================
- kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
- mach_msg_timeout_t timeout) {
- if (!out_message) {
- return KERN_INVALID_ARGUMENT;
- }
- // return any error condition encountered in constructor
- if (init_result_ != KERN_SUCCESS)
- return init_result_;
-
- out_message->head.msgh_bits = 0;
- out_message->head.msgh_local_port = port_;
- out_message->head.msgh_remote_port = MACH_PORT_NULL;
- out_message->head.msgh_reserved = 0;
- out_message->head.msgh_id = 0;
- mach_msg_option_t options = MACH_RCV_MSG;
- if (timeout != MACH_MSG_TIMEOUT_NONE)
- options |= MACH_RCV_TIMEOUT;
- kern_return_t result = mach_msg(&out_message->head,
- options,
- 0,
- sizeof(MachMessage),
- port_,
- timeout, // timeout in ms
- MACH_PORT_NULL);
- return result;
- }
- #pragma mark -
- //==============================================================================
- // get a port with send rights corresponding to a named registered service
- MachPortSender::MachPortSender(const char *receive_port_name) {
- mach_port_t task_bootstrap_port = 0;
- init_result_ = task_get_bootstrap_port(mach_task_self(),
- &task_bootstrap_port);
-
- if (init_result_ != KERN_SUCCESS)
- return;
- init_result_ = bootstrap_look_up(task_bootstrap_port,
- const_cast<char*>(receive_port_name),
- &send_port_);
- }
- //==============================================================================
- MachPortSender::MachPortSender(mach_port_t send_port)
- : send_port_(send_port),
- init_result_(KERN_SUCCESS) {
- }
- //==============================================================================
- kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
- mach_msg_timeout_t timeout) {
- if (message.head.msgh_size == 0) {
- return KERN_INVALID_VALUE; // just for safety -- never should occur
- };
-
- if (init_result_ != KERN_SUCCESS)
- return init_result_;
-
- message.head.msgh_remote_port = send_port_;
- kern_return_t result = mach_msg(&message.head,
- MACH_SEND_MSG | MACH_SEND_TIMEOUT,
- message.head.msgh_size,
- 0,
- MACH_PORT_NULL,
- timeout, // timeout in ms
- MACH_PORT_NULL);
- return result;
- }
- } // namespace google_breakpad