| // Copyright (c) 2007, Google Inc. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| // |
| // MachIPC.h |
| // |
| // Some helpful wrappers for using Mach IPC calls |
| |
| #ifndef MACH_IPC_H__ |
| #define MACH_IPC_H__ |
| |
| #import <mach/mach.h> |
| #import <mach/message.h> |
| #import <servers/bootstrap.h> |
| #import <sys/types.h> |
| |
| #import <CoreServices/CoreServices.h> |
| |
| //============================================================================== |
| // DISCUSSION: |
| // |
| // The three main classes of interest are |
| // |
| // MachMessage: a wrapper for a mach message of the following form |
| // mach_msg_header_t |
| // mach_msg_body_t |
| // optional descriptors |
| // optional extra message data |
| // |
| // MachReceiveMessage and MachSendMessage subclass MachMessage |
| // and are used instead of MachMessage which is an abstract base class |
| // |
| // ReceivePort: |
| // Represents a mach port for which we have receive rights |
| // |
| // MachPortSender: |
| // Represents a mach port for which we have send rights |
| // |
| // Here's an example to receive a message on a server port: |
| // |
| // // This creates our named server port |
| // ReceivePort receivePort("com.Google.MyService"); |
| // |
| // MachReceiveMessage message; |
| // kern_return_t result = receivePort.WaitForMessage(&message, 0); |
| // |
| // if (result == KERN_SUCCESS && message.GetMessageID() == 57) { |
| // mach_port_t task = message.GetTranslatedPort(0); |
| // mach_port_t thread = message.GetTranslatedPort(1); |
| // |
| // char *messageString = message.GetData(); |
| // |
| // printf("message string = %s\n", messageString); |
| // } |
| // |
| // Here is an example of using these classes to send a message to this port: |
| // |
| // // send to already named port |
| // MachPortSender sender("com.Google.MyService"); |
| // MachSendMessage message(57); // our message ID is 57 |
| // |
| // // add some ports to be translated for us |
| // message.AddDescriptor(mach_task_self()); // our task |
| // message.AddDescriptor(mach_thread_self()); // this thread |
| // |
| // char messageString[] = "Hello server!\n"; |
| // message.SetData(messageString, strlen(messageString)+1); |
| // |
| // kern_return_t result = sender.SendMessage(message, 1000); // timeout 1000ms |
| // |
| |
| namespace google_breakpad { |
| #define PRINT_MACH_RESULT(result_, message_) \ |
| printf(message_" %s (%d)\n", mach_error_string(result_), result_ ); |
| |
| //============================================================================== |
| // A wrapper class for mach_msg_port_descriptor_t (with same memory layout) |
| // with convenient constructors and accessors |
| class MachMsgPortDescriptor : public mach_msg_port_descriptor_t { |
| public: |
| // General-purpose constructor |
| MachMsgPortDescriptor(mach_port_t in_name, |
| mach_msg_type_name_t in_disposition) { |
| name = in_name; |
| pad1 = 0; |
| pad2 = 0; |
| disposition = in_disposition; |
| type = MACH_MSG_PORT_DESCRIPTOR; |
| } |
| |
| // For passing send rights to a port |
| MachMsgPortDescriptor(mach_port_t in_name) { |
| name = in_name; |
| pad1 = 0; |
| pad2 = 0; |
| disposition = MACH_MSG_TYPE_COPY_SEND; |
| type = MACH_MSG_PORT_DESCRIPTOR; |
| } |
| |
| // Copy constructor |
| MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) { |
| name = desc.name; |
| pad1 = desc.pad1; |
| pad2 = desc.pad2; |
| disposition = desc.disposition; |
| type = desc.type; |
| } |
| |
| mach_port_t GetMachPort() const { |
| return name; |
| } |
| |
| mach_msg_type_name_t GetDisposition() const { |
| return disposition; |
| } |
| |
| // For convenience |
| operator mach_port_t() const { |
| return GetMachPort(); |
| } |
| }; |
| |
| //============================================================================== |
| // MachMessage: a wrapper for a mach message |
| // (mach_msg_header_t, mach_msg_body_t, extra data) |
| // |
| // This considerably simplifies the construction of a message for sending |
| // and the getting at relevant data and descriptors for the receiver. |
| // |
| // Currently the combined size of the descriptors plus data must be |
| // less than 1024. But as a benefit no memory allocation is necessary. |
| // |
| // TODO: could consider adding malloc() support for very large messages |
| // |
| // A MachMessage object is used by ReceivePort::WaitForMessage |
| // and MachPortSender::SendMessage |
| // |
| class MachMessage { |
| public: |
| |
| // The receiver of the message can retrieve the raw data this way |
| uint8_t *GetData() { |
| return GetDataLength() > 0 ? GetDataPacket()->data : NULL; |
| } |
| |
| uint32_t GetDataLength() { |
| return EndianU32_LtoN(GetDataPacket()->data_length); |
| } |
| |
| // The message ID may be used as a code identifying the type of message |
| void SetMessageID(int32_t message_id) { |
| GetDataPacket()->id = EndianU32_NtoL(message_id); |
| } |
| |
| int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); } |
| |
| // Adds a descriptor (typically a mach port) to be translated |
| // returns true if successful, otherwise not enough space |
| bool AddDescriptor(const MachMsgPortDescriptor &desc); |
| |
| int GetDescriptorCount() const { return body.msgh_descriptor_count; } |
| MachMsgPortDescriptor *GetDescriptor(int n); |
| |
| // Convenience method which gets the mach port described by the descriptor |
| mach_port_t GetTranslatedPort(int n); |
| |
| // A simple message is one with no descriptors |
| bool IsSimpleMessage() const { return GetDescriptorCount() == 0; } |
| |
| // Sets raw data for the message (returns false if not enough space) |
| bool SetData(void *data, int32_t data_length); |
| |
| protected: |
| // Consider this an abstract base class - must create an actual instance |
| // of MachReceiveMessage or MachSendMessage |
| |
| MachMessage() { |
| memset(this, 0, sizeof(MachMessage)); |
| } |
| |
| friend class ReceivePort; |
| friend class MachPortSender; |
| |
| // Represents raw data in our message |
| struct MessageDataPacket { |
| int32_t id; // little-endian |
| int32_t data_length; // little-endian |
| uint8_t data[1]; // actual size limited by sizeof(MachMessage) |
| }; |
| |
| MessageDataPacket* GetDataPacket(); |
| |
| void SetDescriptorCount(int n); |
| void SetDescriptor(int n, const MachMsgPortDescriptor &desc); |
| |
| // Returns total message size setting msgh_size in the header to this value |
| mach_msg_size_t CalculateSize(); |
| |
| mach_msg_header_t head; |
| mach_msg_body_t body; |
| uint8_t padding[1024]; // descriptors and data may be embedded here |
| }; |
| |
| //============================================================================== |
| // MachReceiveMessage and MachSendMessage are useful to separate the idea |
| // of a mach message being sent and being received, and adds increased type |
| // safety: |
| // ReceivePort::WaitForMessage() only accepts a MachReceiveMessage |
| // MachPortSender::SendMessage() only accepts a MachSendMessage |
| |
| //============================================================================== |
| class MachReceiveMessage : public MachMessage { |
| public: |
| MachReceiveMessage() : MachMessage() {} |
| }; |
| |
| //============================================================================== |
| class MachSendMessage : public MachMessage { |
| public: |
| MachSendMessage(int32_t message_id); |
| }; |
| |
| //============================================================================== |
| // Represents a mach port for which we have receive rights |
| class ReceivePort { |
| public: |
| // Creates a new mach port for receiving messages and registers a name for it |
| explicit ReceivePort(const char *receive_port_name); |
| |
| // Given an already existing mach port, use it. We take ownership of the |
| // port and deallocate it in our destructor. |
| explicit ReceivePort(mach_port_t receive_port); |
| |
| // Create a new mach port for receiving messages |
| ReceivePort(); |
| |
| ~ReceivePort(); |
| |
| // Waits on the mach port until message received or timeout |
| kern_return_t WaitForMessage(MachReceiveMessage *out_message, |
| mach_msg_timeout_t timeout); |
| |
| // The underlying mach port that we wrap |
| mach_port_t GetPort() const { return port_; } |
| |
| private: |
| ReceivePort(const ReceivePort&); // disable copy c-tor |
| |
| mach_port_t port_; |
| kern_return_t init_result_; |
| }; |
| |
| //============================================================================== |
| // Represents a mach port for which we have send rights |
| class MachPortSender { |
| public: |
| // get a port with send rights corresponding to a named registered service |
| explicit MachPortSender(const char *receive_port_name); |
| |
| |
| // Given an already existing mach port, use it. |
| explicit MachPortSender(mach_port_t send_port); |
| |
| kern_return_t SendMessage(MachSendMessage &message, |
| mach_msg_timeout_t timeout); |
| |
| private: |
| MachPortSender(const MachPortSender&); // disable copy c-tor |
| |
| mach_port_t send_port_; |
| kern_return_t init_result_; |
| }; |
| |
| } // namespace google_breakpad |
| |
| #endif // MACH_IPC_H__ |