ipc/chromium/src/chrome/common/mach_ipc_mac.mm

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:7ddf0bd8e035
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 }

mercurial