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