OLD | NEW |
| (Empty) |
1 // Copyright (c) 2007, Google Inc. | |
2 // All rights reserved. | |
3 // | |
4 // Redistribution and use in source and binary forms, with or without | |
5 // modification, are permitted provided that the following conditions are | |
6 // met: | |
7 // | |
8 // * Redistributions of source code must retain the above copyright | |
9 // notice, this list of conditions and the following disclaimer. | |
10 // * Redistributions in binary form must reproduce the above | |
11 // copyright notice, this list of conditions and the following disclaimer | |
12 // in the documentation and/or other materials provided with the | |
13 // distribution. | |
14 // * Neither the name of Google Inc. nor the names of its | |
15 // contributors may be used to endorse or promote products derived from | |
16 // this software without specific prior written permission. | |
17 // | |
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 // | |
30 // MachIPC.h | |
31 // | |
32 // Some helpful wrappers for using Mach IPC calls | |
33 | |
34 #ifndef MACH_IPC_H__ | |
35 #define MACH_IPC_H__ | |
36 | |
37 #import <mach/mach.h> | |
38 #import <mach/message.h> | |
39 #import <servers/bootstrap.h> | |
40 #import <sys/types.h> | |
41 | |
42 #import <CoreServices/CoreServices.h> | |
43 | |
44 //============================================================================== | |
45 // DISCUSSION: | |
46 // | |
47 // The three main classes of interest are | |
48 // | |
49 // MachMessage: a wrapper for a mach message of the following form | |
50 // mach_msg_header_t | |
51 // mach_msg_body_t | |
52 // optional descriptors | |
53 // optional extra message data | |
54 // | |
55 // MachReceiveMessage and MachSendMessage subclass MachMessage | |
56 // and are used instead of MachMessage which is an abstract base class | |
57 // | |
58 // ReceivePort: | |
59 // Represents a mach port for which we have receive rights | |
60 // | |
61 // MachPortSender: | |
62 // Represents a mach port for which we have send rights | |
63 // | |
64 // Here's an example to receive a message on a server port: | |
65 // | |
66 // // This creates our named server port | |
67 // ReceivePort receivePort("com.Google.MyService"); | |
68 // | |
69 // MachReceiveMessage message; | |
70 // kern_return_t result = receivePort.WaitForMessage(&message, 0); | |
71 // | |
72 // if (result == KERN_SUCCESS && message.GetMessageID() == 57) { | |
73 // mach_port_t task = message.GetTranslatedPort(0); | |
74 // mach_port_t thread = message.GetTranslatedPort(1); | |
75 // | |
76 // char *messageString = message.GetData(); | |
77 // | |
78 // printf("message string = %s\n", messageString); | |
79 // } | |
80 // | |
81 // Here is an example of using these classes to send a message to this port: | |
82 // | |
83 // // send to already named port | |
84 // MachPortSender sender("com.Google.MyService"); | |
85 // MachSendMessage message(57); // our message ID is 57 | |
86 // | |
87 // // add some ports to be translated for us | |
88 // message.AddDescriptor(mach_task_self()); // our task | |
89 // message.AddDescriptor(mach_thread_self()); // this thread | |
90 // | |
91 // char messageString[] = "Hello server!\n"; | |
92 // message.SetData(messageString, strlen(messageString)+1); | |
93 // | |
94 // kern_return_t result = sender.SendMessage(message, 1000); // timeout 1000m
s | |
95 // | |
96 | |
97 #define PRINT_MACH_RESULT(result_, message_) \ | |
98 printf(message_" %s (%d)\n", mach_error_string(result_), result_ ); | |
99 | |
100 //============================================================================== | |
101 // A wrapper class for mach_msg_port_descriptor_t (with same memory layout) | |
102 // with convenient constructors and accessors | |
103 class MachMsgPortDescriptor : public mach_msg_port_descriptor_t { | |
104 public: | |
105 // General-purpose constructor | |
106 MachMsgPortDescriptor(mach_port_t in_name, | |
107 mach_msg_type_name_t in_disposition) { | |
108 name = in_name; | |
109 pad1 = 0; | |
110 pad2 = 0; | |
111 disposition = in_disposition; | |
112 type = MACH_MSG_PORT_DESCRIPTOR; | |
113 } | |
114 | |
115 // For passing send rights to a port | |
116 MachMsgPortDescriptor(mach_port_t in_name) { | |
117 name = in_name; | |
118 pad1 = 0; | |
119 pad2 = 0; | |
120 disposition = MACH_MSG_TYPE_COPY_SEND; | |
121 type = MACH_MSG_PORT_DESCRIPTOR; | |
122 } | |
123 | |
124 // Copy constructor | |
125 MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) { | |
126 name = desc.name; | |
127 pad1 = desc.pad1; | |
128 pad2 = desc.pad2; | |
129 disposition = desc.disposition; | |
130 type = desc.type; | |
131 } | |
132 | |
133 mach_port_t GetMachPort() const { | |
134 return name; | |
135 } | |
136 | |
137 mach_msg_type_name_t GetDisposition() const { | |
138 return disposition; | |
139 } | |
140 | |
141 // We're just a simple wrapper for mach_msg_port_descriptor_t | |
142 // and have the same memory layout | |
143 operator mach_msg_port_descriptor_t&() { | |
144 return *this; | |
145 } | |
146 | |
147 // For convenience | |
148 operator mach_port_t() const { | |
149 return GetMachPort(); | |
150 } | |
151 }; | |
152 | |
153 //============================================================================== | |
154 // MachMessage: a wrapper for a mach message | |
155 // (mach_msg_header_t, mach_msg_body_t, extra data) | |
156 // | |
157 // This considerably simplifies the construction of a message for sending | |
158 // and the getting at relevant data and descriptors for the receiver. | |
159 // | |
160 // Currently the combined size of the descriptors plus data must be | |
161 // less than 1024. But as a benefit no memory allocation is necessary. | |
162 // | |
163 // TODO: could consider adding malloc() support for very large messages | |
164 // | |
165 // A MachMessage object is used by ReceivePort::WaitForMessage | |
166 // and MachPortSender::SendMessage | |
167 // | |
168 class MachMessage { | |
169 public: | |
170 | |
171 // The receiver of the message can retrieve the raw data this way | |
172 u_int8_t *GetData() { | |
173 return GetDataLength() > 0 ? GetDataPacket()->data : NULL; | |
174 } | |
175 | |
176 u_int32_t GetDataLength() { | |
177 return EndianU32_LtoN(GetDataPacket()->data_length); | |
178 } | |
179 | |
180 // The message ID may be used as a code identifying the type of message | |
181 void SetMessageID(int32_t message_id) { | |
182 GetDataPacket()->id = EndianU32_NtoL(message_id); | |
183 } | |
184 | |
185 int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); } | |
186 | |
187 // Adds a descriptor (typically a mach port) to be translated | |
188 // returns true if successful, otherwise not enough space | |
189 bool AddDescriptor(const MachMsgPortDescriptor &desc); | |
190 | |
191 int GetDescriptorCount() const { return body.msgh_descriptor_count; } | |
192 MachMsgPortDescriptor *GetDescriptor(int n); | |
193 | |
194 // Convenience method which gets the mach port described by the descriptor | |
195 mach_port_t GetTranslatedPort(int n); | |
196 | |
197 // A simple message is one with no descriptors | |
198 bool IsSimpleMessage() const { return GetDescriptorCount() == 0; } | |
199 | |
200 // Sets raw data for the message (returns false if not enough space) | |
201 bool SetData(void *data, int32_t data_length); | |
202 | |
203 protected: | |
204 // Consider this an abstract base class - must create an actual instance | |
205 // of MachReceiveMessage or MachSendMessage | |
206 | |
207 MachMessage() { | |
208 memset(this, 0, sizeof(MachMessage)); | |
209 } | |
210 | |
211 friend class ReceivePort; | |
212 friend class MachPortSender; | |
213 | |
214 // Represents raw data in our message | |
215 struct MessageDataPacket { | |
216 int32_t id; // little-endian | |
217 int32_t data_length; // little-endian | |
218 u_int8_t data[1]; // actual size limited by sizeof(MachMessage) | |
219 }; | |
220 | |
221 MessageDataPacket* GetDataPacket(); | |
222 | |
223 void SetDescriptorCount(int n); | |
224 void SetDescriptor(int n, const MachMsgPortDescriptor &desc); | |
225 | |
226 // Returns total message size setting msgh_size in the header to this value | |
227 int CalculateSize(); | |
228 | |
229 mach_msg_header_t head; | |
230 mach_msg_body_t body; | |
231 u_int8_t padding[1024]; // descriptors and data may be embedded here | |
232 }; | |
233 | |
234 //============================================================================== | |
235 // MachReceiveMessage and MachSendMessage are useful to separate the idea | |
236 // of a mach message being sent and being received, and adds increased type | |
237 // safety: | |
238 // ReceivePort::WaitForMessage() only accepts a MachReceiveMessage | |
239 // MachPortSender::SendMessage() only accepts a MachSendMessage | |
240 | |
241 //============================================================================== | |
242 class MachReceiveMessage : public MachMessage { | |
243 public: | |
244 MachReceiveMessage() : MachMessage() {}; | |
245 }; | |
246 | |
247 //============================================================================== | |
248 class MachSendMessage : public MachMessage { | |
249 public: | |
250 MachSendMessage(int32_t message_id); | |
251 }; | |
252 | |
253 //============================================================================== | |
254 // Represents a mach port for which we have receive rights | |
255 class ReceivePort { | |
256 public: | |
257 // Creates a new mach port for receiving messages and registers a name for it | |
258 ReceivePort(const char *receive_port_name); | |
259 | |
260 // Given an already existing mach port, use it. We take ownership of the | |
261 // port and deallocate it in our destructor. | |
262 ReceivePort(mach_port_t receive_port); | |
263 | |
264 // Create a new mach port for receiving messages | |
265 ReceivePort(); | |
266 | |
267 ~ReceivePort(); | |
268 | |
269 // Waits on the mach port until message received or timeout | |
270 kern_return_t WaitForMessage(MachReceiveMessage *out_message, | |
271 mach_msg_timeout_t timeout); | |
272 | |
273 // The underlying mach port that we wrap | |
274 mach_port_t GetPort() const { return port_; } | |
275 | |
276 private: | |
277 ReceivePort(const ReceivePort&); // disable copy c-tor | |
278 | |
279 mach_port_t port_; | |
280 kern_return_t init_result_; | |
281 }; | |
282 | |
283 //============================================================================== | |
284 // Represents a mach port for which we have send rights | |
285 class MachPortSender { | |
286 public: | |
287 // get a port with send rights corresponding to a named registered service | |
288 MachPortSender(const char *receive_port_name); | |
289 | |
290 | |
291 // Given an already existing mach port, use it. | |
292 MachPortSender(mach_port_t send_port); | |
293 | |
294 kern_return_t SendMessage(MachSendMessage &message, | |
295 mach_msg_timeout_t timeout); | |
296 | |
297 private: | |
298 MachPortSender(const MachPortSender&); // disable copy c-tor | |
299 | |
300 mach_port_t send_port_; | |
301 kern_return_t init_result_; | |
302 }; | |
303 | |
304 #endif // MACH_IPC_H__ | |
OLD | NEW |