xref: /aosp_15_r20/external/google-breakpad/src/common/mac/MachIPC.h (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.h
30*9712c20fSFrederick Mayle //
31*9712c20fSFrederick Mayle //  Some helpful wrappers for using Mach IPC calls
32*9712c20fSFrederick Mayle 
33*9712c20fSFrederick Mayle #ifndef MACH_IPC_H__
34*9712c20fSFrederick Mayle #define MACH_IPC_H__
35*9712c20fSFrederick Mayle 
36*9712c20fSFrederick Mayle #import <mach/mach.h>
37*9712c20fSFrederick Mayle #import <mach/message.h>
38*9712c20fSFrederick Mayle #import <servers/bootstrap.h>
39*9712c20fSFrederick Mayle #import <sys/types.h>
40*9712c20fSFrederick Mayle 
41*9712c20fSFrederick Mayle #import <CoreServices/CoreServices.h>
42*9712c20fSFrederick Mayle 
43*9712c20fSFrederick Mayle //==============================================================================
44*9712c20fSFrederick Mayle // DISCUSSION:
45*9712c20fSFrederick Mayle //
46*9712c20fSFrederick Mayle // The three main classes of interest are
47*9712c20fSFrederick Mayle //
48*9712c20fSFrederick Mayle //  MachMessage:    a wrapper for a mach message of the following form
49*9712c20fSFrederick Mayle //   mach_msg_header_t
50*9712c20fSFrederick Mayle //   mach_msg_body_t
51*9712c20fSFrederick Mayle //   optional descriptors
52*9712c20fSFrederick Mayle //   optional extra message data
53*9712c20fSFrederick Mayle //
54*9712c20fSFrederick Mayle //  MachReceiveMessage and MachSendMessage subclass MachMessage
55*9712c20fSFrederick Mayle //    and are used instead of MachMessage which is an abstract base class
56*9712c20fSFrederick Mayle //
57*9712c20fSFrederick Mayle //  ReceivePort:
58*9712c20fSFrederick Mayle //    Represents a mach port for which we have receive rights
59*9712c20fSFrederick Mayle //
60*9712c20fSFrederick Mayle //  MachPortSender:
61*9712c20fSFrederick Mayle //    Represents a mach port for which we have send rights
62*9712c20fSFrederick Mayle //
63*9712c20fSFrederick Mayle // Here's an example to receive a message on a server port:
64*9712c20fSFrederick Mayle //
65*9712c20fSFrederick Mayle //        // This creates our named server port
66*9712c20fSFrederick Mayle //        ReceivePort receivePort("com.Google.MyService");
67*9712c20fSFrederick Mayle //
68*9712c20fSFrederick Mayle //        MachReceiveMessage message;
69*9712c20fSFrederick Mayle //        kern_return_t result = receivePort.WaitForMessage(&message, 0);
70*9712c20fSFrederick Mayle //
71*9712c20fSFrederick Mayle //        if (result == KERN_SUCCESS && message.GetMessageID() == 57) {
72*9712c20fSFrederick Mayle //          mach_port_t task = message.GetTranslatedPort(0);
73*9712c20fSFrederick Mayle //          mach_port_t thread = message.GetTranslatedPort(1);
74*9712c20fSFrederick Mayle //
75*9712c20fSFrederick Mayle //          char* messageString = message.GetData();
76*9712c20fSFrederick Mayle //
77*9712c20fSFrederick Mayle //          printf("message string = %s\n", messageString);
78*9712c20fSFrederick Mayle //        }
79*9712c20fSFrederick Mayle //
80*9712c20fSFrederick Mayle // Here is an example of using these classes to send a message to this port:
81*9712c20fSFrederick Mayle //
82*9712c20fSFrederick Mayle //    // send to already named port
83*9712c20fSFrederick Mayle //    MachPortSender sender("com.Google.MyService");
84*9712c20fSFrederick Mayle //    MachSendMessage message(57);      // our message ID is 57
85*9712c20fSFrederick Mayle //
86*9712c20fSFrederick Mayle //    // add some ports to be translated for us
87*9712c20fSFrederick Mayle //    message.AddDescriptor(mach_task_self());     // our task
88*9712c20fSFrederick Mayle //    message.AddDescriptor(mach_thread_self());   // this thread
89*9712c20fSFrederick Mayle //
90*9712c20fSFrederick Mayle //    char messageString[] = "Hello server!\n";
91*9712c20fSFrederick Mayle //    message.SetData(messageString, strlen(messageString)+1);
92*9712c20fSFrederick Mayle //
93*9712c20fSFrederick Mayle //    kern_return_t result = sender.SendMessage(message, 1000); // timeout 1000ms
94*9712c20fSFrederick Mayle //
95*9712c20fSFrederick Mayle 
96*9712c20fSFrederick Mayle namespace google_breakpad {
97*9712c20fSFrederick Mayle #define PRINT_MACH_RESULT(result_, message_) \
98*9712c20fSFrederick Mayle   printf(message_" %s (%d)\n", mach_error_string(result_), result_ );
99*9712c20fSFrederick Mayle 
100*9712c20fSFrederick Mayle //==============================================================================
101*9712c20fSFrederick Mayle // A wrapper class for mach_msg_port_descriptor_t (with same memory layout)
102*9712c20fSFrederick Mayle // with convenient constructors and accessors
103*9712c20fSFrederick Mayle class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
104*9712c20fSFrederick Mayle  public:
105*9712c20fSFrederick Mayle   // General-purpose constructor
MachMsgPortDescriptor(mach_port_t in_name,mach_msg_type_name_t in_disposition)106*9712c20fSFrederick Mayle   MachMsgPortDescriptor(mach_port_t in_name,
107*9712c20fSFrederick Mayle                         mach_msg_type_name_t in_disposition) {
108*9712c20fSFrederick Mayle     name = in_name;
109*9712c20fSFrederick Mayle     pad1 = 0;
110*9712c20fSFrederick Mayle     pad2 = 0;
111*9712c20fSFrederick Mayle     disposition = in_disposition;
112*9712c20fSFrederick Mayle     type = MACH_MSG_PORT_DESCRIPTOR;
113*9712c20fSFrederick Mayle   }
114*9712c20fSFrederick Mayle 
115*9712c20fSFrederick Mayle   // For passing send rights to a port
MachMsgPortDescriptor(mach_port_t in_name)116*9712c20fSFrederick Mayle   MachMsgPortDescriptor(mach_port_t in_name) {
117*9712c20fSFrederick Mayle     name = in_name;
118*9712c20fSFrederick Mayle     pad1 = 0;
119*9712c20fSFrederick Mayle     pad2 = 0;
120*9712c20fSFrederick Mayle     disposition = MACH_MSG_TYPE_COPY_SEND;
121*9712c20fSFrederick Mayle     type = MACH_MSG_PORT_DESCRIPTOR;
122*9712c20fSFrederick Mayle   }
123*9712c20fSFrederick Mayle 
124*9712c20fSFrederick Mayle   // Copy constructor
MachMsgPortDescriptor(const MachMsgPortDescriptor & desc)125*9712c20fSFrederick Mayle   MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) {
126*9712c20fSFrederick Mayle     name = desc.name;
127*9712c20fSFrederick Mayle     pad1 = desc.pad1;
128*9712c20fSFrederick Mayle     pad2 = desc.pad2;
129*9712c20fSFrederick Mayle     disposition = desc.disposition;
130*9712c20fSFrederick Mayle     type = desc.type;
131*9712c20fSFrederick Mayle   }
132*9712c20fSFrederick Mayle 
GetMachPort()133*9712c20fSFrederick Mayle   mach_port_t GetMachPort() const {
134*9712c20fSFrederick Mayle     return name;
135*9712c20fSFrederick Mayle   }
136*9712c20fSFrederick Mayle 
GetDisposition()137*9712c20fSFrederick Mayle   mach_msg_type_name_t GetDisposition() const {
138*9712c20fSFrederick Mayle     return disposition;
139*9712c20fSFrederick Mayle   }
140*9712c20fSFrederick Mayle 
141*9712c20fSFrederick Mayle   // For convenience
mach_port_t()142*9712c20fSFrederick Mayle   operator mach_port_t() const {
143*9712c20fSFrederick Mayle     return GetMachPort();
144*9712c20fSFrederick Mayle   }
145*9712c20fSFrederick Mayle };
146*9712c20fSFrederick Mayle 
147*9712c20fSFrederick Mayle //==============================================================================
148*9712c20fSFrederick Mayle // MachMessage: a wrapper for a mach message
149*9712c20fSFrederick Mayle //  (mach_msg_header_t, mach_msg_body_t, extra data)
150*9712c20fSFrederick Mayle //
151*9712c20fSFrederick Mayle //  This considerably simplifies the construction of a message for sending
152*9712c20fSFrederick Mayle //  and the getting at relevant data and descriptors for the receiver.
153*9712c20fSFrederick Mayle //
154*9712c20fSFrederick Mayle //  Currently the combined size of the descriptors plus data must be
155*9712c20fSFrederick Mayle //  less than 1024.  But as a benefit no memory allocation is necessary.
156*9712c20fSFrederick Mayle //
157*9712c20fSFrederick Mayle // TODO: could consider adding malloc() support for very large messages
158*9712c20fSFrederick Mayle //
159*9712c20fSFrederick Mayle //  A MachMessage object is used by ReceivePort::WaitForMessage
160*9712c20fSFrederick Mayle //  and MachPortSender::SendMessage
161*9712c20fSFrederick Mayle //
162*9712c20fSFrederick Mayle class MachMessage {
163*9712c20fSFrederick Mayle  public:
164*9712c20fSFrederick Mayle 
165*9712c20fSFrederick Mayle   // The receiver of the message can retrieve the raw data this way
GetData()166*9712c20fSFrederick Mayle   uint8_t* GetData() {
167*9712c20fSFrederick Mayle     return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
168*9712c20fSFrederick Mayle   }
169*9712c20fSFrederick Mayle 
GetDataLength()170*9712c20fSFrederick Mayle   uint32_t GetDataLength() {
171*9712c20fSFrederick Mayle     return EndianU32_LtoN(GetDataPacket()->data_length);
172*9712c20fSFrederick Mayle   }
173*9712c20fSFrederick Mayle 
174*9712c20fSFrederick Mayle   // The message ID may be used as a code identifying the type of message
SetMessageID(int32_t message_id)175*9712c20fSFrederick Mayle   void SetMessageID(int32_t message_id) {
176*9712c20fSFrederick Mayle     GetDataPacket()->id = EndianU32_NtoL(message_id);
177*9712c20fSFrederick Mayle   }
178*9712c20fSFrederick Mayle 
GetMessageID()179*9712c20fSFrederick Mayle   int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
180*9712c20fSFrederick Mayle 
181*9712c20fSFrederick Mayle   // Adds a descriptor (typically a mach port) to be translated
182*9712c20fSFrederick Mayle   // returns true if successful, otherwise not enough space
183*9712c20fSFrederick Mayle   bool AddDescriptor(const MachMsgPortDescriptor& desc);
184*9712c20fSFrederick Mayle 
GetDescriptorCount()185*9712c20fSFrederick Mayle   int GetDescriptorCount() const { return body.msgh_descriptor_count; }
186*9712c20fSFrederick Mayle   MachMsgPortDescriptor* GetDescriptor(int n);
187*9712c20fSFrederick Mayle 
188*9712c20fSFrederick Mayle   // Convenience method which gets the mach port described by the descriptor
189*9712c20fSFrederick Mayle   mach_port_t GetTranslatedPort(int n);
190*9712c20fSFrederick Mayle 
191*9712c20fSFrederick Mayle   // A simple message is one with no descriptors
IsSimpleMessage()192*9712c20fSFrederick Mayle   bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
193*9712c20fSFrederick Mayle 
194*9712c20fSFrederick Mayle   // Sets raw data for the message (returns false if not enough space)
195*9712c20fSFrederick Mayle   bool SetData(void* data, int32_t data_length);
196*9712c20fSFrederick Mayle 
197*9712c20fSFrederick Mayle  protected:
198*9712c20fSFrederick Mayle   // Consider this an abstract base class - must create an actual instance
199*9712c20fSFrederick Mayle   // of MachReceiveMessage or MachSendMessage
200*9712c20fSFrederick Mayle 
MachMessage()201*9712c20fSFrederick Mayle   MachMessage() {
202*9712c20fSFrederick Mayle     memset(this, 0, sizeof(MachMessage));
203*9712c20fSFrederick Mayle   }
204*9712c20fSFrederick Mayle 
205*9712c20fSFrederick Mayle   friend class ReceivePort;
206*9712c20fSFrederick Mayle   friend class MachPortSender;
207*9712c20fSFrederick Mayle 
208*9712c20fSFrederick Mayle   // Represents raw data in our message
209*9712c20fSFrederick Mayle   struct MessageDataPacket {
210*9712c20fSFrederick Mayle     int32_t      id;          // little-endian
211*9712c20fSFrederick Mayle     int32_t      data_length; // little-endian
212*9712c20fSFrederick Mayle     uint8_t      data[1];     // actual size limited by sizeof(MachMessage)
213*9712c20fSFrederick Mayle   };
214*9712c20fSFrederick Mayle 
215*9712c20fSFrederick Mayle   MessageDataPacket* GetDataPacket();
216*9712c20fSFrederick Mayle 
217*9712c20fSFrederick Mayle   void SetDescriptorCount(int n);
218*9712c20fSFrederick Mayle   void SetDescriptor(int n, const MachMsgPortDescriptor& desc);
219*9712c20fSFrederick Mayle 
220*9712c20fSFrederick Mayle   // Returns total message size setting msgh_size in the header to this value
221*9712c20fSFrederick Mayle   mach_msg_size_t CalculateSize();
222*9712c20fSFrederick Mayle 
223*9712c20fSFrederick Mayle   mach_msg_header_t  head;
224*9712c20fSFrederick Mayle   mach_msg_body_t    body;
225*9712c20fSFrederick Mayle   uint8_t            padding[1024]; // descriptors and data may be embedded here
226*9712c20fSFrederick Mayle };
227*9712c20fSFrederick Mayle 
228*9712c20fSFrederick Mayle //==============================================================================
229*9712c20fSFrederick Mayle // MachReceiveMessage and MachSendMessage are useful to separate the idea
230*9712c20fSFrederick Mayle // of a mach message being sent and being received, and adds increased type
231*9712c20fSFrederick Mayle // safety:
232*9712c20fSFrederick Mayle //  ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
233*9712c20fSFrederick Mayle //  MachPortSender::SendMessage() only accepts a MachSendMessage
234*9712c20fSFrederick Mayle 
235*9712c20fSFrederick Mayle //==============================================================================
236*9712c20fSFrederick Mayle class MachReceiveMessage : public MachMessage {
237*9712c20fSFrederick Mayle  public:
MachReceiveMessage()238*9712c20fSFrederick Mayle   MachReceiveMessage() : MachMessage() {}
239*9712c20fSFrederick Mayle };
240*9712c20fSFrederick Mayle 
241*9712c20fSFrederick Mayle //==============================================================================
242*9712c20fSFrederick Mayle class MachSendMessage : public MachMessage {
243*9712c20fSFrederick Mayle  public:
244*9712c20fSFrederick Mayle   MachSendMessage(int32_t message_id);
245*9712c20fSFrederick Mayle };
246*9712c20fSFrederick Mayle 
247*9712c20fSFrederick Mayle //==============================================================================
248*9712c20fSFrederick Mayle // Represents a mach port for which we have receive rights
249*9712c20fSFrederick Mayle class ReceivePort {
250*9712c20fSFrederick Mayle  public:
251*9712c20fSFrederick Mayle   // Creates a new mach port for receiving messages and registers a name for it
252*9712c20fSFrederick Mayle   explicit ReceivePort(const char* receive_port_name);
253*9712c20fSFrederick Mayle 
254*9712c20fSFrederick Mayle   // Given an already existing mach port, use it.  We take ownership of the
255*9712c20fSFrederick Mayle   // port and deallocate it in our destructor.
256*9712c20fSFrederick Mayle   explicit ReceivePort(mach_port_t receive_port);
257*9712c20fSFrederick Mayle 
258*9712c20fSFrederick Mayle   // Create a new mach port for receiving messages
259*9712c20fSFrederick Mayle   ReceivePort();
260*9712c20fSFrederick Mayle 
261*9712c20fSFrederick Mayle   ~ReceivePort();
262*9712c20fSFrederick Mayle 
263*9712c20fSFrederick Mayle   // Waits on the mach port until message received or timeout
264*9712c20fSFrederick Mayle   kern_return_t WaitForMessage(MachReceiveMessage* out_message,
265*9712c20fSFrederick Mayle                                mach_msg_timeout_t timeout);
266*9712c20fSFrederick Mayle 
267*9712c20fSFrederick Mayle   // The underlying mach port that we wrap
GetPort()268*9712c20fSFrederick Mayle   mach_port_t  GetPort() const { return port_; }
269*9712c20fSFrederick Mayle 
270*9712c20fSFrederick Mayle  private:
271*9712c20fSFrederick Mayle   ReceivePort(const ReceivePort&);  // disable copy c-tor
272*9712c20fSFrederick Mayle 
273*9712c20fSFrederick Mayle   mach_port_t   port_;
274*9712c20fSFrederick Mayle   kern_return_t init_result_;
275*9712c20fSFrederick Mayle };
276*9712c20fSFrederick Mayle 
277*9712c20fSFrederick Mayle //==============================================================================
278*9712c20fSFrederick Mayle // Represents a mach port for which we have send rights
279*9712c20fSFrederick Mayle class MachPortSender {
280*9712c20fSFrederick Mayle  public:
281*9712c20fSFrederick Mayle   // get a port with send rights corresponding to a named registered service
282*9712c20fSFrederick Mayle   explicit MachPortSender(const char* receive_port_name);
283*9712c20fSFrederick Mayle 
284*9712c20fSFrederick Mayle 
285*9712c20fSFrederick Mayle   // Given an already existing mach port, use it.
286*9712c20fSFrederick Mayle   explicit MachPortSender(mach_port_t send_port);
287*9712c20fSFrederick Mayle 
288*9712c20fSFrederick Mayle   kern_return_t SendMessage(MachSendMessage& message,
289*9712c20fSFrederick Mayle                             mach_msg_timeout_t timeout);
290*9712c20fSFrederick Mayle 
291*9712c20fSFrederick Mayle  private:
292*9712c20fSFrederick Mayle   MachPortSender(const MachPortSender&);  // disable copy c-tor
293*9712c20fSFrederick Mayle 
294*9712c20fSFrederick Mayle   mach_port_t   send_port_;
295*9712c20fSFrederick Mayle   kern_return_t init_result_;
296*9712c20fSFrederick Mayle };
297*9712c20fSFrederick Mayle 
298*9712c20fSFrederick Mayle }  // namespace google_breakpad
299*9712c20fSFrederick Mayle 
300*9712c20fSFrederick Mayle #endif // MACH_IPC_H__
301