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