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