ipc/chromium/src/chrome/common/mach_ipc_mac.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial