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