1 // Copyright (c) 2012 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.
5 #ifndef BASE_MACH_IPC_MAC_H_
6 #define BASE_MACH_IPC_MAC_H_
9 #include <mach/message.h>
10 #include <servers/bootstrap.h>
11 #include <sys/types.h>
13 #include <CoreServices/CoreServices.h>
15 #include "base/base_export.h"
16 #include "base/basictypes.h"
18 //==============================================================================
21 // The three main classes of interest are
23 // MachMessage: a wrapper for a Mach message of the following form
26 // optional descriptors
27 // optional extra message data
29 // MachReceiveMessage and MachSendMessage subclass MachMessage
30 // and are used instead of MachMessage which is an abstract base class
33 // Represents a Mach port for which we have receive rights
36 // Represents a Mach port for which we have send rights
38 // Here's an example to receive a message on a server port:
40 // // This creates our named server port
41 // ReceivePort receivePort("com.Google.MyService");
43 // MachReceiveMessage message;
44 // kern_return_t result = receivePort.WaitForMessage(&message, 0);
46 // if (result == KERN_SUCCESS && message.GetMessageID() == 57) {
47 // mach_port_t task = message.GetTranslatedPort(0);
48 // mach_port_t thread = message.GetTranslatedPort(1);
50 // char *messageString = message.GetData();
52 // printf("message string = %s\n", messageString);
55 // Here is an example of using these classes to send a message to this port:
57 // // send to already named port
58 // MachPortSender sender("com.Google.MyService");
59 // MachSendMessage message(57); // our message ID is 57
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
65 // char messageString[] = "Hello server!\n";
66 // message.SetData(messageString, strlen(messageString)+1);
68 // kern_return_t result = sender.SendMessage(message, 1000);
71 #define PRINT_MACH_RESULT(result_, message_) \
72 printf(message_" %s (%d)\n", mach_error_string(result_), result_ );
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
{
81 // General-purpose constructor
82 MachMsgPortDescriptor(mach_port_t in_name
,
83 mach_msg_type_name_t in_disposition
) {
87 disposition
= in_disposition
;
88 type
= MACH_MSG_PORT_DESCRIPTOR
;
91 // For passing send rights to a port
92 MachMsgPortDescriptor(mach_port_t in_name
) {
96 disposition
= MACH_MSG_TYPE_PORT_SEND
;
97 type
= MACH_MSG_PORT_DESCRIPTOR
;
101 MachMsgPortDescriptor(const MachMsgPortDescriptor
& desc
) {
105 disposition
= desc
.disposition
;
109 mach_port_t
GetMachPort() const {
113 mach_msg_type_name_t
GetDisposition() const {
118 operator mach_port_t() const {
119 return GetMachPort();
123 //==============================================================================
124 // MachMessage: a wrapper for a Mach message
125 // (mach_msg_header_t, mach_msg_body_t, extra data)
127 // This considerably simplifies the construction of a message for sending
128 // and the getting at relevant data and descriptors for the receiver.
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
135 // 2. For external storage, a buffer of at least EmptyMessageSize() must be
138 // A MachMessage object is used by ReceivePort::WaitForMessage
139 // and MachPortSender::SendMessage
141 class BASE_EXPORT MachMessage
{
143 static const size_t kEmptyMessageSize
;
145 virtual ~MachMessage();
147 // The receiver of the message can retrieve the raw data this way
148 u_int8_t
*GetData() {
149 return GetDataLength() > 0 ? GetDataPacket()->data
: NULL
;
152 u_int32_t
GetDataLength() {
153 return EndianU32_LtoN(GetDataPacket()->data_length
);
156 // The message ID may be used as a code identifying the type of message
157 void SetMessageID(int32_t message_id
) {
158 GetDataPacket()->id
= EndianU32_NtoL(message_id
);
161 int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id
); }
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
);
167 int GetDescriptorCount() const {
168 return storage_
->body
.msgh_descriptor_count
;
171 MachMsgPortDescriptor
*GetDescriptor(int n
);
173 // Convenience method which gets the Mach port described by the descriptor
174 mach_port_t
GetTranslatedPort(int n
);
176 // A simple message is one with no descriptors
177 bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
179 // Sets raw data for the message (returns false if not enough space)
180 bool SetData(const void* data
, int32_t data_length
);
183 // Consider this an abstract base class - must create an actual instance
184 // of MachReceiveMessage or MachSendMessage
187 // Constructor for use with preallocate storage.
188 // storage_length must be >= EmptyMessageSize()
189 MachMessage(void *storage
, size_t storage_length
);
191 friend class ReceivePort
;
192 friend class MachPortSender
;
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_
201 MessageDataPacket
* GetDataPacket();
203 void SetDescriptorCount(int n
);
204 void SetDescriptor(int n
, const MachMsgPortDescriptor
&desc
);
206 // Returns total message size setting msgh_size in the header to this value
209 // Returns total storage size that this object can grow to, this is inclusive
210 // of the Mach header.
211 size_t MaxSize() const { return storage_length_bytes_
; }
213 mach_msg_header_t
*Head() { return &(storage_
->head
); }
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];
223 MachMessageData
*storage_
;
224 size_t storage_length_bytes_
;
225 bool own_storage_
; // Is storage owned by this object?
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
232 // ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
233 // MachPortSender::SendMessage() only accepts a MachSendMessage
235 //==============================================================================
236 class MachReceiveMessage
: public MachMessage
{
238 MachReceiveMessage() : MachMessage() {}
239 MachReceiveMessage(void *storage
, size_t storage_length
)
240 : MachMessage(storage
, storage_length
) {}
243 DISALLOW_COPY_AND_ASSIGN(MachReceiveMessage
);
246 //==============================================================================
247 class BASE_EXPORT MachSendMessage
: public MachMessage
{
249 explicit MachSendMessage(int32_t message_id
);
250 MachSendMessage(void *storage
, size_t storage_length
, int32_t message_id
);
253 void Initialize(int32_t message_id
);
255 DISALLOW_COPY_AND_ASSIGN(MachSendMessage
);
258 //==============================================================================
259 // Represents a Mach port for which we have receive rights
260 class BASE_EXPORT ReceivePort
{
262 // Creates a new Mach port for receiving messages and registers a name for it
263 explicit ReceivePort(const char *receive_port_name
);
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
);
269 // Create a new Mach port for receiving messages
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
);
279 // The underlying Mach port that we wrap
280 mach_port_t
GetPort() const { return port_
; }
284 kern_return_t init_result_
;
286 DISALLOW_COPY_AND_ASSIGN(ReceivePort
);
289 //==============================================================================
290 // Represents a Mach port for which we have send rights
291 class BASE_EXPORT MachPortSender
{
293 // get a port with send rights corresponding to a named registered service
294 explicit MachPortSender(const char *receive_port_name
);
297 // Given an already existing Mach port, use it. Does not take ownership of
299 explicit MachPortSender(mach_port_t send_port
);
301 kern_return_t
SendMessage(MachSendMessage
&message
,
302 mach_msg_timeout_t timeout
);
305 mach_port_t send_port_
;
306 kern_return_t init_result_
;
308 DISALLOW_COPY_AND_ASSIGN(MachPortSender
);
311 //==============================================================================
312 // Static utility functions.
316 // Returns the number of Mach ports to which the given task has a right.
317 // Note that unless the calling task has send rights to the passed task port,
318 // this will fail unless the calling task is running as root.
319 kern_return_t BASE_EXPORT
GetNumberOfMachPorts(mach_port_t task_port
,
326 #endif // BASE_MACH_IPC_MAC_H_