Planeshift

MachIPC.h

Go to the documentation of this file.
00001 // Copyright (c) 2007, Google Inc.
00002 // All rights reserved.
00003 //
00004 // Redistribution and use in source and binary forms, with or without
00005 // modification, are permitted provided that the following conditions are
00006 // met:
00007 //
00008 //     * Redistributions of source code must retain the above copyright
00009 // notice, this list of conditions and the following disclaimer.
00010 //     * Redistributions in binary form must reproduce the above
00011 // copyright notice, this list of conditions and the following disclaimer
00012 // in the documentation and/or other materials provided with the
00013 // distribution.
00014 //     * Neither the name of Google Inc. nor the names of its
00015 // contributors may be used to endorse or promote products derived from
00016 // this software without specific prior written permission.
00017 //
00018 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00019 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00021 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00022 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00023 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00024 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00025 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00026 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00028 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 //
00030 //  MachIPC.h
00031 //
00032 //  Some helpful wrappers for using Mach IPC calls
00033 
00034 #ifndef MACH_IPC_H__
00035 #define MACH_IPC_H__
00036 
00037 #import <mach/mach.h>
00038 #import <mach/message.h>
00039 #import <servers/bootstrap.h>
00040 #import <sys/types.h>
00041 
00042 #import <CoreServices/CoreServices.h>
00043 
00044 //==============================================================================
00045 // DISCUSSION:
00046 //
00047 // The three main classes of interest are
00048 //
00049 //  MachMessage:    a wrapper for a mach message of the following form
00050 //   mach_msg_header_t
00051 //   mach_msg_body_t
00052 //   optional descriptors
00053 //   optional extra message data
00054 //
00055 //  MachReceiveMessage and MachSendMessage subclass MachMessage
00056 //    and are used instead of MachMessage which is an abstract base class
00057 //
00058 //  ReceivePort:
00059 //    Represents a mach port for which we have receive rights
00060 //
00061 //  MachPortSender:
00062 //    Represents a mach port for which we have send rights
00063 //
00064 // Here's an example to receive a message on a server port:
00065 //
00066 //        // This creates our named server port
00067 //        ReceivePort receivePort("com.Google.MyService");
00068 //
00069 //        MachReceiveMessage message;
00070 //        kern_return_t result = receivePort.WaitForMessage(&message, 0);
00071 //
00072 //        if (result == KERN_SUCCESS && message.GetMessageID() == 57) {
00073 //          mach_port_t task = message.GetTranslatedPort(0);
00074 //          mach_port_t thread = message.GetTranslatedPort(1);
00075 //
00076 //          char *messageString = message.GetData();
00077 //
00078 //          printf("message string = %s\n", messageString);
00079 //        }
00080 //
00081 // Here is an example of using these classes to send a message to this port:
00082 //
00083 //    // send to already named port
00084 //    MachPortSender sender("com.Google.MyService");
00085 //    MachSendMessage message(57);      // our message ID is 57
00086 //
00087 //    // add some ports to be translated for us
00088 //    message.AddDescriptor(mach_task_self());     // our task
00089 //    message.AddDescriptor(mach_thread_self());   // this thread
00090 //
00091 //    char messageString[] = "Hello server!\n";
00092 //    message.SetData(messageString, strlen(messageString)+1);
00093 //
00094 //    kern_return_t result = sender.SendMessage(message, 1000); // timeout 1000ms
00095 //
00096 
00097 namespace google_breakpad {
00098 #define PRINT_MACH_RESULT(result_, message_) \
00099   printf(message_" %s (%d)\n", mach_error_string(result_), result_ );
00100 
00101 //==============================================================================
00102 // A wrapper class for mach_msg_port_descriptor_t (with same memory layout)
00103 // with convenient constructors and accessors
00104 class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
00105  public:
00106   // General-purpose constructor
00107   MachMsgPortDescriptor(mach_port_t in_name,
00108                         mach_msg_type_name_t in_disposition) {
00109     name = in_name;
00110     pad1 = 0;
00111     pad2 = 0;
00112     disposition = in_disposition;
00113     type = MACH_MSG_PORT_DESCRIPTOR;
00114   }
00115 
00116   // For passing send rights to a port
00117   MachMsgPortDescriptor(mach_port_t in_name) {
00118     name = in_name;
00119     pad1 = 0;
00120     pad2 = 0;
00121     disposition = MACH_MSG_TYPE_COPY_SEND;
00122     type = MACH_MSG_PORT_DESCRIPTOR;
00123   }
00124 
00125   // Copy constructor
00126   MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) {
00127     name = desc.name;
00128     pad1 = desc.pad1;
00129     pad2 = desc.pad2;
00130     disposition = desc.disposition;
00131     type = desc.type;
00132   }
00133 
00134   mach_port_t GetMachPort() const {
00135     return name;
00136   }
00137 
00138   mach_msg_type_name_t GetDisposition() const {
00139     return disposition;
00140   }
00141 
00142   // For convenience
00143   operator mach_port_t() const {
00144     return GetMachPort();
00145   }
00146 };
00147 
00148 //==============================================================================
00149 // MachMessage: a wrapper for a mach message
00150 //  (mach_msg_header_t, mach_msg_body_t, extra data)
00151 //
00152 //  This considerably simplifies the construction of a message for sending
00153 //  and the getting at relevant data and descriptors for the receiver.
00154 //
00155 //  Currently the combined size of the descriptors plus data must be
00156 //  less than 1024.  But as a benefit no memory allocation is necessary.
00157 //
00158 // TODO: could consider adding malloc() support for very large messages
00159 //
00160 //  A MachMessage object is used by ReceivePort::WaitForMessage
00161 //  and MachPortSender::SendMessage
00162 //
00163 class MachMessage {
00164  public:
00165 
00166   // The receiver of the message can retrieve the raw data this way
00167   uint8_t *GetData() {
00168     return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
00169   }
00170 
00171   uint32_t GetDataLength() {
00172     return EndianU32_LtoN(GetDataPacket()->data_length);
00173   }
00174 
00175   // The message ID may be used as a code identifying the type of message
00176   void SetMessageID(int32_t message_id) {
00177     GetDataPacket()->id = EndianU32_NtoL(message_id);
00178   }
00179 
00180   int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
00181 
00182   // Adds a descriptor (typically a mach port) to be translated
00183   // returns true if successful, otherwise not enough space
00184   bool AddDescriptor(const MachMsgPortDescriptor &desc);
00185 
00186   int GetDescriptorCount() const { return body.msgh_descriptor_count; }
00187   MachMsgPortDescriptor *GetDescriptor(int n);
00188 
00189   // Convenience method which gets the mach port described by the descriptor
00190   mach_port_t GetTranslatedPort(int n);
00191 
00192   // A simple message is one with no descriptors
00193   bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
00194 
00195   // Sets raw data for the message (returns false if not enough space)
00196   bool SetData(void *data, int32_t data_length);
00197 
00198  protected:
00199   // Consider this an abstract base class - must create an actual instance
00200   // of MachReceiveMessage or MachSendMessage
00201 
00202   MachMessage() {
00203     memset(this, 0, sizeof(MachMessage));
00204   }
00205 
00206   friend class ReceivePort;
00207   friend class MachPortSender;
00208 
00209   // Represents raw data in our message
00210   struct MessageDataPacket {
00211     int32_t      id;          // little-endian
00212     int32_t      data_length; // little-endian
00213     uint8_t      data[1];     // actual size limited by sizeof(MachMessage)
00214   };
00215 
00216   MessageDataPacket* GetDataPacket();
00217 
00218   void SetDescriptorCount(int n);
00219   void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
00220 
00221   // Returns total message size setting msgh_size in the header to this value
00222   mach_msg_size_t CalculateSize();
00223 
00224   mach_msg_header_t  head;
00225   mach_msg_body_t    body;
00226   uint8_t            padding[1024]; // descriptors and data may be embedded here
00227 };
00228 
00229 //==============================================================================
00230 // MachReceiveMessage and MachSendMessage are useful to separate the idea
00231 // of a mach message being sent and being received, and adds increased type
00232 // safety:
00233 //  ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
00234 //  MachPortSender::SendMessage() only accepts a MachSendMessage
00235 
00236 //==============================================================================
00237 class MachReceiveMessage : public MachMessage {
00238  public:
00239   MachReceiveMessage() : MachMessage() {};
00240 };
00241 
00242 //==============================================================================
00243 class MachSendMessage : public MachMessage {
00244  public:
00245   MachSendMessage(int32_t message_id);
00246 };
00247 
00248 //==============================================================================
00249 // Represents a mach port for which we have receive rights
00250 class ReceivePort {
00251  public:
00252   // Creates a new mach port for receiving messages and registers a name for it
00253   explicit ReceivePort(const char *receive_port_name);
00254 
00255   // Given an already existing mach port, use it.  We take ownership of the
00256   // port and deallocate it in our destructor.
00257   explicit ReceivePort(mach_port_t receive_port);
00258 
00259   // Create a new mach port for receiving messages
00260   ReceivePort();
00261 
00262   ~ReceivePort();
00263 
00264   // Waits on the mach port until message received or timeout
00265   kern_return_t WaitForMessage(MachReceiveMessage *out_message,
00266                                mach_msg_timeout_t timeout);
00267 
00268   // The underlying mach port that we wrap
00269   mach_port_t  GetPort() const { return port_; }
00270 
00271  private:
00272   ReceivePort(const ReceivePort&);  // disable copy c-tor
00273 
00274   mach_port_t   port_;
00275   kern_return_t init_result_;
00276 };
00277 
00278 //==============================================================================
00279 // Represents a mach port for which we have send rights
00280 class MachPortSender {
00281  public:
00282   // get a port with send rights corresponding to a named registered service
00283   explicit MachPortSender(const char *receive_port_name);
00284 
00285 
00286   // Given an already existing mach port, use it.
00287   explicit MachPortSender(mach_port_t send_port);
00288 
00289   kern_return_t SendMessage(MachSendMessage &message,
00290                             mach_msg_timeout_t timeout);
00291 
00292  private:
00293   MachPortSender(const MachPortSender&);  // disable copy c-tor
00294 
00295   mach_port_t   send_port_;
00296   kern_return_t init_result_;
00297 };
00298 
00299 }  // namespace google_breakpad
00300 
00301 #endif // MACH_IPC_H__