| // 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__ |