Home | History | Annotate | Download | only in mac
      1 // Copyright (c) 2007, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 //
     30 //  MachIPC.h
     31 //
     32 //  Some helpful wrappers for using Mach IPC calls
     33 
     34 #ifndef MACH_IPC_H__
     35 #define MACH_IPC_H__
     36 
     37 #import <mach/mach.h>
     38 #import <mach/message.h>
     39 #import <servers/bootstrap.h>
     40 #import <sys/types.h>
     41 
     42 #import <CoreServices/CoreServices.h>
     43 
     44 //==============================================================================
     45 // DISCUSSION:
     46 //
     47 // The three main classes of interest are
     48 //
     49 //  MachMessage:    a wrapper for a mach message of the following form
     50 //   mach_msg_header_t
     51 //   mach_msg_body_t
     52 //   optional descriptors
     53 //   optional extra message data
     54 //
     55 //  MachReceiveMessage and MachSendMessage subclass MachMessage
     56 //    and are used instead of MachMessage which is an abstract base class
     57 //
     58 //  ReceivePort:
     59 //    Represents a mach port for which we have receive rights
     60 //
     61 //  MachPortSender:
     62 //    Represents a mach port for which we have send rights
     63 //
     64 // Here's an example to receive a message on a server port:
     65 //
     66 //        // This creates our named server port
     67 //        ReceivePort receivePort("com.Google.MyService");
     68 //
     69 //        MachReceiveMessage message;
     70 //        kern_return_t result = receivePort.WaitForMessage(&message, 0);
     71 //
     72 //        if (result == KERN_SUCCESS && message.GetMessageID() == 57) {
     73 //          mach_port_t task = message.GetTranslatedPort(0);
     74 //          mach_port_t thread = message.GetTranslatedPort(1);
     75 //
     76 //          char *messageString = message.GetData();
     77 //
     78 //          printf("message string = %s\n", messageString);
     79 //        }
     80 //
     81 // Here is an example of using these classes to send a message to this port:
     82 //
     83 //    // send to already named port
     84 //    MachPortSender sender("com.Google.MyService");
     85 //    MachSendMessage message(57);      // our message ID is 57
     86 //
     87 //    // add some ports to be translated for us
     88 //    message.AddDescriptor(mach_task_self());     // our task
     89 //    message.AddDescriptor(mach_thread_self());   // this thread
     90 //
     91 //    char messageString[] = "Hello server!\n";
     92 //    message.SetData(messageString, strlen(messageString)+1);
     93 //
     94 //    kern_return_t result = sender.SendMessage(message, 1000); // timeout 1000ms
     95 //
     96 
     97 namespace google_breakpad {
     98 #define PRINT_MACH_RESULT(result_, message_) \
     99   printf(message_" %s (%d)\n", mach_error_string(result_), result_ );
    100 
    101 //==============================================================================
    102 // A wrapper class for mach_msg_port_descriptor_t (with same memory layout)
    103 // with convenient constructors and accessors
    104 class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
    105  public:
    106   // General-purpose constructor
    107   MachMsgPortDescriptor(mach_port_t in_name,
    108                         mach_msg_type_name_t in_disposition) {
    109     name = in_name;
    110     pad1 = 0;
    111     pad2 = 0;
    112     disposition = in_disposition;
    113     type = MACH_MSG_PORT_DESCRIPTOR;
    114   }
    115 
    116   // For passing send rights to a port
    117   MachMsgPortDescriptor(mach_port_t in_name) {
    118     name = in_name;
    119     pad1 = 0;
    120     pad2 = 0;
    121     disposition = MACH_MSG_TYPE_COPY_SEND;
    122     type = MACH_MSG_PORT_DESCRIPTOR;
    123   }
    124 
    125   // Copy constructor
    126   MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) {
    127     name = desc.name;
    128     pad1 = desc.pad1;
    129     pad2 = desc.pad2;
    130     disposition = desc.disposition;
    131     type = desc.type;
    132   }
    133 
    134   mach_port_t GetMachPort() const {
    135     return name;
    136   }
    137 
    138   mach_msg_type_name_t GetDisposition() const {
    139     return disposition;
    140   }
    141 
    142   // For convenience
    143   operator mach_port_t() const {
    144     return GetMachPort();
    145   }
    146 };
    147 
    148 //==============================================================================
    149 // MachMessage: a wrapper for a mach message
    150 //  (mach_msg_header_t, mach_msg_body_t, extra data)
    151 //
    152 //  This considerably simplifies the construction of a message for sending
    153 //  and the getting at relevant data and descriptors for the receiver.
    154 //
    155 //  Currently the combined size of the descriptors plus data must be
    156 //  less than 1024.  But as a benefit no memory allocation is necessary.
    157 //
    158 // TODO: could consider adding malloc() support for very large messages
    159 //
    160 //  A MachMessage object is used by ReceivePort::WaitForMessage
    161 //  and MachPortSender::SendMessage
    162 //
    163 class MachMessage {
    164  public:
    165 
    166   // The receiver of the message can retrieve the raw data this way
    167   uint8_t *GetData() {
    168     return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
    169   }
    170 
    171   uint32_t GetDataLength() {
    172     return EndianU32_LtoN(GetDataPacket()->data_length);
    173   }
    174 
    175   // The message ID may be used as a code identifying the type of message
    176   void SetMessageID(int32_t message_id) {
    177     GetDataPacket()->id = EndianU32_NtoL(message_id);
    178   }
    179 
    180   int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
    181 
    182   // Adds a descriptor (typically a mach port) to be translated
    183   // returns true if successful, otherwise not enough space
    184   bool AddDescriptor(const MachMsgPortDescriptor &desc);
    185 
    186   int GetDescriptorCount() const { return body.msgh_descriptor_count; }
    187   MachMsgPortDescriptor *GetDescriptor(int n);
    188 
    189   // Convenience method which gets the mach port described by the descriptor
    190   mach_port_t GetTranslatedPort(int n);
    191 
    192   // A simple message is one with no descriptors
    193   bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
    194 
    195   // Sets raw data for the message (returns false if not enough space)
    196   bool SetData(void *data, int32_t data_length);
    197 
    198  protected:
    199   // Consider this an abstract base class - must create an actual instance
    200   // of MachReceiveMessage or MachSendMessage
    201 
    202   MachMessage() {
    203     memset(this, 0, sizeof(MachMessage));
    204   }
    205 
    206   friend class ReceivePort;
    207   friend class MachPortSender;
    208 
    209   // Represents raw data in our message
    210   struct MessageDataPacket {
    211     int32_t      id;          // little-endian
    212     int32_t      data_length; // little-endian
    213     uint8_t      data[1];     // actual size limited by sizeof(MachMessage)
    214   };
    215 
    216   MessageDataPacket* GetDataPacket();
    217 
    218   void SetDescriptorCount(int n);
    219   void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
    220 
    221   // Returns total message size setting msgh_size in the header to this value
    222   mach_msg_size_t CalculateSize();
    223 
    224   mach_msg_header_t  head;
    225   mach_msg_body_t    body;
    226   uint8_t            padding[1024]; // descriptors and data may be embedded here
    227 };
    228 
    229 //==============================================================================
    230 // MachReceiveMessage and MachSendMessage are useful to separate the idea
    231 // of a mach message being sent and being received, and adds increased type
    232 // safety:
    233 //  ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
    234 //  MachPortSender::SendMessage() only accepts a MachSendMessage
    235 
    236 //==============================================================================
    237 class MachReceiveMessage : public MachMessage {
    238  public:
    239   MachReceiveMessage() : MachMessage() {};
    240 };
    241 
    242 //==============================================================================
    243 class MachSendMessage : public MachMessage {
    244  public:
    245   MachSendMessage(int32_t message_id);
    246 };
    247 
    248 //==============================================================================
    249 // Represents a mach port for which we have receive rights
    250 class ReceivePort {
    251  public:
    252   // Creates a new mach port for receiving messages and registers a name for it
    253   explicit ReceivePort(const char *receive_port_name);
    254 
    255   // Given an already existing mach port, use it.  We take ownership of the
    256   // port and deallocate it in our destructor.
    257   explicit ReceivePort(mach_port_t receive_port);
    258 
    259   // Create a new mach port for receiving messages
    260   ReceivePort();
    261 
    262   ~ReceivePort();
    263 
    264   // Waits on the mach port until message received or timeout
    265   kern_return_t WaitForMessage(MachReceiveMessage *out_message,
    266                                mach_msg_timeout_t timeout);
    267 
    268   // The underlying mach port that we wrap
    269   mach_port_t  GetPort() const { return port_; }
    270 
    271  private:
    272   ReceivePort(const ReceivePort&);  // disable copy c-tor
    273 
    274   mach_port_t   port_;
    275   kern_return_t init_result_;
    276 };
    277 
    278 //==============================================================================
    279 // Represents a mach port for which we have send rights
    280 class MachPortSender {
    281  public:
    282   // get a port with send rights corresponding to a named registered service
    283   explicit MachPortSender(const char *receive_port_name);
    284 
    285 
    286   // Given an already existing mach port, use it.
    287   explicit MachPortSender(mach_port_t send_port);
    288 
    289   kern_return_t SendMessage(MachSendMessage &message,
    290                             mach_msg_timeout_t timeout);
    291 
    292  private:
    293   MachPortSender(const MachPortSender&);  // disable copy c-tor
    294 
    295   mach_port_t   send_port_;
    296   kern_return_t init_result_;
    297 };
    298 
    299 }  // namespace google_breakpad
    300 
    301 #endif // MACH_IPC_H__
    302