ipc/chromium/src/chrome/common/mach_ipc_mac.h

branch
TOR_BUG_3246
changeset 6
8bccb770b82d
equal deleted inserted replaced
-1:000000000000 0:8afcf9cd9c02
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 //==============================================================================
74 // A wrapper class for mach_msg_port_descriptor_t (with same memory layout)
75 // with convenient constructors and accessors
76 class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
77 public:
78 // General-purpose constructor
79 MachMsgPortDescriptor(mach_port_t in_name,
80 mach_msg_type_name_t in_disposition) {
81 name = in_name;
82 pad1 = 0;
83 pad2 = 0;
84 disposition = in_disposition;
85 type = MACH_MSG_PORT_DESCRIPTOR;
86 }
87
88 // For passing send rights to a port
89 MachMsgPortDescriptor(mach_port_t in_name) {
90 name = in_name;
91 pad1 = 0;
92 pad2 = 0;
93 disposition = MACH_MSG_TYPE_PORT_SEND;
94 type = MACH_MSG_PORT_DESCRIPTOR;
95 }
96
97 // Copy constructor
98 MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) {
99 name = desc.name;
100 pad1 = desc.pad1;
101 pad2 = desc.pad2;
102 disposition = desc.disposition;
103 type = desc.type;
104 }
105
106 mach_port_t GetMachPort() const {
107 return name;
108 }
109
110 mach_msg_type_name_t GetDisposition() const {
111 return disposition;
112 }
113
114 // For convenience
115 operator mach_port_t() const {
116 return GetMachPort();
117 }
118 };
119
120 //==============================================================================
121 // MachMessage: a wrapper for a mach message
122 // (mach_msg_header_t, mach_msg_body_t, extra data)
123 //
124 // This considerably simplifies the construction of a message for sending
125 // and the getting at relevant data and descriptors for the receiver.
126 //
127 // This class can be initialized using external storage of an arbitrary size
128 // or it can manage storage internally.
129 // 1. If storage is allocated internally, the combined size of the descriptors
130 // plus data must be less than 1024. But as a benefit no memory allocation is
131 // necessary.
132 // 2. For external storage, a buffer of at least EmptyMessageSize() must be
133 // provided.
134 //
135 // A MachMessage object is used by ReceivePort::WaitForMessage
136 // and MachPortSender::SendMessage
137 //
138 class MachMessage {
139 public:
140
141 virtual ~MachMessage();
142
143 // The receiver of the message can retrieve the raw data this way
144 u_int8_t *GetData() {
145 return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
146 }
147
148 u_int32_t GetDataLength() {
149 return EndianU32_LtoN(GetDataPacket()->data_length);
150 }
151
152 // The message ID may be used as a code identifying the type of message
153 void SetMessageID(int32_t message_id) {
154 GetDataPacket()->id = EndianU32_NtoL(message_id);
155 }
156
157 int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
158
159 // Adds a descriptor (typically a mach port) to be translated
160 // returns true if successful, otherwise not enough space
161 bool AddDescriptor(const MachMsgPortDescriptor &desc);
162
163 int GetDescriptorCount() const {
164 return storage_->body.msgh_descriptor_count;
165 }
166 MachMsgPortDescriptor *GetDescriptor(int n);
167
168 // Convenience method which gets the mach port described by the descriptor
169 mach_port_t GetTranslatedPort(int n);
170
171 // A simple message is one with no descriptors
172 bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
173
174 // Sets raw data for the message (returns false if not enough space)
175 bool SetData(const void* data, int32_t data_length);
176
177 protected:
178 // Consider this an abstract base class - must create an actual instance
179 // of MachReceiveMessage or MachSendMessage
180 MachMessage();
181
182 // Constructor for use with preallocate storage.
183 // storage_length must be >= EmptyMessageSize()
184 MachMessage(void *storage, size_t storage_length);
185
186 friend class ReceivePort;
187 friend class MachPortSender;
188
189 // Represents raw data in our message
190 struct MessageDataPacket {
191 int32_t id; // little-endian
192 int32_t data_length; // little-endian
193 u_int8_t data[1]; // actual size limited by storage_length_bytes_
194 };
195
196 MessageDataPacket* GetDataPacket();
197
198 void SetDescriptorCount(int n);
199 void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
200
201 // Returns total message size setting msgh_size in the header to this value
202 int CalculateSize();
203
204 // Returns total storage size that this object can grow to, this is inclusive
205 // of the mach header.
206 size_t MaxSize() const { return storage_length_bytes_; }
207
208 protected:
209 mach_msg_header_t *Head() { return &(storage_->head); }
210
211 private:
212 struct MachMessageData {
213 mach_msg_header_t head;
214 mach_msg_body_t body;
215 // descriptors and data may be embedded here.
216 u_int8_t padding[1024];
217 };
218
219 // kEmptyMessageSize needs to have the definition of MachMessageData before
220 // it.
221 public:
222 // The size of an empty message with no data.
223 static const size_t kEmptyMessageSize = sizeof(mach_msg_header_t) +
224 sizeof(mach_msg_body_t) +
225 sizeof(MessageDataPacket);
226
227 private:
228 MachMessageData *storage_;
229 size_t storage_length_bytes_;
230 bool own_storage_; // Is storage owned by this object?
231 };
232
233 //==============================================================================
234 // MachReceiveMessage and MachSendMessage are useful to separate the idea
235 // of a mach message being sent and being received, and adds increased type
236 // safety:
237 // ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
238 // MachPortSender::SendMessage() only accepts a MachSendMessage
239
240 //==============================================================================
241 class MachReceiveMessage : public MachMessage {
242 public:
243 MachReceiveMessage() : MachMessage() {}
244 MachReceiveMessage(void *storage, size_t storage_length)
245 : MachMessage(storage, storage_length) {}
246
247 private:
248 DISALLOW_COPY_AND_ASSIGN(MachReceiveMessage);
249 };
250
251 //==============================================================================
252 class MachSendMessage : public MachMessage {
253 public:
254 MachSendMessage(int32_t message_id);
255 MachSendMessage(void *storage, size_t storage_length, int32_t message_id);
256
257 private:
258 void Initialize(int32_t message_id);
259
260 DISALLOW_COPY_AND_ASSIGN(MachSendMessage);
261 };
262
263 //==============================================================================
264 // Represents a mach port for which we have receive rights
265 class ReceivePort {
266 public:
267 // Creates a new mach port for receiving messages and registers a name for it
268 ReceivePort(const char *receive_port_name);
269
270 // Given an already existing mach port, use it. We take ownership of the
271 // port and deallocate it in our destructor.
272 ReceivePort(mach_port_t receive_port);
273
274 // Create a new mach port for receiving messages
275 ReceivePort();
276
277 ~ReceivePort();
278
279 // Waits on the mach port until message received or timeout
280 kern_return_t WaitForMessage(MachReceiveMessage *out_message,
281 mach_msg_timeout_t timeout);
282
283 // The underlying mach port that we wrap
284 mach_port_t GetPort() const { return port_; }
285
286 private:
287 mach_port_t port_;
288 kern_return_t init_result_;
289
290 DISALLOW_COPY_AND_ASSIGN(ReceivePort);
291 };
292
293 //==============================================================================
294 // Represents a mach port for which we have send rights
295 class MachPortSender {
296 public:
297 // get a port with send rights corresponding to a named registered service
298 MachPortSender(const char *receive_port_name);
299
300
301 // Given an already existing mach port, use it.
302 MachPortSender(mach_port_t send_port);
303
304 kern_return_t SendMessage(MachSendMessage &message,
305 mach_msg_timeout_t timeout);
306
307 private:
308 mach_port_t send_port_;
309 kern_return_t init_result_;
310
311 DISALLOW_COPY_AND_ASSIGN(MachPortSender);
312 };
313
314 #endif // BASE_MACH_IPC_MAC_H_

mercurial