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 97 namespace 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 104 class MachMsgPortDescriptor : public mach_msg_port_descriptor_t { 105 public: 106 // General-purpose constructor MachMsgPortDescriptor(mach_port_t in_name,mach_msg_type_name_t in_disposition)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 MachMsgPortDescriptor(mach_port_t in_name)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 MachMsgPortDescriptor(const MachMsgPortDescriptor & desc)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 GetMachPort()134 mach_port_t GetMachPort() const { 135 return name; 136 } 137 GetDisposition()138 mach_msg_type_name_t GetDisposition() const { 139 return disposition; 140 } 141 142 // For convenience mach_port_t()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 // 163 class MachMessage { 164 public: 165 166 // The receiver of the message can retrieve the raw data this way GetData()167 uint8_t *GetData() { 168 return GetDataLength() > 0 ? GetDataPacket()->data : NULL; 169 } 170 GetDataLength()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 SetMessageID(int32_t message_id)176 void SetMessageID(int32_t message_id) { 177 GetDataPacket()->id = EndianU32_NtoL(message_id); 178 } 179 GetMessageID()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 GetDescriptorCount()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 IsSimpleMessage()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 MachMessage()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 //============================================================================== 237 class MachReceiveMessage : public MachMessage { 238 public: MachReceiveMessage()239 MachReceiveMessage() : MachMessage() {} 240 }; 241 242 //============================================================================== 243 class 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 250 class 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 GetPort()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 280 class 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