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#ifndef BASE_MACH_IPC_MAC_H_ 6#define BASE_MACH_IPC_MAC_H_ 7#pragma once 8 9#include <mach/mach.h> 10#include <mach/message.h> 11#include <servers/bootstrap.h> 12#include <sys/types.h> 13 14#include <CoreServices/CoreServices.h> 15 16#include "base/basictypes.h" 17 18//============================================================================== 19// DISCUSSION: 20// 21// The three main classes of interest are 22// 23// MachMessage: a wrapper for a Mach message of the following form 24// mach_msg_header_t 25// mach_msg_body_t 26// optional descriptors 27// optional extra message data 28// 29// MachReceiveMessage and MachSendMessage subclass MachMessage 30// and are used instead of MachMessage which is an abstract base class 31// 32// ReceivePort: 33// Represents a Mach port for which we have receive rights 34// 35// MachPortSender: 36// Represents a Mach port for which we have send rights 37// 38// Here's an example to receive a message on a server port: 39// 40// // This creates our named server port 41// ReceivePort receivePort("com.Google.MyService"); 42// 43// MachReceiveMessage message; 44// kern_return_t result = receivePort.WaitForMessage(&message, 0); 45// 46// if (result == KERN_SUCCESS && message.GetMessageID() == 57) { 47// mach_port_t task = message.GetTranslatedPort(0); 48// mach_port_t thread = message.GetTranslatedPort(1); 49// 50// char *messageString = message.GetData(); 51// 52// printf("message string = %s\n", messageString); 53// } 54// 55// Here is an example of using these classes to send a message to this port: 56// 57// // send to already named port 58// MachPortSender sender("com.Google.MyService"); 59// MachSendMessage message(57); // our message ID is 57 60// 61// // add some ports to be translated for us 62// message.AddDescriptor(mach_task_self()); // our task 63// message.AddDescriptor(mach_thread_self()); // this thread 64// 65// char messageString[] = "Hello server!\n"; 66// message.SetData(messageString, strlen(messageString)+1); 67// // timeout 1000ms 68// kern_return_t result = sender.SendMessage(message, 1000); 69// 70 71#define PRINT_MACH_RESULT(result_, message_) \ 72 printf(message_" %s (%d)\n", mach_error_string(result_), result_ ); 73 74namespace base { 75 76//============================================================================== 77// A wrapper class for mach_msg_port_descriptor_t (with same memory layout) 78// with convenient constructors and accessors 79class MachMsgPortDescriptor : public mach_msg_port_descriptor_t { 80 public: 81 // General-purpose constructor 82 MachMsgPortDescriptor(mach_port_t in_name, 83 mach_msg_type_name_t in_disposition) { 84 name = in_name; 85 pad1 = 0; 86 pad2 = 0; 87 disposition = in_disposition; 88 type = MACH_MSG_PORT_DESCRIPTOR; 89 } 90 91 // For passing send rights to a port 92 MachMsgPortDescriptor(mach_port_t in_name) { 93 name = in_name; 94 pad1 = 0; 95 pad2 = 0; 96 disposition = MACH_MSG_TYPE_PORT_SEND; 97 type = MACH_MSG_PORT_DESCRIPTOR; 98 } 99 100 // Copy constructor 101 MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) { 102 name = desc.name; 103 pad1 = desc.pad1; 104 pad2 = desc.pad2; 105 disposition = desc.disposition; 106 type = desc.type; 107 } 108 109 mach_port_t GetMachPort() const { 110 return name; 111 } 112 113 mach_msg_type_name_t GetDisposition() const { 114 return disposition; 115 } 116 117 // For convenience 118 operator mach_port_t() const { 119 return GetMachPort(); 120 } 121}; 122 123//============================================================================== 124// MachMessage: a wrapper for a Mach message 125// (mach_msg_header_t, mach_msg_body_t, extra data) 126// 127// This considerably simplifies the construction of a message for sending 128// and the getting at relevant data and descriptors for the receiver. 129// 130// This class can be initialized using external storage of an arbitrary size 131// or it can manage storage internally. 132// 1. If storage is allocated internally, the combined size of the descriptors 133// plus data must be less than 1024. But as a benefit no memory allocation is 134// necessary. 135// 2. For external storage, a buffer of at least EmptyMessageSize() must be 136// provided. 137// 138// A MachMessage object is used by ReceivePort::WaitForMessage 139// and MachPortSender::SendMessage 140// 141class MachMessage { 142 public: 143 static const size_t kEmptyMessageSize; 144 145 virtual ~MachMessage(); 146 147 // The receiver of the message can retrieve the raw data this way 148 u_int8_t *GetData() { 149 return GetDataLength() > 0 ? GetDataPacket()->data : NULL; 150 } 151 152 u_int32_t GetDataLength() { 153 return EndianU32_LtoN(GetDataPacket()->data_length); 154 } 155 156 // The message ID may be used as a code identifying the type of message 157 void SetMessageID(int32_t message_id) { 158 GetDataPacket()->id = EndianU32_NtoL(message_id); 159 } 160 161 int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); } 162 163 // Adds a descriptor (typically a Mach port) to be translated 164 // returns true if successful, otherwise not enough space 165 bool AddDescriptor(const MachMsgPortDescriptor &desc); 166 167 int GetDescriptorCount() const { 168 return storage_->body.msgh_descriptor_count; 169 } 170 171 MachMsgPortDescriptor *GetDescriptor(int n); 172 173 // Convenience method which gets the Mach port described by the descriptor 174 mach_port_t GetTranslatedPort(int n); 175 176 // A simple message is one with no descriptors 177 bool IsSimpleMessage() const { return GetDescriptorCount() == 0; } 178 179 // Sets raw data for the message (returns false if not enough space) 180 bool SetData(const void* data, int32_t data_length); 181 182 protected: 183 // Consider this an abstract base class - must create an actual instance 184 // of MachReceiveMessage or MachSendMessage 185 MachMessage(); 186 187 // Constructor for use with preallocate storage. 188 // storage_length must be >= EmptyMessageSize() 189 MachMessage(void *storage, size_t storage_length); 190 191 friend class ReceivePort; 192 friend class MachPortSender; 193 194 // Represents raw data in our message 195 struct MessageDataPacket { 196 int32_t id; // little-endian 197 int32_t data_length; // little-endian 198 u_int8_t data[1]; // actual size limited by storage_length_bytes_ 199 }; 200 201 MessageDataPacket* GetDataPacket(); 202 203 void SetDescriptorCount(int n); 204 void SetDescriptor(int n, const MachMsgPortDescriptor &desc); 205 206 // Returns total message size setting msgh_size in the header to this value 207 int CalculateSize(); 208 209 // Returns total storage size that this object can grow to, this is inclusive 210 // of the Mach header. 211 size_t MaxSize() const { return storage_length_bytes_; } 212 213 mach_msg_header_t *Head() { return &(storage_->head); } 214 215 private: 216 struct MachMessageData { 217 mach_msg_header_t head; 218 mach_msg_body_t body; 219 // descriptors and data may be embedded here. 220 u_int8_t padding[1024]; 221 }; 222 223 MachMessageData *storage_; 224 size_t storage_length_bytes_; 225 bool own_storage_; // Is storage owned by this object? 226}; 227 228//============================================================================== 229// MachReceiveMessage and MachSendMessage are useful to separate the idea 230// of a Mach message being sent and being received, and adds increased type 231// safety: 232// ReceivePort::WaitForMessage() only accepts a MachReceiveMessage 233// MachPortSender::SendMessage() only accepts a MachSendMessage 234 235//============================================================================== 236class MachReceiveMessage : public MachMessage { 237 public: 238 MachReceiveMessage() : MachMessage() {} 239 MachReceiveMessage(void *storage, size_t storage_length) 240 : MachMessage(storage, storage_length) {} 241 242 private: 243 DISALLOW_COPY_AND_ASSIGN(MachReceiveMessage); 244}; 245 246//============================================================================== 247class MachSendMessage : public MachMessage { 248 public: 249 explicit MachSendMessage(int32_t message_id); 250 MachSendMessage(void *storage, size_t storage_length, int32_t message_id); 251 252 private: 253 void Initialize(int32_t message_id); 254 255 DISALLOW_COPY_AND_ASSIGN(MachSendMessage); 256}; 257 258//============================================================================== 259// Represents a Mach port for which we have receive rights 260class ReceivePort { 261 public: 262 // Creates a new Mach port for receiving messages and registers a name for it 263 explicit ReceivePort(const char *receive_port_name); 264 265 // Given an already existing Mach port, use it. We take ownership of the 266 // port and deallocate it in our destructor. 267 explicit ReceivePort(mach_port_t receive_port); 268 269 // Create a new Mach port for receiving messages 270 ReceivePort(); 271 272 ~ReceivePort(); 273 274 // Waits on the Mach port until message received or timeout. If |timeout| is 275 // MACH_MSG_TIMEOUT_NONE, this method waits forever. 276 kern_return_t WaitForMessage(MachReceiveMessage *out_message, 277 mach_msg_timeout_t timeout); 278 279 // The underlying Mach port that we wrap 280 mach_port_t GetPort() const { return port_; } 281 282 private: 283 mach_port_t port_; 284 kern_return_t init_result_; 285 286 DISALLOW_COPY_AND_ASSIGN(ReceivePort); 287}; 288 289//============================================================================== 290// Represents a Mach port for which we have send rights 291class MachPortSender { 292 public: 293 // get a port with send rights corresponding to a named registered service 294 explicit MachPortSender(const char *receive_port_name); 295 296 297 // Given an already existing Mach port, use it. Does not take ownership of 298 // |send_port|. 299 explicit MachPortSender(mach_port_t send_port); 300 301 kern_return_t SendMessage(MachSendMessage &message, 302 mach_msg_timeout_t timeout); 303 304 private: 305 mach_port_t send_port_; 306 kern_return_t init_result_; 307 308 DISALLOW_COPY_AND_ASSIGN(MachPortSender); 309}; 310 311} // namespace base 312 313#endif // BASE_MACH_IPC_MAC_H_ 314