|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef BASE_MACH_IPC_MAC_H_ | 
|  | #define BASE_MACH_IPC_MAC_H_ | 
|  |  | 
|  | #include <mach/mach.h> | 
|  | #include <mach/message.h> | 
|  | #include <servers/bootstrap.h> | 
|  | #include <sys/types.h> | 
|  |  | 
|  | #include <CoreServices/CoreServices.h> | 
|  |  | 
|  | #include "base/base_export.h" | 
|  | #include "base/basictypes.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); | 
|  | //    // timeout 1000ms | 
|  | //    kern_return_t result = sender.SendMessage(message, 1000); | 
|  | // | 
|  |  | 
|  | #define PRINT_MACH_RESULT(result_, message_) \ | 
|  | printf(message_" %s (%d)\n", mach_error_string(result_), result_ ); | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | //============================================================================== | 
|  | // 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_PORT_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. | 
|  | // | 
|  | //  This class can be initialized using external storage of an arbitrary size | 
|  | //  or it can manage storage internally. | 
|  | //  1. If storage is allocated internally, the combined size of the descriptors | 
|  | //  plus data must be less than 1024.  But as a benefit no memory allocation is | 
|  | //  necessary. | 
|  | //  2. For external storage, a buffer of at least EmptyMessageSize() must be | 
|  | //  provided. | 
|  | // | 
|  | //  A MachMessage object is used by ReceivePort::WaitForMessage | 
|  | //  and MachPortSender::SendMessage | 
|  | // | 
|  | class BASE_EXPORT MachMessage { | 
|  | public: | 
|  | static const size_t kEmptyMessageSize; | 
|  |  | 
|  | virtual ~MachMessage(); | 
|  |  | 
|  | // The receiver of the message can retrieve the raw data this way | 
|  | u_int8_t *GetData() { | 
|  | return GetDataLength() > 0 ? GetDataPacket()->data : NULL; | 
|  | } | 
|  |  | 
|  | u_int32_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 storage_->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(const void* data, int32_t data_length); | 
|  |  | 
|  | protected: | 
|  | // Consider this an abstract base class - must create an actual instance | 
|  | // of MachReceiveMessage or MachSendMessage | 
|  | MachMessage(); | 
|  |  | 
|  | // Constructor for use with preallocate storage. | 
|  | // storage_length must be >= EmptyMessageSize() | 
|  | MachMessage(void *storage, size_t storage_length); | 
|  |  | 
|  | 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 | 
|  | u_int8_t data[1];     // actual size limited by storage_length_bytes_ | 
|  | }; | 
|  |  | 
|  | 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 | 
|  | int CalculateSize(); | 
|  |  | 
|  | // Returns total storage size that this object can grow to, this is inclusive | 
|  | // of the Mach header. | 
|  | size_t MaxSize() const { return storage_length_bytes_; } | 
|  |  | 
|  | mach_msg_header_t *Head() { return &(storage_->head); } | 
|  |  | 
|  | private: | 
|  | struct MachMessageData { | 
|  | mach_msg_header_t  head; | 
|  | mach_msg_body_t    body; | 
|  | // descriptors and data may be embedded here. | 
|  | u_int8_t           padding[1024]; | 
|  | }; | 
|  |  | 
|  | MachMessageData *storage_; | 
|  | size_t storage_length_bytes_; | 
|  | bool own_storage_;  // Is storage owned by this object? | 
|  | }; | 
|  |  | 
|  | //============================================================================== | 
|  | // 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() {} | 
|  | MachReceiveMessage(void *storage, size_t storage_length) | 
|  | : MachMessage(storage, storage_length) {} | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(MachReceiveMessage); | 
|  | }; | 
|  |  | 
|  | //============================================================================== | 
|  | class BASE_EXPORT MachSendMessage : public MachMessage { | 
|  | public: | 
|  | explicit MachSendMessage(int32_t message_id); | 
|  | MachSendMessage(void *storage, size_t storage_length, int32_t message_id); | 
|  |  | 
|  | private: | 
|  | void Initialize(int32_t message_id); | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(MachSendMessage); | 
|  | }; | 
|  |  | 
|  | //============================================================================== | 
|  | // Represents a Mach port for which we have receive rights | 
|  | class BASE_EXPORT 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.  If |timeout| is | 
|  | // MACH_MSG_TIMEOUT_NONE, this method waits forever. | 
|  | 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: | 
|  | mach_port_t   port_; | 
|  | kern_return_t init_result_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(ReceivePort); | 
|  | }; | 
|  |  | 
|  | //============================================================================== | 
|  | // Represents a Mach port for which we have send rights | 
|  | class BASE_EXPORT 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. Does not take ownership of | 
|  | // |send_port|. | 
|  | explicit MachPortSender(mach_port_t send_port); | 
|  |  | 
|  | kern_return_t SendMessage(MachSendMessage &message, | 
|  | mach_msg_timeout_t timeout); | 
|  |  | 
|  | private: | 
|  | mach_port_t   send_port_; | 
|  | kern_return_t init_result_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(MachPortSender); | 
|  | }; | 
|  |  | 
|  | //============================================================================== | 
|  | // Static utility functions. | 
|  |  | 
|  | namespace mac { | 
|  |  | 
|  | // Returns the number of Mach ports to which the given task has a right. | 
|  | // Note that unless the calling task has send rights to the passed task port, | 
|  | // this will fail unless the calling task is running as root. | 
|  | kern_return_t BASE_EXPORT GetNumberOfMachPorts(mach_port_t task_port, | 
|  | int* port_count); | 
|  |  | 
|  | }  // namespace mac | 
|  |  | 
|  | }  // namespace base | 
|  |  | 
|  | #endif // BASE_MACH_IPC_MAC_H_ |