1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/chrome/common/mach_ipc_mac.mm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,308 @@ 1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "chrome/common/mach_ipc_mac.h" 1.9 + 1.10 +#import <Foundation/Foundation.h> 1.11 + 1.12 +#include <stdio.h> 1.13 +#include "base/logging.h" 1.14 + 1.15 +//============================================================================== 1.16 +MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() { 1.17 + Initialize(message_id); 1.18 +} 1.19 + 1.20 +MachSendMessage::MachSendMessage(void *storage, size_t storage_length, 1.21 + int32_t message_id) 1.22 + : MachMessage(storage, storage_length) { 1.23 + Initialize(message_id); 1.24 +} 1.25 + 1.26 +void MachSendMessage::Initialize(int32_t message_id) { 1.27 + Head()->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); 1.28 + 1.29 + // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage() 1.30 + Head()->msgh_local_port = MACH_PORT_NULL; 1.31 + Head()->msgh_reserved = 0; 1.32 + Head()->msgh_id = 0; 1.33 + 1.34 + SetDescriptorCount(0); // start out with no descriptors 1.35 + 1.36 + SetMessageID(message_id); 1.37 + SetData(NULL, 0); // client may add data later 1.38 +} 1.39 + 1.40 +//============================================================================== 1.41 +MachMessage::MachMessage() 1.42 + : storage_(new MachMessageData), // Allocate storage_ ourselves 1.43 + storage_length_bytes_(sizeof(MachMessageData)), 1.44 + own_storage_(true) { 1.45 + memset(storage_, 0, storage_length_bytes_); 1.46 +} 1.47 + 1.48 +//============================================================================== 1.49 +MachMessage::MachMessage(void *storage, size_t storage_length) 1.50 + : storage_(static_cast<MachMessageData*>(storage)), 1.51 + storage_length_bytes_(storage_length), 1.52 + own_storage_(false) { 1.53 + DCHECK(storage); 1.54 + DCHECK(storage_length >= kEmptyMessageSize); 1.55 +} 1.56 + 1.57 +//============================================================================== 1.58 +MachMessage::~MachMessage() { 1.59 + if (own_storage_) { 1.60 + delete storage_; 1.61 + storage_ = NULL; 1.62 + } 1.63 +} 1.64 + 1.65 +//============================================================================== 1.66 +// returns true if successful 1.67 +bool MachMessage::SetData(const void* data, 1.68 + int32_t data_length) { 1.69 + // Enforce the fact that it's only safe to call this method once on a 1.70 + // message. 1.71 + DCHECK(GetDataPacket()->data_length == 0); 1.72 + 1.73 + // first check to make sure we have enough space 1.74 + int size = CalculateSize(); 1.75 + int new_size = size + data_length; 1.76 + 1.77 + if ((unsigned)new_size > storage_length_bytes_) { 1.78 + return false; // not enough space 1.79 + } 1.80 + 1.81 + GetDataPacket()->data_length = EndianU32_NtoL(data_length); 1.82 + if (data) memcpy(GetDataPacket()->data, data, data_length); 1.83 + 1.84 + // Update the Mach header with the new aligned size of the message. 1.85 + CalculateSize(); 1.86 + 1.87 + return true; 1.88 +} 1.89 + 1.90 +//============================================================================== 1.91 +// calculates and returns the total size of the message 1.92 +// Currently, the entire message MUST fit inside of the MachMessage 1.93 +// messsage size <= EmptyMessageSize() 1.94 +int MachMessage::CalculateSize() { 1.95 + int size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t); 1.96 + 1.97 + // add space for MessageDataPacket 1.98 + int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3; 1.99 + size += 2*sizeof(int32_t) + alignedDataLength; 1.100 + 1.101 + // add space for descriptors 1.102 + size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor); 1.103 + 1.104 + Head()->msgh_size = size; 1.105 + 1.106 + return size; 1.107 +} 1.108 + 1.109 +//============================================================================== 1.110 +MachMessage::MessageDataPacket *MachMessage::GetDataPacket() { 1.111 + int desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount(); 1.112 + MessageDataPacket *packet = 1.113 + reinterpret_cast<MessageDataPacket*>(storage_->padding + desc_size); 1.114 + 1.115 + return packet; 1.116 +} 1.117 + 1.118 +//============================================================================== 1.119 +void MachMessage::SetDescriptor(int n, 1.120 + const MachMsgPortDescriptor &desc) { 1.121 + MachMsgPortDescriptor *desc_array = 1.122 + reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding); 1.123 + desc_array[n] = desc; 1.124 +} 1.125 + 1.126 +//============================================================================== 1.127 +// returns true if successful otherwise there was not enough space 1.128 +bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) { 1.129 + // first check to make sure we have enough space 1.130 + int size = CalculateSize(); 1.131 + int new_size = size + sizeof(MachMsgPortDescriptor); 1.132 + 1.133 + if ((unsigned)new_size > storage_length_bytes_) { 1.134 + return false; // not enough space 1.135 + } 1.136 + 1.137 + // unfortunately, we need to move the data to allow space for the 1.138 + // new descriptor 1.139 + u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket()); 1.140 + bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t)); 1.141 + 1.142 + SetDescriptor(GetDescriptorCount(), desc); 1.143 + SetDescriptorCount(GetDescriptorCount() + 1); 1.144 + 1.145 + CalculateSize(); 1.146 + 1.147 + return true; 1.148 +} 1.149 + 1.150 +//============================================================================== 1.151 +void MachMessage::SetDescriptorCount(int n) { 1.152 + storage_->body.msgh_descriptor_count = n; 1.153 + 1.154 + if (n > 0) { 1.155 + Head()->msgh_bits |= MACH_MSGH_BITS_COMPLEX; 1.156 + } else { 1.157 + Head()->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX; 1.158 + } 1.159 +} 1.160 + 1.161 +//============================================================================== 1.162 +MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) { 1.163 + if (n < GetDescriptorCount()) { 1.164 + MachMsgPortDescriptor *desc = 1.165 + reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding); 1.166 + return desc + n; 1.167 + } 1.168 + 1.169 + return nil; 1.170 +} 1.171 + 1.172 +//============================================================================== 1.173 +mach_port_t MachMessage::GetTranslatedPort(int n) { 1.174 + if (n < GetDescriptorCount()) { 1.175 + return GetDescriptor(n)->GetMachPort(); 1.176 + } 1.177 + return MACH_PORT_NULL; 1.178 +} 1.179 + 1.180 +#pragma mark - 1.181 + 1.182 +//============================================================================== 1.183 +// create a new mach port for receiving messages and register a name for it 1.184 +ReceivePort::ReceivePort(const char *receive_port_name) { 1.185 + mach_port_t current_task = mach_task_self(); 1.186 + 1.187 + init_result_ = mach_port_allocate(current_task, 1.188 + MACH_PORT_RIGHT_RECEIVE, 1.189 + &port_); 1.190 + 1.191 + if (init_result_ != KERN_SUCCESS) 1.192 + return; 1.193 + 1.194 + init_result_ = mach_port_insert_right(current_task, 1.195 + port_, 1.196 + port_, 1.197 + MACH_MSG_TYPE_MAKE_SEND); 1.198 + 1.199 + if (init_result_ != KERN_SUCCESS) 1.200 + return; 1.201 + 1.202 + NSPort *ns_port = [NSMachPort portWithMachPort:port_]; 1.203 + NSString *port_name = [NSString stringWithUTF8String:receive_port_name]; 1.204 + [[NSMachBootstrapServer sharedInstance] registerPort:ns_port name:port_name]; 1.205 +} 1.206 + 1.207 +//============================================================================== 1.208 +// create a new mach port for receiving messages 1.209 +ReceivePort::ReceivePort() { 1.210 + mach_port_t current_task = mach_task_self(); 1.211 + 1.212 + init_result_ = mach_port_allocate(current_task, 1.213 + MACH_PORT_RIGHT_RECEIVE, 1.214 + &port_); 1.215 + 1.216 + if (init_result_ != KERN_SUCCESS) 1.217 + return; 1.218 + 1.219 + init_result_ = mach_port_insert_right(current_task, 1.220 + port_, 1.221 + port_, 1.222 + MACH_MSG_TYPE_MAKE_SEND); 1.223 +} 1.224 + 1.225 +//============================================================================== 1.226 +// Given an already existing mach port, use it. We take ownership of the 1.227 +// port and deallocate it in our destructor. 1.228 +ReceivePort::ReceivePort(mach_port_t receive_port) 1.229 + : port_(receive_port), 1.230 + init_result_(KERN_SUCCESS) { 1.231 +} 1.232 + 1.233 +//============================================================================== 1.234 +ReceivePort::~ReceivePort() { 1.235 + if (init_result_ == KERN_SUCCESS) 1.236 + mach_port_deallocate(mach_task_self(), port_); 1.237 +} 1.238 + 1.239 +//============================================================================== 1.240 +kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message, 1.241 + mach_msg_timeout_t timeout) { 1.242 + if (!out_message) { 1.243 + return KERN_INVALID_ARGUMENT; 1.244 + } 1.245 + 1.246 + // return any error condition encountered in constructor 1.247 + if (init_result_ != KERN_SUCCESS) 1.248 + return init_result_; 1.249 + 1.250 + out_message->Head()->msgh_bits = 0; 1.251 + out_message->Head()->msgh_local_port = port_; 1.252 + out_message->Head()->msgh_remote_port = MACH_PORT_NULL; 1.253 + out_message->Head()->msgh_reserved = 0; 1.254 + out_message->Head()->msgh_id = 0; 1.255 + 1.256 + kern_return_t result = mach_msg(out_message->Head(), 1.257 + MACH_RCV_MSG | MACH_RCV_TIMEOUT, 1.258 + 0, 1.259 + out_message->MaxSize(), 1.260 + port_, 1.261 + timeout, // timeout in ms 1.262 + MACH_PORT_NULL); 1.263 + 1.264 + return result; 1.265 +} 1.266 + 1.267 +#pragma mark - 1.268 + 1.269 +//============================================================================== 1.270 +// get a port with send rights corresponding to a named registered service 1.271 +MachPortSender::MachPortSender(const char *receive_port_name) { 1.272 + mach_port_t bootstrap_port = 0; 1.273 + init_result_ = task_get_bootstrap_port(mach_task_self(), &bootstrap_port); 1.274 + 1.275 + if (init_result_ != KERN_SUCCESS) 1.276 + return; 1.277 + 1.278 + init_result_ = bootstrap_look_up(bootstrap_port, 1.279 + const_cast<char*>(receive_port_name), 1.280 + &send_port_); 1.281 +} 1.282 + 1.283 +//============================================================================== 1.284 +MachPortSender::MachPortSender(mach_port_t send_port) 1.285 + : send_port_(send_port), 1.286 + init_result_(KERN_SUCCESS) { 1.287 +} 1.288 + 1.289 +//============================================================================== 1.290 +kern_return_t MachPortSender::SendMessage(MachSendMessage &message, 1.291 + mach_msg_timeout_t timeout) { 1.292 + if (message.Head()->msgh_size == 0) { 1.293 + NOTREACHED(); 1.294 + return KERN_INVALID_VALUE; // just for safety -- never should occur 1.295 + }; 1.296 + 1.297 + if (init_result_ != KERN_SUCCESS) 1.298 + return init_result_; 1.299 + 1.300 + message.Head()->msgh_remote_port = send_port_; 1.301 + 1.302 + kern_return_t result = mach_msg(message.Head(), 1.303 + MACH_SEND_MSG | MACH_SEND_TIMEOUT, 1.304 + message.Head()->msgh_size, 1.305 + 0, 1.306 + MACH_PORT_NULL, 1.307 + timeout, // timeout in ms 1.308 + MACH_PORT_NULL); 1.309 + 1.310 + return result; 1.311 +}