1// Copyright (c) 2007, Google Inc. 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are 6// met: 7// 8// * Redistributions of source code must retain the above copyright 9// notice, this list of conditions and the following disclaimer. 10// * Redistributions in binary form must reproduce the above 11// copyright notice, this list of conditions and the following disclaimer 12// in the documentation and/or other materials provided with the 13// distribution. 14// * Neither the name of Google Inc. nor the names of its 15// contributors may be used to endorse or promote products derived from 16// this software without specific prior written permission. 17// 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29// 30// MachIPC.h 31// 32// Some helpful wrappers for using Mach IPC calls 33 34#ifndef MACH_IPC_H__ 35#define MACH_IPC_H__ 36 37#import <mach/mach.h> 38#import <mach/message.h> 39#import <servers/bootstrap.h> 40#import <sys/types.h> 41 42#import <CoreServices/CoreServices.h> 43 44//============================================================================== 45// DISCUSSION: 46// 47// The three main classes of interest are 48// 49// MachMessage: a wrapper for a mach message of the following form 50// mach_msg_header_t 51// mach_msg_body_t 52// optional descriptors 53// optional extra message data 54// 55// MachReceiveMessage and MachSendMessage subclass MachMessage 56// and are used instead of MachMessage which is an abstract base class 57// 58// ReceivePort: 59// Represents a mach port for which we have receive rights 60// 61// MachPortSender: 62// Represents a mach port for which we have send rights 63// 64// Here's an example to receive a message on a server port: 65// 66// // This creates our named server port 67// ReceivePort receivePort("com.Google.MyService"); 68// 69// MachReceiveMessage message; 70// kern_return_t result = receivePort.WaitForMessage(&message, 0); 71// 72// if (result == KERN_SUCCESS && message.GetMessageID() == 57) { 73// mach_port_t task = message.GetTranslatedPort(0); 74// mach_port_t thread = message.GetTranslatedPort(1); 75// 76// char *messageString = message.GetData(); 77// 78// printf("message string = %s\n", messageString); 79// } 80// 81// Here is an example of using these classes to send a message to this port: 82// 83// // send to already named port 84// MachPortSender sender("com.Google.MyService"); 85// MachSendMessage message(57); // our message ID is 57 86// 87// // add some ports to be translated for us 88// message.AddDescriptor(mach_task_self()); // our task 89// message.AddDescriptor(mach_thread_self()); // this thread 90// 91// char messageString[] = "Hello server!\n"; 92// message.SetData(messageString, strlen(messageString)+1); 93// 94// kern_return_t result = sender.SendMessage(message, 1000); // timeout 1000ms 95// 96 97namespace google_breakpad { 98#define PRINT_MACH_RESULT(result_, message_) \ 99 printf(message_" %s (%d)\n", mach_error_string(result_), result_ ); 100 101//============================================================================== 102// A wrapper class for mach_msg_port_descriptor_t (with same memory layout) 103// with convenient constructors and accessors 104class MachMsgPortDescriptor : public mach_msg_port_descriptor_t { 105 public: 106 // General-purpose constructor 107 MachMsgPortDescriptor(mach_port_t in_name, 108 mach_msg_type_name_t in_disposition) { 109 name = in_name; 110 pad1 = 0; 111 pad2 = 0; 112 disposition = in_disposition; 113 type = MACH_MSG_PORT_DESCRIPTOR; 114 } 115 116 // For passing send rights to a port 117 MachMsgPortDescriptor(mach_port_t in_name) { 118 name = in_name; 119 pad1 = 0; 120 pad2 = 0; 121 disposition = MACH_MSG_TYPE_COPY_SEND; 122 type = MACH_MSG_PORT_DESCRIPTOR; 123 } 124 125 // Copy constructor 126 MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) { 127 name = desc.name; 128 pad1 = desc.pad1; 129 pad2 = desc.pad2; 130 disposition = desc.disposition; 131 type = desc.type; 132 } 133 134 mach_port_t GetMachPort() const { 135 return name; 136 } 137 138 mach_msg_type_name_t GetDisposition() const { 139 return disposition; 140 } 141 142 // For convenience 143 operator mach_port_t() const { 144 return GetMachPort(); 145 } 146}; 147 148//============================================================================== 149// MachMessage: a wrapper for a mach message 150// (mach_msg_header_t, mach_msg_body_t, extra data) 151// 152// This considerably simplifies the construction of a message for sending 153// and the getting at relevant data and descriptors for the receiver. 154// 155// Currently the combined size of the descriptors plus data must be 156// less than 1024. But as a benefit no memory allocation is necessary. 157// 158// TODO: could consider adding malloc() support for very large messages 159// 160// A MachMessage object is used by ReceivePort::WaitForMessage 161// and MachPortSender::SendMessage 162// 163class MachMessage { 164 public: 165 166 // The receiver of the message can retrieve the raw data this way 167 uint8_t *GetData() { 168 return GetDataLength() > 0 ? GetDataPacket()->data : NULL; 169 } 170 171 uint32_t GetDataLength() { 172 return EndianU32_LtoN(GetDataPacket()->data_length); 173 } 174 175 // The message ID may be used as a code identifying the type of message 176 void SetMessageID(int32_t message_id) { 177 GetDataPacket()->id = EndianU32_NtoL(message_id); 178 } 179 180 int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); } 181 182 // Adds a descriptor (typically a mach port) to be translated 183 // returns true if successful, otherwise not enough space 184 bool AddDescriptor(const MachMsgPortDescriptor &desc); 185 186 int GetDescriptorCount() const { return body.msgh_descriptor_count; } 187 MachMsgPortDescriptor *GetDescriptor(int n); 188 189 // Convenience method which gets the mach port described by the descriptor 190 mach_port_t GetTranslatedPort(int n); 191 192 // A simple message is one with no descriptors 193 bool IsSimpleMessage() const { return GetDescriptorCount() == 0; } 194 195 // Sets raw data for the message (returns false if not enough space) 196 bool SetData(void *data, int32_t data_length); 197 198 protected: 199 // Consider this an abstract base class - must create an actual instance 200 // of MachReceiveMessage or MachSendMessage 201 202 MachMessage() { 203 memset(this, 0, sizeof(MachMessage)); 204 } 205 206 friend class ReceivePort; 207 friend class MachPortSender; 208 209 // Represents raw data in our message 210 struct MessageDataPacket { 211 int32_t id; // little-endian 212 int32_t data_length; // little-endian 213 uint8_t data[1]; // actual size limited by sizeof(MachMessage) 214 }; 215 216 MessageDataPacket* GetDataPacket(); 217 218 void SetDescriptorCount(int n); 219 void SetDescriptor(int n, const MachMsgPortDescriptor &desc); 220 221 // Returns total message size setting msgh_size in the header to this value 222 mach_msg_size_t CalculateSize(); 223 224 mach_msg_header_t head; 225 mach_msg_body_t body; 226 uint8_t padding[1024]; // descriptors and data may be embedded here 227}; 228 229//============================================================================== 230// MachReceiveMessage and MachSendMessage are useful to separate the idea 231// of a mach message being sent and being received, and adds increased type 232// safety: 233// ReceivePort::WaitForMessage() only accepts a MachReceiveMessage 234// MachPortSender::SendMessage() only accepts a MachSendMessage 235 236//============================================================================== 237class MachReceiveMessage : public MachMessage { 238 public: 239 MachReceiveMessage() : MachMessage() {}; 240}; 241 242//============================================================================== 243class MachSendMessage : public MachMessage { 244 public: 245 MachSendMessage(int32_t message_id); 246}; 247 248//============================================================================== 249// Represents a mach port for which we have receive rights 250class ReceivePort { 251 public: 252 // Creates a new mach port for receiving messages and registers a name for it 253 explicit ReceivePort(const char *receive_port_name); 254 255 // Given an already existing mach port, use it. We take ownership of the 256 // port and deallocate it in our destructor. 257 explicit ReceivePort(mach_port_t receive_port); 258 259 // Create a new mach port for receiving messages 260 ReceivePort(); 261 262 ~ReceivePort(); 263 264 // Waits on the mach port until message received or timeout 265 kern_return_t WaitForMessage(MachReceiveMessage *out_message, 266 mach_msg_timeout_t timeout); 267 268 // The underlying mach port that we wrap 269 mach_port_t GetPort() const { return port_; } 270 271 private: 272 ReceivePort(const ReceivePort&); // disable copy c-tor 273 274 mach_port_t port_; 275 kern_return_t init_result_; 276}; 277 278//============================================================================== 279// Represents a mach port for which we have send rights 280class MachPortSender { 281 public: 282 // get a port with send rights corresponding to a named registered service 283 explicit MachPortSender(const char *receive_port_name); 284 285 286 // Given an already existing mach port, use it. 287 explicit MachPortSender(mach_port_t send_port); 288 289 kern_return_t SendMessage(MachSendMessage &message, 290 mach_msg_timeout_t timeout); 291 292 private: 293 MachPortSender(const MachPortSender&); // disable copy c-tor 294 295 mach_port_t send_port_; 296 kern_return_t init_result_; 297}; 298 299} // namespace google_breakpad 300 301#endif // MACH_IPC_H__ 302