Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_MACH_IPC_MAC_H_
      6 #define BASE_MACH_IPC_MAC_H_
      7 #pragma once
      8 
      9 #include <mach/mach.h>
     10 #include <mach/message.h>
     11 #include <servers/bootstrap.h>
     12 #include <sys/types.h>
     13 
     14 #include <CoreServices/CoreServices.h>
     15 
     16 #include "base/basictypes.h"
     17 
     18 //==============================================================================
     19 // DISCUSSION:
     20 //
     21 // The three main classes of interest are
     22 //
     23 //  MachMessage:    a wrapper for a Mach message of the following form
     24 //   mach_msg_header_t
     25 //   mach_msg_body_t
     26 //   optional descriptors
     27 //   optional extra message data
     28 //
     29 //  MachReceiveMessage and MachSendMessage subclass MachMessage
     30 //    and are used instead of MachMessage which is an abstract base class
     31 //
     32 //  ReceivePort:
     33 //    Represents a Mach port for which we have receive rights
     34 //
     35 //  MachPortSender:
     36 //    Represents a Mach port for which we have send rights
     37 //
     38 // Here's an example to receive a message on a server port:
     39 //
     40 //        // This creates our named server port
     41 //        ReceivePort receivePort("com.Google.MyService");
     42 //
     43 //        MachReceiveMessage message;
     44 //        kern_return_t result = receivePort.WaitForMessage(&message, 0);
     45 //
     46 //        if (result == KERN_SUCCESS && message.GetMessageID() == 57) {
     47 //          mach_port_t task = message.GetTranslatedPort(0);
     48 //          mach_port_t thread = message.GetTranslatedPort(1);
     49 //
     50 //          char *messageString = message.GetData();
     51 //
     52 //          printf("message string = %s\n", messageString);
     53 //        }
     54 //
     55 // Here is an example of using these classes to send a message to this port:
     56 //
     57 //    // send to already named port
     58 //    MachPortSender sender("com.Google.MyService");
     59 //    MachSendMessage message(57);      // our message ID is 57
     60 //
     61 //    // add some ports to be translated for us
     62 //    message.AddDescriptor(mach_task_self());     // our task
     63 //    message.AddDescriptor(mach_thread_self());   // this thread
     64 //
     65 //    char messageString[] = "Hello server!\n";
     66 //    message.SetData(messageString, strlen(messageString)+1);
     67 //    // timeout 1000ms
     68 //    kern_return_t result = sender.SendMessage(message, 1000);
     69 //
     70 
     71 #define PRINT_MACH_RESULT(result_, message_) \
     72   printf(message_" %s (%d)\n", mach_error_string(result_), result_ );
     73 
     74 namespace base {
     75 
     76 //==============================================================================
     77 // A wrapper class for mach_msg_port_descriptor_t (with same memory layout)
     78 // with convenient constructors and accessors
     79 class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
     80  public:
     81   // General-purpose constructor
     82   MachMsgPortDescriptor(mach_port_t in_name,
     83                         mach_msg_type_name_t in_disposition) {
     84     name = in_name;
     85     pad1 = 0;
     86     pad2 = 0;
     87     disposition = in_disposition;
     88     type = MACH_MSG_PORT_DESCRIPTOR;
     89   }
     90 
     91   // For passing send rights to a port
     92   MachMsgPortDescriptor(mach_port_t in_name) {
     93     name = in_name;
     94     pad1 = 0;
     95     pad2 = 0;
     96     disposition = MACH_MSG_TYPE_PORT_SEND;
     97     type = MACH_MSG_PORT_DESCRIPTOR;
     98   }
     99 
    100   // Copy constructor
    101   MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) {
    102     name = desc.name;
    103     pad1 = desc.pad1;
    104     pad2 = desc.pad2;
    105     disposition = desc.disposition;
    106     type = desc.type;
    107   }
    108 
    109   mach_port_t GetMachPort() const {
    110     return name;
    111   }
    112 
    113   mach_msg_type_name_t GetDisposition() const {
    114     return disposition;
    115   }
    116 
    117   // For convenience
    118   operator mach_port_t() const {
    119     return GetMachPort();
    120   }
    121 };
    122 
    123 //==============================================================================
    124 // MachMessage: a wrapper for a Mach message
    125 //  (mach_msg_header_t, mach_msg_body_t, extra data)
    126 //
    127 //  This considerably simplifies the construction of a message for sending
    128 //  and the getting at relevant data and descriptors for the receiver.
    129 //
    130 //  This class can be initialized using external storage of an arbitrary size
    131 //  or it can manage storage internally.
    132 //  1. If storage is allocated internally, the combined size of the descriptors
    133 //  plus data must be less than 1024.  But as a benefit no memory allocation is
    134 //  necessary.
    135 //  2. For external storage, a buffer of at least EmptyMessageSize() must be
    136 //  provided.
    137 //
    138 //  A MachMessage object is used by ReceivePort::WaitForMessage
    139 //  and MachPortSender::SendMessage
    140 //
    141 class MachMessage {
    142  public:
    143   static const size_t kEmptyMessageSize;
    144 
    145   virtual ~MachMessage();
    146 
    147   // The receiver of the message can retrieve the raw data this way
    148   u_int8_t *GetData() {
    149     return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
    150   }
    151 
    152   u_int32_t GetDataLength() {
    153     return EndianU32_LtoN(GetDataPacket()->data_length);
    154   }
    155 
    156   // The message ID may be used as a code identifying the type of message
    157   void SetMessageID(int32_t message_id) {
    158     GetDataPacket()->id = EndianU32_NtoL(message_id);
    159   }
    160 
    161   int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
    162 
    163   // Adds a descriptor (typically a Mach port) to be translated
    164   // returns true if successful, otherwise not enough space
    165   bool AddDescriptor(const MachMsgPortDescriptor &desc);
    166 
    167   int GetDescriptorCount() const {
    168     return storage_->body.msgh_descriptor_count;
    169   }
    170 
    171   MachMsgPortDescriptor *GetDescriptor(int n);
    172 
    173   // Convenience method which gets the Mach port described by the descriptor
    174   mach_port_t GetTranslatedPort(int n);
    175 
    176   // A simple message is one with no descriptors
    177   bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
    178 
    179   // Sets raw data for the message (returns false if not enough space)
    180   bool SetData(const void* data, int32_t data_length);
    181 
    182  protected:
    183   // Consider this an abstract base class - must create an actual instance
    184   // of MachReceiveMessage or MachSendMessage
    185   MachMessage();
    186 
    187   // Constructor for use with preallocate storage.
    188   // storage_length must be >= EmptyMessageSize()
    189   MachMessage(void *storage, size_t storage_length);
    190 
    191   friend class ReceivePort;
    192   friend class MachPortSender;
    193 
    194   // Represents raw data in our message
    195   struct MessageDataPacket {
    196     int32_t  id;          // little-endian
    197     int32_t  data_length; // little-endian
    198     u_int8_t data[1];     // actual size limited by storage_length_bytes_
    199   };
    200 
    201   MessageDataPacket* GetDataPacket();
    202 
    203   void SetDescriptorCount(int n);
    204   void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
    205 
    206   // Returns total message size setting msgh_size in the header to this value
    207   int CalculateSize();
    208 
    209   // Returns total storage size that this object can grow to, this is inclusive
    210   // of the Mach header.
    211   size_t MaxSize() const { return storage_length_bytes_; }
    212 
    213   mach_msg_header_t *Head() { return &(storage_->head); }
    214 
    215  private:
    216   struct MachMessageData {
    217     mach_msg_header_t  head;
    218     mach_msg_body_t    body;
    219     // descriptors and data may be embedded here.
    220     u_int8_t           padding[1024];
    221   };
    222 
    223   MachMessageData *storage_;
    224   size_t storage_length_bytes_;
    225   bool own_storage_;  // Is storage owned by this object?
    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:
    238   MachReceiveMessage() : MachMessage() {}
    239   MachReceiveMessage(void *storage, size_t storage_length)
    240       : MachMessage(storage, storage_length) {}
    241 
    242  private:
    243     DISALLOW_COPY_AND_ASSIGN(MachReceiveMessage);
    244 };
    245 
    246 //==============================================================================
    247 class MachSendMessage : public MachMessage {
    248  public:
    249   explicit MachSendMessage(int32_t message_id);
    250   MachSendMessage(void *storage, size_t storage_length, int32_t message_id);
    251 
    252  private:
    253   void Initialize(int32_t message_id);
    254 
    255   DISALLOW_COPY_AND_ASSIGN(MachSendMessage);
    256 };
    257 
    258 //==============================================================================
    259 // Represents a Mach port for which we have receive rights
    260 class ReceivePort {
    261  public:
    262   // Creates a new Mach port for receiving messages and registers a name for it
    263   explicit ReceivePort(const char *receive_port_name);
    264 
    265   // Given an already existing Mach port, use it.  We take ownership of the
    266   // port and deallocate it in our destructor.
    267   explicit ReceivePort(mach_port_t receive_port);
    268 
    269   // Create a new Mach port for receiving messages
    270   ReceivePort();
    271 
    272   ~ReceivePort();
    273 
    274   // Waits on the Mach port until message received or timeout.  If |timeout| is
    275   // MACH_MSG_TIMEOUT_NONE, this method waits forever.
    276   kern_return_t WaitForMessage(MachReceiveMessage *out_message,
    277                                mach_msg_timeout_t timeout);
    278 
    279   // The underlying Mach port that we wrap
    280   mach_port_t  GetPort() const { return port_; }
    281 
    282  private:
    283   mach_port_t   port_;
    284   kern_return_t init_result_;
    285 
    286   DISALLOW_COPY_AND_ASSIGN(ReceivePort);
    287 };
    288 
    289 //==============================================================================
    290 // Represents a Mach port for which we have send rights
    291 class MachPortSender {
    292  public:
    293   // get a port with send rights corresponding to a named registered service
    294   explicit MachPortSender(const char *receive_port_name);
    295 
    296 
    297   // Given an already existing Mach port, use it. Does not take ownership of
    298   // |send_port|.
    299   explicit MachPortSender(mach_port_t send_port);
    300 
    301   kern_return_t SendMessage(MachSendMessage &message,
    302                             mach_msg_timeout_t timeout);
    303 
    304  private:
    305   mach_port_t   send_port_;
    306   kern_return_t init_result_;
    307 
    308   DISALLOW_COPY_AND_ASSIGN(MachPortSender);
    309 };
    310 
    311 }  // namespace base
    312 
    313 #endif // BASE_MACH_IPC_MAC_H_
    314