mach_ipc_mac.h revision ddb351dbec246cf1fab5ec20d2d5520909041de1
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
74namespace base {
75
76//==============================================================================
77// A wrapper class for mach_msg_port_descriptor_t (with same memory layout)
78// with convenient constructors and accessors
79class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
80 public:
81  // General-purpose constructor
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
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
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
109  mach_port_t GetMachPort() const {
110    return name;
111  }
112
113  mach_msg_type_name_t GetDisposition() const {
114    return disposition;
115  }
116
117  // For convenience
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//
141class 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
148  u_int8_t *GetData() {
149    return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
150  }
151
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
157  void SetMessageID(int32_t message_id) {
158    GetDataPacket()->id = EndianU32_NtoL(message_id);
159  }
160
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
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
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.
211  size_t MaxSize() const { return storage_length_bytes_; }
212
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//==============================================================================
236class MachReceiveMessage : public MachMessage {
237 public:
238  MachReceiveMessage() : MachMessage() {}
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//==============================================================================
247class 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
260class 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
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
291class 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