1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/chrome/common/mach_ipc_mac.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,314 @@ 1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#ifndef BASE_MACH_IPC_MAC_H_ 1.9 +#define BASE_MACH_IPC_MAC_H_ 1.10 + 1.11 +#include <mach/mach.h> 1.12 +#include <mach/message.h> 1.13 +#include <servers/bootstrap.h> 1.14 +#include <sys/types.h> 1.15 + 1.16 +#include <CoreServices/CoreServices.h> 1.17 + 1.18 +#include "base/basictypes.h" 1.19 + 1.20 +//============================================================================== 1.21 +// DISCUSSION: 1.22 +// 1.23 +// The three main classes of interest are 1.24 +// 1.25 +// MachMessage: a wrapper for a mach message of the following form 1.26 +// mach_msg_header_t 1.27 +// mach_msg_body_t 1.28 +// optional descriptors 1.29 +// optional extra message data 1.30 +// 1.31 +// MachReceiveMessage and MachSendMessage subclass MachMessage 1.32 +// and are used instead of MachMessage which is an abstract base class 1.33 +// 1.34 +// ReceivePort: 1.35 +// Represents a mach port for which we have receive rights 1.36 +// 1.37 +// MachPortSender: 1.38 +// Represents a mach port for which we have send rights 1.39 +// 1.40 +// Here's an example to receive a message on a server port: 1.41 +// 1.42 +// // This creates our named server port 1.43 +// ReceivePort receivePort("com.Google.MyService"); 1.44 +// 1.45 +// MachReceiveMessage message; 1.46 +// kern_return_t result = receivePort.WaitForMessage(&message, 0); 1.47 +// 1.48 +// if (result == KERN_SUCCESS && message.GetMessageID() == 57) { 1.49 +// mach_port_t task = message.GetTranslatedPort(0); 1.50 +// mach_port_t thread = message.GetTranslatedPort(1); 1.51 +// 1.52 +// char *messageString = message.GetData(); 1.53 +// 1.54 +// printf("message string = %s\n", messageString); 1.55 +// } 1.56 +// 1.57 +// Here is an example of using these classes to send a message to this port: 1.58 +// 1.59 +// // send to already named port 1.60 +// MachPortSender sender("com.Google.MyService"); 1.61 +// MachSendMessage message(57); // our message ID is 57 1.62 +// 1.63 +// // add some ports to be translated for us 1.64 +// message.AddDescriptor(mach_task_self()); // our task 1.65 +// message.AddDescriptor(mach_thread_self()); // this thread 1.66 +// 1.67 +// char messageString[] = "Hello server!\n"; 1.68 +// message.SetData(messageString, strlen(messageString)+1); 1.69 +// // timeout 1000ms 1.70 +// kern_return_t result = sender.SendMessage(message, 1000); 1.71 +// 1.72 + 1.73 +#define PRINT_MACH_RESULT(result_, message_) \ 1.74 + printf(message_" %s (%d)\n", mach_error_string(result_), result_ ); 1.75 + 1.76 +//============================================================================== 1.77 +// A wrapper class for mach_msg_port_descriptor_t (with same memory layout) 1.78 +// with convenient constructors and accessors 1.79 +class MachMsgPortDescriptor : public mach_msg_port_descriptor_t { 1.80 + public: 1.81 + // General-purpose constructor 1.82 + MachMsgPortDescriptor(mach_port_t in_name, 1.83 + mach_msg_type_name_t in_disposition) { 1.84 + name = in_name; 1.85 + pad1 = 0; 1.86 + pad2 = 0; 1.87 + disposition = in_disposition; 1.88 + type = MACH_MSG_PORT_DESCRIPTOR; 1.89 + } 1.90 + 1.91 + // For passing send rights to a port 1.92 + MachMsgPortDescriptor(mach_port_t in_name) { 1.93 + name = in_name; 1.94 + pad1 = 0; 1.95 + pad2 = 0; 1.96 + disposition = MACH_MSG_TYPE_PORT_SEND; 1.97 + type = MACH_MSG_PORT_DESCRIPTOR; 1.98 + } 1.99 + 1.100 + // Copy constructor 1.101 + MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) { 1.102 + name = desc.name; 1.103 + pad1 = desc.pad1; 1.104 + pad2 = desc.pad2; 1.105 + disposition = desc.disposition; 1.106 + type = desc.type; 1.107 + } 1.108 + 1.109 + mach_port_t GetMachPort() const { 1.110 + return name; 1.111 + } 1.112 + 1.113 + mach_msg_type_name_t GetDisposition() const { 1.114 + return disposition; 1.115 + } 1.116 + 1.117 + // For convenience 1.118 + operator mach_port_t() const { 1.119 + return GetMachPort(); 1.120 + } 1.121 +}; 1.122 + 1.123 +//============================================================================== 1.124 +// MachMessage: a wrapper for a mach message 1.125 +// (mach_msg_header_t, mach_msg_body_t, extra data) 1.126 +// 1.127 +// This considerably simplifies the construction of a message for sending 1.128 +// and the getting at relevant data and descriptors for the receiver. 1.129 +// 1.130 +// This class can be initialized using external storage of an arbitrary size 1.131 +// or it can manage storage internally. 1.132 +// 1. If storage is allocated internally, the combined size of the descriptors 1.133 +// plus data must be less than 1024. But as a benefit no memory allocation is 1.134 +// necessary. 1.135 +// 2. For external storage, a buffer of at least EmptyMessageSize() must be 1.136 +// provided. 1.137 +// 1.138 +// A MachMessage object is used by ReceivePort::WaitForMessage 1.139 +// and MachPortSender::SendMessage 1.140 +// 1.141 +class MachMessage { 1.142 + public: 1.143 + 1.144 + virtual ~MachMessage(); 1.145 + 1.146 + // The receiver of the message can retrieve the raw data this way 1.147 + u_int8_t *GetData() { 1.148 + return GetDataLength() > 0 ? GetDataPacket()->data : NULL; 1.149 + } 1.150 + 1.151 + u_int32_t GetDataLength() { 1.152 + return EndianU32_LtoN(GetDataPacket()->data_length); 1.153 + } 1.154 + 1.155 + // The message ID may be used as a code identifying the type of message 1.156 + void SetMessageID(int32_t message_id) { 1.157 + GetDataPacket()->id = EndianU32_NtoL(message_id); 1.158 + } 1.159 + 1.160 + int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); } 1.161 + 1.162 + // Adds a descriptor (typically a mach port) to be translated 1.163 + // returns true if successful, otherwise not enough space 1.164 + bool AddDescriptor(const MachMsgPortDescriptor &desc); 1.165 + 1.166 + int GetDescriptorCount() const { 1.167 + return storage_->body.msgh_descriptor_count; 1.168 + } 1.169 + MachMsgPortDescriptor *GetDescriptor(int n); 1.170 + 1.171 + // Convenience method which gets the mach port described by the descriptor 1.172 + mach_port_t GetTranslatedPort(int n); 1.173 + 1.174 + // A simple message is one with no descriptors 1.175 + bool IsSimpleMessage() const { return GetDescriptorCount() == 0; } 1.176 + 1.177 + // Sets raw data for the message (returns false if not enough space) 1.178 + bool SetData(const void* data, int32_t data_length); 1.179 + 1.180 + protected: 1.181 + // Consider this an abstract base class - must create an actual instance 1.182 + // of MachReceiveMessage or MachSendMessage 1.183 + MachMessage(); 1.184 + 1.185 + // Constructor for use with preallocate storage. 1.186 + // storage_length must be >= EmptyMessageSize() 1.187 + MachMessage(void *storage, size_t storage_length); 1.188 + 1.189 + friend class ReceivePort; 1.190 + friend class MachPortSender; 1.191 + 1.192 + // Represents raw data in our message 1.193 + struct MessageDataPacket { 1.194 + int32_t id; // little-endian 1.195 + int32_t data_length; // little-endian 1.196 + u_int8_t data[1]; // actual size limited by storage_length_bytes_ 1.197 + }; 1.198 + 1.199 + MessageDataPacket* GetDataPacket(); 1.200 + 1.201 + void SetDescriptorCount(int n); 1.202 + void SetDescriptor(int n, const MachMsgPortDescriptor &desc); 1.203 + 1.204 + // Returns total message size setting msgh_size in the header to this value 1.205 + int CalculateSize(); 1.206 + 1.207 + // Returns total storage size that this object can grow to, this is inclusive 1.208 + // of the mach header. 1.209 + size_t MaxSize() const { return storage_length_bytes_; } 1.210 + 1.211 + protected: 1.212 + mach_msg_header_t *Head() { return &(storage_->head); } 1.213 + 1.214 + private: 1.215 + struct MachMessageData { 1.216 + mach_msg_header_t head; 1.217 + mach_msg_body_t body; 1.218 + // descriptors and data may be embedded here. 1.219 + u_int8_t padding[1024]; 1.220 + }; 1.221 + 1.222 + // kEmptyMessageSize needs to have the definition of MachMessageData before 1.223 + // it. 1.224 + public: 1.225 + // The size of an empty message with no data. 1.226 + static const size_t kEmptyMessageSize = sizeof(mach_msg_header_t) + 1.227 + sizeof(mach_msg_body_t) + 1.228 + sizeof(MessageDataPacket); 1.229 + 1.230 + private: 1.231 + MachMessageData *storage_; 1.232 + size_t storage_length_bytes_; 1.233 + bool own_storage_; // Is storage owned by this object? 1.234 +}; 1.235 + 1.236 +//============================================================================== 1.237 +// MachReceiveMessage and MachSendMessage are useful to separate the idea 1.238 +// of a mach message being sent and being received, and adds increased type 1.239 +// safety: 1.240 +// ReceivePort::WaitForMessage() only accepts a MachReceiveMessage 1.241 +// MachPortSender::SendMessage() only accepts a MachSendMessage 1.242 + 1.243 +//============================================================================== 1.244 +class MachReceiveMessage : public MachMessage { 1.245 + public: 1.246 + MachReceiveMessage() : MachMessage() {} 1.247 + MachReceiveMessage(void *storage, size_t storage_length) 1.248 + : MachMessage(storage, storage_length) {} 1.249 + 1.250 + private: 1.251 + DISALLOW_COPY_AND_ASSIGN(MachReceiveMessage); 1.252 +}; 1.253 + 1.254 +//============================================================================== 1.255 +class MachSendMessage : public MachMessage { 1.256 + public: 1.257 + MachSendMessage(int32_t message_id); 1.258 + MachSendMessage(void *storage, size_t storage_length, int32_t message_id); 1.259 + 1.260 + private: 1.261 + void Initialize(int32_t message_id); 1.262 + 1.263 + DISALLOW_COPY_AND_ASSIGN(MachSendMessage); 1.264 +}; 1.265 + 1.266 +//============================================================================== 1.267 +// Represents a mach port for which we have receive rights 1.268 +class ReceivePort { 1.269 + public: 1.270 + // Creates a new mach port for receiving messages and registers a name for it 1.271 + ReceivePort(const char *receive_port_name); 1.272 + 1.273 + // Given an already existing mach port, use it. We take ownership of the 1.274 + // port and deallocate it in our destructor. 1.275 + ReceivePort(mach_port_t receive_port); 1.276 + 1.277 + // Create a new mach port for receiving messages 1.278 + ReceivePort(); 1.279 + 1.280 + ~ReceivePort(); 1.281 + 1.282 + // Waits on the mach port until message received or timeout 1.283 + kern_return_t WaitForMessage(MachReceiveMessage *out_message, 1.284 + mach_msg_timeout_t timeout); 1.285 + 1.286 + // The underlying mach port that we wrap 1.287 + mach_port_t GetPort() const { return port_; } 1.288 + 1.289 + private: 1.290 + mach_port_t port_; 1.291 + kern_return_t init_result_; 1.292 + 1.293 + DISALLOW_COPY_AND_ASSIGN(ReceivePort); 1.294 +}; 1.295 + 1.296 +//============================================================================== 1.297 +// Represents a mach port for which we have send rights 1.298 +class MachPortSender { 1.299 + public: 1.300 + // get a port with send rights corresponding to a named registered service 1.301 + MachPortSender(const char *receive_port_name); 1.302 + 1.303 + 1.304 + // Given an already existing mach port, use it. 1.305 + MachPortSender(mach_port_t send_port); 1.306 + 1.307 + kern_return_t SendMessage(MachSendMessage &message, 1.308 + mach_msg_timeout_t timeout); 1.309 + 1.310 + private: 1.311 + mach_port_t send_port_; 1.312 + kern_return_t init_result_; 1.313 + 1.314 + DISALLOW_COPY_AND_ASSIGN(MachPortSender); 1.315 +}; 1.316 + 1.317 +#endif // BASE_MACH_IPC_MAC_H_