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