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 74 namespace base { 75 76 //============================================================================== 77 // A wrapper class for mach_msg_port_descriptor_t (with same memory layout) 78 // with convenient constructors and accessors 79 class MachMsgPortDescriptor : public mach_msg_port_descriptor_t { 80 public: 81 // General-purpose constructor MachMsgPortDescriptor(mach_port_t in_name,mach_msg_type_name_t in_disposition)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 MachMsgPortDescriptor(mach_port_t in_name)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 MachMsgPortDescriptor(const MachMsgPortDescriptor & desc)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 GetMachPort()109 mach_port_t GetMachPort() const { 110 return name; 111 } 112 GetDisposition()113 mach_msg_type_name_t GetDisposition() const { 114 return disposition; 115 } 116 117 // For convenience mach_port_t()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 // 141 class 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 GetData()148 u_int8_t *GetData() { 149 return GetDataLength() > 0 ? GetDataPacket()->data : NULL; 150 } 151 GetDataLength()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 SetMessageID(int32_t message_id)157 void SetMessageID(int32_t message_id) { 158 GetDataPacket()->id = EndianU32_NtoL(message_id); 159 } 160 GetMessageID()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 GetDescriptorCount()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 IsSimpleMessage()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. MaxSize()211 size_t MaxSize() const { return storage_length_bytes_; } 212 Head()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 //============================================================================== 236 class MachReceiveMessage : public MachMessage { 237 public: MachReceiveMessage()238 MachReceiveMessage() : MachMessage() {} MachReceiveMessage(void * storage,size_t storage_length)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 //============================================================================== 247 class 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 260 class 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 GetPort()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 291 class 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