• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_MACH_IPC_MAC_H_
6 #define BASE_MACH_IPC_MAC_H_
7 
8 #include <mach/mach.h>
9 #include <mach/message.h>
10 #include <servers/bootstrap.h>
11 #include <sys/types.h>
12 
13 #include <CoreServices/CoreServices.h>
14 
15 #include "base/basictypes.h"
16 
17 //==============================================================================
18 // DISCUSSION:
19 //
20 // The three main classes of interest are
21 //
22 //  MachMessage:    a wrapper for a mach message of the following form
23 //   mach_msg_header_t
24 //   mach_msg_body_t
25 //   optional descriptors
26 //   optional extra message data
27 //
28 //  MachReceiveMessage and MachSendMessage subclass MachMessage
29 //    and are used instead of MachMessage which is an abstract base class
30 //
31 //  ReceivePort:
32 //    Represents a mach port for which we have receive rights
33 //
34 //  MachPortSender:
35 //    Represents a mach port for which we have send rights
36 //
37 // Here's an example to receive a message on a server port:
38 //
39 //        // This creates our named server port
40 //        ReceivePort receivePort("com.Google.MyService");
41 //
42 //        MachReceiveMessage message;
43 //        kern_return_t result = receivePort.WaitForMessage(&message, 0);
44 //
45 //        if (result == KERN_SUCCESS && message.GetMessageID() == 57) {
46 //          mach_port_t task = message.GetTranslatedPort(0);
47 //          mach_port_t thread = message.GetTranslatedPort(1);
48 //
49 //          char *messageString = message.GetData();
50 //
51 //          printf("message string = %s\n", messageString);
52 //        }
53 //
54 // Here is an example of using these classes to send a message to this port:
55 //
56 //    // send to already named port
57 //    MachPortSender sender("com.Google.MyService");
58 //    MachSendMessage message(57);      // our message ID is 57
59 //
60 //    // add some ports to be translated for us
61 //    message.AddDescriptor(mach_task_self());     // our task
62 //    message.AddDescriptor(mach_thread_self());   // this thread
63 //
64 //    char messageString[] = "Hello server!\n";
65 //    message.SetData(messageString, strlen(messageString)+1);
66 //    // timeout 1000ms
67 //    kern_return_t result = sender.SendMessage(message, 1000);
68 //
69 
70 #define PRINT_MACH_RESULT(result_, message_) \
71   printf(message_" %s (%d)\n", mach_error_string(result_), result_ );
72 
73 namespace base {
74 
75 //==============================================================================
76 // A wrapper class for mach_msg_port_descriptor_t (with same memory layout)
77 // with convenient constructors and accessors
78 class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
79  public:
80   // General-purpose constructor
MachMsgPortDescriptor(mach_port_t in_name,mach_msg_type_name_t in_disposition)81   MachMsgPortDescriptor(mach_port_t in_name,
82                         mach_msg_type_name_t in_disposition) {
83     name = in_name;
84     pad1 = 0;
85     pad2 = 0;
86     disposition = in_disposition;
87     type = MACH_MSG_PORT_DESCRIPTOR;
88   }
89 
90   // For passing send rights to a port
MachMsgPortDescriptor(mach_port_t in_name)91   MachMsgPortDescriptor(mach_port_t in_name) {
92     name = in_name;
93     pad1 = 0;
94     pad2 = 0;
95     disposition = MACH_MSG_TYPE_PORT_SEND;
96     type = MACH_MSG_PORT_DESCRIPTOR;
97   }
98 
99   // Copy constructor
MachMsgPortDescriptor(const MachMsgPortDescriptor & desc)100   MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) {
101     name = desc.name;
102     pad1 = desc.pad1;
103     pad2 = desc.pad2;
104     disposition = desc.disposition;
105     type = desc.type;
106   }
107 
GetMachPort()108   mach_port_t GetMachPort() const {
109     return name;
110   }
111 
GetDisposition()112   mach_msg_type_name_t GetDisposition() const {
113     return disposition;
114   }
115 
116   // We're just a simple wrapper for mach_msg_port_descriptor_t
117   // and have the same memory layout
118   operator mach_msg_port_descriptor_t&() {
119     return *this;
120   }
121 
122   // For convenience
mach_port_t()123   operator mach_port_t() const {
124     return GetMachPort();
125   }
126 };
127 
128 //==============================================================================
129 // MachMessage: a wrapper for a mach message
130 //  (mach_msg_header_t, mach_msg_body_t, extra data)
131 //
132 //  This considerably simplifies the construction of a message for sending
133 //  and the getting at relevant data and descriptors for the receiver.
134 //
135 //  This class can be initialized using external storage of an arbitrary size
136 //  or it can manage storage internally.
137 //  1. If storage is allocated internally, the combined size of the descriptors
138 //  plus data must be less than 1024.  But as a benefit no memory allocation is
139 //  necessary.
140 //  2. For external storage, a buffer of at least EmptyMessageSize() must be
141 //  provided.
142 //
143 //  A MachMessage object is used by ReceivePort::WaitForMessage
144 //  and MachPortSender::SendMessage
145 //
146 class MachMessage {
147  public:
148 
149   virtual ~MachMessage();
150 
151   // The receiver of the message can retrieve the raw data this way
GetData()152   u_int8_t *GetData() {
153     return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
154   }
155 
GetDataLength()156   u_int32_t GetDataLength() {
157     return EndianU32_LtoN(GetDataPacket()->data_length);
158   }
159 
160   // The message ID may be used as a code identifying the type of message
SetMessageID(int32_t message_id)161   void SetMessageID(int32_t message_id) {
162     GetDataPacket()->id = EndianU32_NtoL(message_id);
163   }
164 
GetMessageID()165   int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
166 
167   // Adds a descriptor (typically a mach port) to be translated
168   // returns true if successful, otherwise not enough space
169   bool AddDescriptor(const MachMsgPortDescriptor &desc);
170 
GetDescriptorCount()171   int GetDescriptorCount() const {
172     return storage_->body.msgh_descriptor_count;
173   }
174 
175   MachMsgPortDescriptor *GetDescriptor(int n);
176 
177   // Convenience method which gets the mach port described by the descriptor
178   mach_port_t GetTranslatedPort(int n);
179 
180   // A simple message is one with no descriptors
IsSimpleMessage()181   bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
182 
183   // Sets raw data for the message (returns false if not enough space)
184   bool SetData(const void* data, int32_t data_length);
185 
186  protected:
187   // Consider this an abstract base class - must create an actual instance
188   // of MachReceiveMessage or MachSendMessage
189   MachMessage();
190 
191   // Constructor for use with preallocate storage.
192   // storage_length must be >= EmptyMessageSize()
193   MachMessage(void *storage, size_t storage_length);
194 
195   friend class ReceivePort;
196   friend class MachPortSender;
197 
198   // Represents raw data in our message
199   struct MessageDataPacket {
200     int32_t  id;          // little-endian
201     int32_t  data_length; // little-endian
202     u_int8_t data[1];     // actual size limited by storage_length_bytes_
203   };
204 
205   MessageDataPacket* GetDataPacket();
206 
207   void SetDescriptorCount(int n);
208   void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
209 
210   // Returns total message size setting msgh_size in the header to this value
211   int CalculateSize();
212 
213   // Returns total storage size that this object can grow to, this is inclusive
214   // of the mach header.
MaxSize()215   size_t MaxSize() const { return storage_length_bytes_; }
216 
217  protected:
Head()218   mach_msg_header_t *Head() { return &(storage_->head); }
219 
220  private:
221   struct MachMessageData {
222     mach_msg_header_t  head;
223     mach_msg_body_t    body;
224     // descriptors and data may be embedded here.
225     u_int8_t           padding[1024];
226   };
227 
228  // kEmptyMessageSize needs to have the definition of MachMessageData before
229  // it.
230  public:
231    // The size of an empty message with no data.
232   static const size_t kEmptyMessageSize = sizeof(mach_msg_header_t) +
233                                           sizeof(mach_msg_body_t) +
234                                           sizeof(MessageDataPacket);
235 
236  private:
237   MachMessageData *storage_;
238   size_t storage_length_bytes_;
239   bool own_storage_;  // Is storage owned by this object?
240 };
241 
242 //==============================================================================
243 // MachReceiveMessage and MachSendMessage are useful to separate the idea
244 // of a mach message being sent and being received, and adds increased type
245 // safety:
246 //  ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
247 //  MachPortSender::SendMessage() only accepts a MachSendMessage
248 
249 //==============================================================================
250 class MachReceiveMessage : public MachMessage {
251  public:
MachReceiveMessage()252   MachReceiveMessage() : MachMessage() {}
MachReceiveMessage(void * storage,size_t storage_length)253   MachReceiveMessage(void *storage, size_t storage_length)
254       : MachMessage(storage, storage_length) {}
255 
256  private:
257     DISALLOW_COPY_AND_ASSIGN(MachReceiveMessage);
258 };
259 
260 //==============================================================================
261 class MachSendMessage : public MachMessage {
262  public:
263   explicit MachSendMessage(int32_t message_id);
264   MachSendMessage(void *storage, size_t storage_length, int32_t message_id);
265 
266  private:
267   void Initialize(int32_t message_id);
268 
269   DISALLOW_COPY_AND_ASSIGN(MachSendMessage);
270 };
271 
272 //==============================================================================
273 // Represents a mach port for which we have receive rights
274 class ReceivePort {
275  public:
276   // Creates a new mach port for receiving messages and registers a name for it
277   explicit ReceivePort(const char *receive_port_name);
278 
279   // Given an already existing mach port, use it.  We take ownership of the
280   // port and deallocate it in our destructor.
281   explicit ReceivePort(mach_port_t receive_port);
282 
283   // Create a new mach port for receiving messages
284   ReceivePort();
285 
286   ~ReceivePort();
287 
288   // Waits on the mach port until message received or timeout
289   kern_return_t WaitForMessage(MachReceiveMessage *out_message,
290                                mach_msg_timeout_t timeout);
291 
292   // The underlying mach port that we wrap
GetPort()293   mach_port_t  GetPort() const { return port_; }
294 
295  private:
296   mach_port_t   port_;
297   kern_return_t init_result_;
298 
299   DISALLOW_COPY_AND_ASSIGN(ReceivePort);
300 };
301 
302 //==============================================================================
303 // Represents a mach port for which we have send rights
304 class MachPortSender {
305  public:
306   // get a port with send rights corresponding to a named registered service
307   explicit MachPortSender(const char *receive_port_name);
308 
309 
310   // Given an already existing mach port, use it. Does not take ownership of
311   // |send_port|.
312   explicit MachPortSender(mach_port_t send_port);
313 
314   kern_return_t SendMessage(MachSendMessage &message,
315                             mach_msg_timeout_t timeout);
316 
317  private:
318   mach_port_t   send_port_;
319   kern_return_t init_result_;
320 
321   DISALLOW_COPY_AND_ASSIGN(MachPortSender);
322 };
323 
324 }  // namespace base
325 
326 #endif // BASE_MACH_IPC_MAC_H_
327