xref: /aosp_15_r20/external/google-breakpad/src/common/mac/MachIPC.mm (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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