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