Planeshift
|
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__