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.mm | |
31 // Wrapper for mach IPC calls | |
32 | |
33 #import <stdio.h> | |
34 #import "MachIPC.h" | |
35 | |
36 //============================================================================== | |
37 MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() { | |
38 head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); | |
39 | |
40 // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage() | |
41 head.msgh_local_port = MACH_PORT_NULL; | |
42 head.msgh_reserved = 0; | |
43 head.msgh_id = 0; | |
44 | |
45 SetDescriptorCount(0); // start out with no descriptors | |
46 | |
47 SetMessageID(message_id); | |
48 SetData(NULL, 0); // client may add data later | |
49 } | |
50 | |
51 //============================================================================== | |
52 // returns true if successful | |
53 bool MachMessage::SetData(void *data, | |
54 int32_t data_length) { | |
55 // first check to make sure we have enough space | |
56 int size = CalculateSize(); | |
57 int new_size = size + data_length; | |
58 | |
59 if ((unsigned)new_size > sizeof(MachMessage)) { | |
60 return false; // not enough space | |
61 } | |
62 | |
63 GetDataPacket()->data_length = EndianU32_NtoL(data_length); | |
64 if (data) memcpy(GetDataPacket()->data, data, data_length); | |
65 | |
66 CalculateSize(); | |
67 | |
68 return true; | |
69 } | |
70 | |
71 //============================================================================== | |
72 // calculates and returns the total size of the message | |
73 // Currently, the entire message MUST fit inside of the MachMessage | |
74 // messsage size <= sizeof(MachMessage) | |
75 int MachMessage::CalculateSize() { | |
76 int size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t); | |
77 | |
78 // add space for MessageDataPacket | |
79 int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3; | |
80 size += 2*sizeof(int32_t) + alignedDataLength; | |
81 | |
82 // add space for descriptors | |
83 size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor); | |
84 | |
85 head.msgh_size = size; | |
86 | |
87 return size; | |
88 } | |
89 | |
90 //============================================================================== | |
91 MachMessage::MessageDataPacket *MachMessage::GetDataPacket() { | |
92 int desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount(); | |
93 MessageDataPacket *packet = | |
94 reinterpret_cast<MessageDataPacket*>(padding + desc_size); | |
95 | |
96 return packet; | |
97 } | |
98 | |
99 //============================================================================== | |
100 void MachMessage::SetDescriptor(int n, | |
101 const MachMsgPortDescriptor &desc) { | |
102 MachMsgPortDescriptor *desc_array = | |
103 reinterpret_cast<MachMsgPortDescriptor*>(padding); | |
104 desc_array[n] = desc; | |
105 } | |
106 | |
107 //============================================================================== | |
108 // returns true if successful otherwise there was not enough space | |
109 bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) { | |
110 // first check to make sure we have enough space | |
111 int size = CalculateSize(); | |
112 int new_size = size + sizeof(MachMsgPortDescriptor); | |
113 | |
114 if ((unsigned)new_size > sizeof(MachMessage)) { | |
115 return false; // not enough space | |
116 } | |
117 | |
118 // unfortunately, we need to move the data to allow space for the | |
119 // new descriptor | |
120 u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket()); | |
121 bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t)); | |
122 | |
123 SetDescriptor(GetDescriptorCount(), desc); | |
124 SetDescriptorCount(GetDescriptorCount() + 1); | |
125 | |
126 CalculateSize(); | |
127 | |
128 return true; | |
129 } | |
130 | |
131 //============================================================================== | |
132 void MachMessage::SetDescriptorCount(int n) { | |
133 body.msgh_descriptor_count = n; | |
134 | |
135 if (n > 0) { | |
136 head.msgh_bits |= MACH_MSGH_BITS_COMPLEX; | |
137 } else { | |
138 head.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX; | |
139 } | |
140 } | |
141 | |
142 //============================================================================== | |
143 MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) { | |
144 if (n < GetDescriptorCount()) { | |
145 MachMsgPortDescriptor *desc = | |
146 reinterpret_cast<MachMsgPortDescriptor*>(padding); | |
147 return desc + n; | |
148 } | |
149 | |
150 return nil; | |
151 } | |
152 | |
153 //============================================================================== | |
154 mach_port_t MachMessage::GetTranslatedPort(int n) { | |
155 if (n < GetDescriptorCount()) { | |
156 return GetDescriptor(n)->GetMachPort(); | |
157 } | |
158 return MACH_PORT_NULL; | |
159 } | |
160 | |
161 #pragma mark - | |
162 | |
163 //============================================================================== | |
164 // create a new mach port for receiving messages and register a name for it | |
165 ReceivePort::ReceivePort(const char *receive_port_name) { | |
166 mach_port_t current_task = mach_task_self(); | |
167 | |
168 init_result_ = mach_port_allocate(current_task, | |
169 MACH_PORT_RIGHT_RECEIVE, | |
170 &port_); | |
171 | |
172 if (init_result_ != KERN_SUCCESS) | |
173 return; | |
174 | |
175 init_result_ = mach_port_insert_right(current_task, | |
176 port_, | |
177 port_, | |
178 MACH_MSG_TYPE_MAKE_SEND); | |
179 | |
180 if (init_result_ != KERN_SUCCESS) | |
181 return; | |
182 | |
183 mach_port_t bootstrap_port = 0; | |
184 init_result_ = task_get_bootstrap_port(current_task, &bootstrap_port); | |
185 | |
186 if (init_result_ != KERN_SUCCESS) | |
187 return; | |
188 | |
189 init_result_ = bootstrap_register(bootstrap_port, | |
190 const_cast<char*>(receive_port_name), | |
191 port_); | |
192 } | |
193 | |
194 //============================================================================== | |
195 // create a new mach port for receiving messages | |
196 ReceivePort::ReceivePort() { | |
197 mach_port_t current_task = mach_task_self(); | |
198 | |
199 init_result_ = mach_port_allocate(current_task, | |
200 MACH_PORT_RIGHT_RECEIVE, | |
201 &port_); | |
202 | |
203 if (init_result_ != KERN_SUCCESS) | |
204 return; | |
205 | |
206 init_result_ = mach_port_insert_right(current_task, | |
207 port_, | |
208 port_, | |
209 MACH_MSG_TYPE_MAKE_SEND); | |
210 } | |
211 | |
212 //============================================================================== | |
213 // Given an already existing mach port, use it. We take ownership of the | |
214 // port and deallocate it in our destructor. | |
215 ReceivePort::ReceivePort(mach_port_t receive_port) | |
216 : port_(receive_port), | |
217 init_result_(KERN_SUCCESS) { | |
218 } | |
219 | |
220 //============================================================================== | |
221 ReceivePort::~ReceivePort() { | |
222 if (init_result_ == KERN_SUCCESS) | |
223 mach_port_deallocate(mach_task_self(), port_); | |
224 } | |
225 | |
226 //============================================================================== | |
227 kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message, | |
228 mach_msg_timeout_t timeout) { | |
229 if (!out_message) { | |
230 return KERN_INVALID_ARGUMENT; | |
231 } | |
232 | |
233 // return any error condition encountered in constructor | |
234 if (init_result_ != KERN_SUCCESS) | |
235 return init_result_; | |
236 | |
237 out_message->head.msgh_bits = 0; | |
238 out_message->head.msgh_local_port = port_; | |
239 out_message->head.msgh_remote_port = MACH_PORT_NULL; | |
240 out_message->head.msgh_reserved = 0; | |
241 out_message->head.msgh_id = 0; | |
242 | |
243 kern_return_t result = mach_msg(&out_message->head, | |
244 MACH_RCV_MSG | MACH_RCV_TIMEOUT, | |
245 0, | |
246 sizeof(MachMessage), | |
247 port_, | |
248 timeout, // timeout in ms | |
249 MACH_PORT_NULL); | |
250 | |
251 return result; | |
252 } | |
253 | |
254 #pragma mark - | |
255 | |
256 //============================================================================== | |
257 // get a port with send rights corresponding to a named registered service | |
258 MachPortSender::MachPortSender(const char *receive_port_name) { | |
259 mach_port_t bootstrap_port = 0; | |
260 init_result_ = task_get_bootstrap_port(mach_task_self(), &bootstrap_port); | |
261 | |
262 if (init_result_ != KERN_SUCCESS) | |
263 return; | |
264 | |
265 init_result_ = bootstrap_look_up(bootstrap_port, | |
266 const_cast<char*>(receive_port_name), | |
267 &send_port_); | |
268 } | |
269 | |
270 //============================================================================== | |
271 MachPortSender::MachPortSender(mach_port_t send_port) | |
272 : send_port_(send_port), | |
273 init_result_(KERN_SUCCESS) { | |
274 } | |
275 | |
276 //============================================================================== | |
277 kern_return_t MachPortSender::SendMessage(MachSendMessage &message, | |
278 mach_msg_timeout_t timeout) { | |
279 if (message.head.msgh_size == 0) { | |
280 return KERN_INVALID_VALUE; // just for safety -- never should occur | |
281 }; | |
282 | |
283 if (init_result_ != KERN_SUCCESS) | |
284 return init_result_; | |
285 | |
286 message.head.msgh_remote_port = send_port_; | |
287 | |
288 kern_return_t result = mach_msg(&message.head, | |
289 MACH_SEND_MSG | MACH_SEND_TIMEOUT, | |
290 message.head.msgh_size, | |
291 0, | |
292 MACH_PORT_NULL, | |
293 timeout, // timeout in ms | |
294 MACH_PORT_NULL); | |
295 | |
296 return result; | |
297 } | |
OLD | NEW |