blob: b6dedd2b89190b7cea5dba167105c77db155e818 [file] [log] [blame]
[email protected]8e03fec2011-03-31 20:34:251// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]369537e82008-11-19 18:27:562// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]c0028792010-01-12 00:39:155#include "base/mach_ipc_mac.h"
[email protected]5062bb02008-11-20 21:11:206
7#import <Foundation/Foundation.h>
8
9#include <stdio.h>
10#include "base/logging.h"
[email protected]369537e82008-11-19 18:27:5611
[email protected]1fdb095d2010-01-12 21:33:4812namespace base {
13
[email protected]8e03fec2011-03-31 20:34:2514// static
[email protected]b4a45ea2011-03-31 20:52:0515const size_t MachMessage::kEmptyMessageSize = sizeof(mach_msg_header_t) +
[email protected]8e03fec2011-03-31 20:34:2516 sizeof(mach_msg_body_t) + sizeof(MessageDataPacket);
17
[email protected]369537e82008-11-19 18:27:5618//==============================================================================
19MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
[email protected]5062bb02008-11-20 21:11:2020 Initialize(message_id);
21}
22
23MachSendMessage::MachSendMessage(void *storage, size_t storage_length,
24 int32_t message_id)
25 : MachMessage(storage, storage_length) {
26 Initialize(message_id);
27}
28
29void MachSendMessage::Initialize(int32_t message_id) {
30 Head()->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
[email protected]369537e82008-11-19 18:27:5631
32 // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage()
[email protected]5062bb02008-11-20 21:11:2033 Head()->msgh_local_port = MACH_PORT_NULL;
34 Head()->msgh_reserved = 0;
35 Head()->msgh_id = 0;
[email protected]369537e82008-11-19 18:27:5636
37 SetDescriptorCount(0); // start out with no descriptors
38
39 SetMessageID(message_id);
40 SetData(NULL, 0); // client may add data later
41}
42
43//==============================================================================
[email protected]5062bb02008-11-20 21:11:2044MachMessage::MachMessage()
45 : storage_(new MachMessageData), // Allocate storage_ ourselves
46 storage_length_bytes_(sizeof(MachMessageData)),
47 own_storage_(true) {
48 memset(storage_, 0, storage_length_bytes_);
49}
50
51//==============================================================================
52MachMessage::MachMessage(void *storage, size_t storage_length)
53 : storage_(static_cast<MachMessageData*>(storage)),
54 storage_length_bytes_(storage_length),
55 own_storage_(false) {
56 DCHECK(storage);
[email protected]8e03fec2011-03-31 20:34:2557 DCHECK_GE(storage_length, kEmptyMessageSize);
[email protected]5062bb02008-11-20 21:11:2058}
59
60//==============================================================================
61MachMessage::~MachMessage() {
62 if (own_storage_) {
63 delete storage_;
64 storage_ = NULL;
65 }
66}
67
68//==============================================================================
[email protected]369537e82008-11-19 18:27:5669// returns true if successful
[email protected]5062bb02008-11-20 21:11:2070bool MachMessage::SetData(const void* data,
[email protected]369537e82008-11-19 18:27:5671 int32_t data_length) {
[email protected]5062bb02008-11-20 21:11:2072 // Enforce the fact that it's only safe to call this method once on a
73 // message.
74 DCHECK(GetDataPacket()->data_length == 0);
75
[email protected]369537e82008-11-19 18:27:5676 // first check to make sure we have enough space
77 int size = CalculateSize();
78 int new_size = size + data_length;
[email protected]5062bb02008-11-20 21:11:2079
80 if ((unsigned)new_size > storage_length_bytes_) {
[email protected]369537e82008-11-19 18:27:5681 return false; // not enough space
82 }
83
84 GetDataPacket()->data_length = EndianU32_NtoL(data_length);
85 if (data) memcpy(GetDataPacket()->data, data, data_length);
86
[email protected]5062bb02008-11-20 21:11:2087 // Update the Mach header with the new aligned size of the message.
[email protected]369537e82008-11-19 18:27:5688 CalculateSize();
89
90 return true;
91}
92
93//==============================================================================
94// calculates and returns the total size of the message
95// Currently, the entire message MUST fit inside of the MachMessage
[email protected]5062bb02008-11-20 21:11:2096// messsage size <= EmptyMessageSize()
[email protected]369537e82008-11-19 18:27:5697int MachMessage::CalculateSize() {
98 int size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t);
[email protected]5062bb02008-11-20 21:11:2099
[email protected]369537e82008-11-19 18:27:56100 // add space for MessageDataPacket
101 int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3;
102 size += 2*sizeof(int32_t) + alignedDataLength;
[email protected]5062bb02008-11-20 21:11:20103
[email protected]369537e82008-11-19 18:27:56104 // add space for descriptors
105 size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor);
[email protected]5062bb02008-11-20 21:11:20106
107 Head()->msgh_size = size;
108
[email protected]369537e82008-11-19 18:27:56109 return size;
110}
111
112//==============================================================================
113MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
114 int desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
115 MessageDataPacket *packet =
[email protected]5062bb02008-11-20 21:11:20116 reinterpret_cast<MessageDataPacket*>(storage_->padding + desc_size);
[email protected]369537e82008-11-19 18:27:56117
118 return packet;
119}
120
121//==============================================================================
122void MachMessage::SetDescriptor(int n,
123 const MachMsgPortDescriptor &desc) {
124 MachMsgPortDescriptor *desc_array =
[email protected]5062bb02008-11-20 21:11:20125 reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
[email protected]369537e82008-11-19 18:27:56126 desc_array[n] = desc;
127}
128
129//==============================================================================
130// returns true if successful otherwise there was not enough space
131bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
132 // first check to make sure we have enough space
133 int size = CalculateSize();
134 int new_size = size + sizeof(MachMsgPortDescriptor);
[email protected]5062bb02008-11-20 21:11:20135
136 if ((unsigned)new_size > storage_length_bytes_) {
[email protected]369537e82008-11-19 18:27:56137 return false; // not enough space
138 }
139
140 // unfortunately, we need to move the data to allow space for the
141 // new descriptor
142 u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
143 bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
[email protected]5062bb02008-11-20 21:11:20144
[email protected]369537e82008-11-19 18:27:56145 SetDescriptor(GetDescriptorCount(), desc);
146 SetDescriptorCount(GetDescriptorCount() + 1);
147
148 CalculateSize();
[email protected]5062bb02008-11-20 21:11:20149
[email protected]369537e82008-11-19 18:27:56150 return true;
151}
152
153//==============================================================================
154void MachMessage::SetDescriptorCount(int n) {
[email protected]5062bb02008-11-20 21:11:20155 storage_->body.msgh_descriptor_count = n;
[email protected]369537e82008-11-19 18:27:56156
157 if (n > 0) {
[email protected]5062bb02008-11-20 21:11:20158 Head()->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
[email protected]369537e82008-11-19 18:27:56159 } else {
[email protected]5062bb02008-11-20 21:11:20160 Head()->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
[email protected]369537e82008-11-19 18:27:56161 }
162}
163
164//==============================================================================
165MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
166 if (n < GetDescriptorCount()) {
167 MachMsgPortDescriptor *desc =
[email protected]5062bb02008-11-20 21:11:20168 reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
[email protected]369537e82008-11-19 18:27:56169 return desc + n;
170 }
[email protected]5062bb02008-11-20 21:11:20171
[email protected]369537e82008-11-19 18:27:56172 return nil;
173}
174
175//==============================================================================
176mach_port_t MachMessage::GetTranslatedPort(int n) {
177 if (n < GetDescriptorCount()) {
178 return GetDescriptor(n)->GetMachPort();
179 }
180 return MACH_PORT_NULL;
181}
182
183#pragma mark -
184
185//==============================================================================
186// create a new mach port for receiving messages and register a name for it
187ReceivePort::ReceivePort(const char *receive_port_name) {
188 mach_port_t current_task = mach_task_self();
189
190 init_result_ = mach_port_allocate(current_task,
191 MACH_PORT_RIGHT_RECEIVE,
192 &port_);
193
194 if (init_result_ != KERN_SUCCESS)
195 return;
[email protected]5062bb02008-11-20 21:11:20196
[email protected]369537e82008-11-19 18:27:56197 init_result_ = mach_port_insert_right(current_task,
198 port_,
199 port_,
200 MACH_MSG_TYPE_MAKE_SEND);
201
202 if (init_result_ != KERN_SUCCESS)
203 return;
204
[email protected]b88a7492010-09-17 12:28:32205 // Without |NSMachPortDeallocateNone|, the NSMachPort seems to deallocate
206 // receive rights on port when it is eventually released. It is not necessary
207 // to deallocate any rights here as |port_| is fully deallocated in the
208 // ReceivePort destructor.
209 NSPort *ns_port = [NSMachPort portWithMachPort:port_
210 options:NSMachPortDeallocateNone];
[email protected]5062bb02008-11-20 21:11:20211 NSString *port_name = [NSString stringWithUTF8String:receive_port_name];
212 [[NSMachBootstrapServer sharedInstance] registerPort:ns_port name:port_name];
[email protected]369537e82008-11-19 18:27:56213}
214
215//==============================================================================
216// create a new mach port for receiving messages
217ReceivePort::ReceivePort() {
218 mach_port_t current_task = mach_task_self();
219
220 init_result_ = mach_port_allocate(current_task,
221 MACH_PORT_RIGHT_RECEIVE,
222 &port_);
223
224 if (init_result_ != KERN_SUCCESS)
225 return;
226
[email protected]3740cb9b52009-12-19 04:50:04227 init_result_ = mach_port_insert_right(current_task,
228 port_,
229 port_,
230 MACH_MSG_TYPE_MAKE_SEND);
[email protected]369537e82008-11-19 18:27:56231}
232
233//==============================================================================
234// Given an already existing mach port, use it. We take ownership of the
235// port and deallocate it in our destructor.
236ReceivePort::ReceivePort(mach_port_t receive_port)
237 : port_(receive_port),
238 init_result_(KERN_SUCCESS) {
239}
240
241//==============================================================================
242ReceivePort::~ReceivePort() {
243 if (init_result_ == KERN_SUCCESS)
244 mach_port_deallocate(mach_task_self(), port_);
245}
246
247//==============================================================================
248kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
249 mach_msg_timeout_t timeout) {
250 if (!out_message) {
251 return KERN_INVALID_ARGUMENT;
252 }
253
254 // return any error condition encountered in constructor
255 if (init_result_ != KERN_SUCCESS)
256 return init_result_;
[email protected]369537e82008-11-19 18:27:56257
[email protected]5062bb02008-11-20 21:11:20258 out_message->Head()->msgh_bits = 0;
259 out_message->Head()->msgh_local_port = port_;
260 out_message->Head()->msgh_remote_port = MACH_PORT_NULL;
261 out_message->Head()->msgh_reserved = 0;
262 out_message->Head()->msgh_id = 0;
263
[email protected]b88a7492010-09-17 12:28:32264 mach_msg_option_t rcv_options = MACH_RCV_MSG;
265 if (timeout != MACH_MSG_TIMEOUT_NONE)
266 rcv_options |= MACH_RCV_TIMEOUT;
267
[email protected]5062bb02008-11-20 21:11:20268 kern_return_t result = mach_msg(out_message->Head(),
[email protected]b88a7492010-09-17 12:28:32269 rcv_options,
[email protected]369537e82008-11-19 18:27:56270 0,
[email protected]5062bb02008-11-20 21:11:20271 out_message->MaxSize(),
[email protected]369537e82008-11-19 18:27:56272 port_,
273 timeout, // timeout in ms
274 MACH_PORT_NULL);
275
276 return result;
277}
278
279#pragma mark -
280
281//==============================================================================
282// get a port with send rights corresponding to a named registered service
283MachPortSender::MachPortSender(const char *receive_port_name) {
284 mach_port_t bootstrap_port = 0;
285 init_result_ = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
[email protected]5062bb02008-11-20 21:11:20286
[email protected]369537e82008-11-19 18:27:56287 if (init_result_ != KERN_SUCCESS)
288 return;
289
290 init_result_ = bootstrap_look_up(bootstrap_port,
291 const_cast<char*>(receive_port_name),
292 &send_port_);
293}
294
295//==============================================================================
[email protected]5062bb02008-11-20 21:11:20296MachPortSender::MachPortSender(mach_port_t send_port)
[email protected]369537e82008-11-19 18:27:56297 : send_port_(send_port),
298 init_result_(KERN_SUCCESS) {
299}
300
301//==============================================================================
302kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
303 mach_msg_timeout_t timeout) {
[email protected]5062bb02008-11-20 21:11:20304 if (message.Head()->msgh_size == 0) {
305 NOTREACHED();
[email protected]369537e82008-11-19 18:27:56306 return KERN_INVALID_VALUE; // just for safety -- never should occur
307 };
[email protected]5062bb02008-11-20 21:11:20308
[email protected]369537e82008-11-19 18:27:56309 if (init_result_ != KERN_SUCCESS)
310 return init_result_;
[email protected]369537e82008-11-19 18:27:56311
[email protected]5062bb02008-11-20 21:11:20312 message.Head()->msgh_remote_port = send_port_;
313
314 kern_return_t result = mach_msg(message.Head(),
[email protected]369537e82008-11-19 18:27:56315 MACH_SEND_MSG | MACH_SEND_TIMEOUT,
[email protected]5062bb02008-11-20 21:11:20316 message.Head()->msgh_size,
[email protected]369537e82008-11-19 18:27:56317 0,
318 MACH_PORT_NULL,
319 timeout, // timeout in ms
320 MACH_PORT_NULL);
321
322 return result;
323}
[email protected]1fdb095d2010-01-12 21:33:48324
325} // namespace base