OLD | NEW |
| (Empty) |
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. | |
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/base_export.h" | |
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 | |
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 // | |
141 class BASE_EXPORT 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() const { | |
149 return GetDataLength() > 0 ? GetDataPacket()->data : NULL; | |
150 } | |
151 | |
152 u_int32_t GetDataLength() const { | |
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() const { 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) const; | |
172 | |
173 // Convenience method which gets the Mach port described by the descriptor | |
174 mach_port_t GetTranslatedPort(int n) const; | |
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() const; | |
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() const { 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: | |
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 //============================================================================== | |
247 class BASE_EXPORT 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 BASE_EXPORT 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 | |
291 class BASE_EXPORT 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(const MachSendMessage& message, | |
302 mach_msg_timeout_t timeout); | |
303 | |
304 mach_port_t GetPort() const { return send_port_; } | |
305 | |
306 private: | |
307 mach_port_t send_port_; | |
308 kern_return_t init_result_; | |
309 | |
310 DISALLOW_COPY_AND_ASSIGN(MachPortSender); | |
311 }; | |
312 | |
313 //============================================================================== | |
314 // Static utility functions. | |
315 | |
316 namespace mac { | |
317 | |
318 // Returns the number of Mach ports to which the given task has a right. | |
319 // Note that unless the calling task has send rights to the passed task port, | |
320 // this will fail unless the calling task is running as root. | |
321 kern_return_t BASE_EXPORT GetNumberOfMachPorts(mach_port_t task_port, | |
322 int* port_count); | |
323 | |
324 } // namespace mac | |
325 | |
326 } // namespace base | |
327 | |
328 #endif // BASE_MACH_IPC_MAC_H_ | |
OLD | NEW |