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