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