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