1 // Copyright (c) 2011 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 12 namespace base { 13 14 // static 15 const size_t MachMessage::kEmptyMessageSize = sizeof(mach_msg_header_t) + 16 sizeof(mach_msg_body_t) + sizeof(MessageDataPacket); 17 18 //============================================================================== 19 MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() { 20 Initialize(message_id); 21 } 22 23 MachSendMessage::MachSendMessage(void *storage, size_t storage_length, 24 int32_t message_id) 25 : MachMessage(storage, storage_length) { 26 Initialize(message_id); 27 } 28 29 void MachSendMessage::Initialize(int32_t message_id) { 30 Head()->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); 31 32 // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage() 33 Head()->msgh_local_port = MACH_PORT_NULL; 34 Head()->msgh_reserved = 0; 35 Head()->msgh_id = 0; 36 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 //============================================================================== 44 MachMessage::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 //============================================================================== 52 MachMessage::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); 57 DCHECK_GE(storage_length, kEmptyMessageSize); 58 } 59 60 //============================================================================== 61 MachMessage::~MachMessage() { 62 if (own_storage_) { 63 delete storage_; 64 storage_ = NULL; 65 } 66 } 67 68 //============================================================================== 69 // returns true if successful 70 bool MachMessage::SetData(const void* data, 71 int32_t data_length) { 72 // Enforce the fact that it's only safe to call this method once on a 73 // message. 74 DCHECK(GetDataPacket()->data_length == 0); 75 76 // first check to make sure we have enough space 77 int size = CalculateSize(); 78 int new_size = size + data_length; 79 80 if ((unsigned)new_size > storage_length_bytes_) { 81 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 87 // Update the Mach header with the new aligned size of the message. 88 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 96 // messsage size <= EmptyMessageSize() 97 int MachMessage::CalculateSize() { 98 int size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t); 99 100 // add space for MessageDataPacket 101 int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3; 102 size += 2*sizeof(int32_t) + alignedDataLength; 103 104 // add space for descriptors 105 size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor); 106 107 Head()->msgh_size = size; 108 109 return size; 110 } 111 112 //============================================================================== 113 MachMessage::MessageDataPacket *MachMessage::GetDataPacket() { 114 int desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount(); 115 MessageDataPacket *packet = 116 reinterpret_cast<MessageDataPacket*>(storage_->padding + desc_size); 117 118 return packet; 119 } 120 121 //============================================================================== 122 void MachMessage::SetDescriptor(int n, 123 const MachMsgPortDescriptor &desc) { 124 MachMsgPortDescriptor *desc_array = 125 reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding); 126 desc_array[n] = desc; 127 } 128 129 //============================================================================== 130 // returns true if successful otherwise there was not enough space 131 bool 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); 135 136 if ((unsigned)new_size > storage_length_bytes_) { 137 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)); 144 145 SetDescriptor(GetDescriptorCount(), desc); 146 SetDescriptorCount(GetDescriptorCount() + 1); 147 148 CalculateSize(); 149 150 return true; 151 } 152 153 //============================================================================== 154 void MachMessage::SetDescriptorCount(int n) { 155 storage_->body.msgh_descriptor_count = n; 156 157 if (n > 0) { 158 Head()->msgh_bits |= MACH_MSGH_BITS_COMPLEX; 159 } else { 160 Head()->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX; 161 } 162 } 163 164 //============================================================================== 165 MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) { 166 if (n < GetDescriptorCount()) { 167 MachMsgPortDescriptor *desc = 168 reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding); 169 return desc + n; 170 } 171 172 return nil; 173 } 174 175 //============================================================================== 176 mach_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 187 ReceivePort::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; 196 197 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 205 // 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]; 211 NSString *port_name = [NSString stringWithUTF8String:receive_port_name]; 212 [[NSMachBootstrapServer sharedInstance] registerPort:ns_port name:port_name]; 213 } 214 215 //============================================================================== 216 // create a new mach port for receiving messages 217 ReceivePort::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 227 init_result_ = mach_port_insert_right(current_task, 228 port_, 229 port_, 230 MACH_MSG_TYPE_MAKE_SEND); 231 } 232 233 //============================================================================== 234 // Given an already existing mach port, use it. We take ownership of the 235 // port and deallocate it in our destructor. 236 ReceivePort::ReceivePort(mach_port_t receive_port) 237 : port_(receive_port), 238 init_result_(KERN_SUCCESS) { 239 } 240 241 //============================================================================== 242 ReceivePort::~ReceivePort() { 243 if (init_result_ == KERN_SUCCESS) 244 mach_port_deallocate(mach_task_self(), port_); 245 } 246 247 //============================================================================== 248 kern_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_; 257 258 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 264 mach_msg_option_t rcv_options = MACH_RCV_MSG; 265 if (timeout != MACH_MSG_TIMEOUT_NONE) 266 rcv_options |= MACH_RCV_TIMEOUT; 267 268 kern_return_t result = mach_msg(out_message->Head(), 269 rcv_options, 270 0, 271 out_message->MaxSize(), 272 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 283 MachPortSender::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); 286 287 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 //============================================================================== 296 MachPortSender::MachPortSender(mach_port_t send_port) 297 : send_port_(send_port), 298 init_result_(KERN_SUCCESS) { 299 } 300 301 //============================================================================== 302 kern_return_t MachPortSender::SendMessage(MachSendMessage &message, 303 mach_msg_timeout_t timeout) { 304 if (message.Head()->msgh_size == 0) { 305 NOTREACHED(); 306 return KERN_INVALID_VALUE; // just for safety -- never should occur 307 }; 308 309 if (init_result_ != KERN_SUCCESS) 310 return init_result_; 311 312 message.Head()->msgh_remote_port = send_port_; 313 314 kern_return_t result = mach_msg(message.Head(), 315 MACH_SEND_MSG | MACH_SEND_TIMEOUT, 316 message.Head()->msgh_size, 317 0, 318 MACH_PORT_NULL, 319 timeout, // timeout in ms 320 MACH_PORT_NULL); 321 322 return result; 323 } 324 325 } // namespace base 326