blob: 7d39101965e735f691f188756d4848e955cb4772 [file] [log] [blame]
[email protected]8e03fec2011-03-31 20:34:251// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]369537e82008-11-19 18:27:562// 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]32b76ef2010-07-26 23:08:247#pragma once
[email protected]369537e82008-11-19 18:27:568
[email protected]5062bb02008-11-20 21:11:209#include <mach/mach.h>
10#include <mach/message.h>
11#include <servers/bootstrap.h>
12#include <sys/types.h>
[email protected]369537e82008-11-19 18:27:5613
[email protected]5062bb02008-11-20 21:11:2014#include <CoreServices/CoreServices.h>
15
[email protected]0bea7252011-08-05 15:34:0016#include "base/base_export.h"
[email protected]5062bb02008-11-20 21:11:2017#include "base/basictypes.h"
[email protected]369537e82008-11-19 18:27:5618
19//==============================================================================
20// DISCUSSION:
21//
22// The three main classes of interest are
23//
[email protected]b88a7492010-09-17 12:28:3224// MachMessage: a wrapper for a Mach message of the following form
[email protected]369537e82008-11-19 18:27:5625// 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]b88a7492010-09-17 12:28:3234// Represents a Mach port for which we have receive rights
[email protected]369537e82008-11-19 18:27:5635//
36// MachPortSender:
[email protected]b88a7492010-09-17 12:28:3237// Represents a Mach port for which we have send rights
[email protected]369537e82008-11-19 18:27:5638//
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]5062bb02008-11-20 21:11:2046//
[email protected]369537e82008-11-19 18:27:5647// 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]5062bb02008-11-20 21:11:2052//
[email protected]369537e82008-11-19 18:27:5653// 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]5062bb02008-11-20 21:11:2065//
[email protected]369537e82008-11-19 18:27:5666// char messageString[] = "Hello server!\n";
67// message.SetData(messageString, strlen(messageString)+1);
[email protected]f09c7182009-03-10 12:54:0468// // timeout 1000ms
69// kern_return_t result = sender.SendMessage(message, 1000);
[email protected]369537e82008-11-19 18:27:5670//
71
72#define PRINT_MACH_RESULT(result_, message_) \
73 printf(message_" %s (%d)\n", mach_error_string(result_), result_ );
74
[email protected]1fdb095d2010-01-12 21:33:4875namespace base {
76
[email protected]369537e82008-11-19 18:27:5677//==============================================================================
78// A wrapper class for mach_msg_port_descriptor_t (with same memory layout)
79// with convenient constructors and accessors
80class 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]5062bb02008-11-20 21:11:2091
[email protected]369537e82008-11-19 18:27:5692 // 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]5062bb02008-11-20 21:11:20113
[email protected]369537e82008-11-19 18:27:56114 mach_msg_type_name_t GetDisposition() const {
115 return disposition;
116 }
[email protected]5062bb02008-11-20 21:11:20117
[email protected]369537e82008-11-19 18:27:56118 // For convenience
119 operator mach_port_t() const {
120 return GetMachPort();
121 }
122};
123
124//==============================================================================
[email protected]b88a7492010-09-17 12:28:32125// MachMessage: a wrapper for a Mach message
[email protected]369537e82008-11-19 18:27:56126// (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]5062bb02008-11-20 21:11:20131// 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]369537e82008-11-19 18:27:56138//
139// A MachMessage object is used by ReceivePort::WaitForMessage
140// and MachPortSender::SendMessage
141//
[email protected]0bea7252011-08-05 15:34:00142class BASE_EXPORT MachMessage {
[email protected]369537e82008-11-19 18:27:56143 public:
[email protected]8e03fec2011-03-31 20:34:25144 static const size_t kEmptyMessageSize;
[email protected]369537e82008-11-19 18:27:56145
[email protected]5062bb02008-11-20 21:11:20146 virtual ~MachMessage();
147
[email protected]369537e82008-11-19 18:27:56148 // 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]5062bb02008-11-20 21:11:20152
[email protected]369537e82008-11-19 18:27:56153 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]5062bb02008-11-20 21:11:20161
[email protected]369537e82008-11-19 18:27:56162 int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
163
[email protected]b88a7492010-09-17 12:28:32164 // Adds a descriptor (typically a Mach port) to be translated
[email protected]369537e82008-11-19 18:27:56165 // returns true if successful, otherwise not enough space
[email protected]5062bb02008-11-20 21:11:20166 bool AddDescriptor(const MachMsgPortDescriptor &desc);
[email protected]369537e82008-11-19 18:27:56167
[email protected]5062bb02008-11-20 21:11:20168 int GetDescriptorCount() const {
[email protected]3740cb9b52009-12-19 04:50:04169 return storage_->body.msgh_descriptor_count;
170 }
171
[email protected]369537e82008-11-19 18:27:56172 MachMsgPortDescriptor *GetDescriptor(int n);
173
[email protected]b88a7492010-09-17 12:28:32174 // Convenience method which gets the Mach port described by the descriptor
[email protected]369537e82008-11-19 18:27:56175 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]5062bb02008-11-20 21:11:20181 bool SetData(const void* data, int32_t data_length);
[email protected]369537e82008-11-19 18:27:56182
183 protected:
184 // Consider this an abstract base class - must create an actual instance
185 // of MachReceiveMessage or MachSendMessage
[email protected]5062bb02008-11-20 21:11:20186 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]369537e82008-11-19 18:27:56191
192 friend class ReceivePort;
193 friend class MachPortSender;
194
195 // Represents raw data in our message
196 struct MessageDataPacket {
[email protected]f09c7182009-03-10 12:54:04197 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]369537e82008-11-19 18:27:56200 };
201
202 MessageDataPacket* GetDataPacket();
203
204 void SetDescriptorCount(int n);
[email protected]5062bb02008-11-20 21:11:20205 void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
[email protected]369537e82008-11-19 18:27:56206
[email protected]5062bb02008-11-20 21:11:20207 // Returns total message size setting msgh_size in the header to this value
[email protected]369537e82008-11-19 18:27:56208 int CalculateSize();
209
[email protected]5062bb02008-11-20 21:11:20210 // Returns total storage size that this object can grow to, this is inclusive
[email protected]b88a7492010-09-17 12:28:32211 // of the Mach header.
[email protected]5062bb02008-11-20 21:11:20212 size_t MaxSize() const { return storage_length_bytes_; }
213
[email protected]5062bb02008-11-20 21:11:20214 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]5062bb02008-11-20 21:11:20224 MachMessageData *storage_;
225 size_t storage_length_bytes_;
226 bool own_storage_; // Is storage owned by this object?
[email protected]369537e82008-11-19 18:27:56227};
228
229//==============================================================================
230// MachReceiveMessage and MachSendMessage are useful to separate the idea
[email protected]b88a7492010-09-17 12:28:32231// of a Mach message being sent and being received, and adds increased type
[email protected]369537e82008-11-19 18:27:56232// safety:
[email protected]5062bb02008-11-20 21:11:20233// ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
234// MachPortSender::SendMessage() only accepts a MachSendMessage
[email protected]369537e82008-11-19 18:27:56235
236//==============================================================================
237class MachReceiveMessage : public MachMessage {
238 public:
[email protected]5062bb02008-11-20 21:11:20239 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]369537e82008-11-19 18:27:56245};
246
247//==============================================================================
[email protected]0bea7252011-08-05 15:34:00248class BASE_EXPORT MachSendMessage : public MachMessage {
[email protected]369537e82008-11-19 18:27:56249 public:
[email protected]c0028792010-01-12 00:39:15250 explicit MachSendMessage(int32_t message_id);
[email protected]5062bb02008-11-20 21:11:20251 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]369537e82008-11-19 18:27:56257};
258
259//==============================================================================
[email protected]b88a7492010-09-17 12:28:32260// Represents a Mach port for which we have receive rights
[email protected]0bea7252011-08-05 15:34:00261class BASE_EXPORT ReceivePort {
[email protected]369537e82008-11-19 18:27:56262 public:
[email protected]b88a7492010-09-17 12:28:32263 // Creates a new Mach port for receiving messages and registers a name for it
[email protected]c0028792010-01-12 00:39:15264 explicit ReceivePort(const char *receive_port_name);
[email protected]369537e82008-11-19 18:27:56265
[email protected]b88a7492010-09-17 12:28:32266 // Given an already existing Mach port, use it. We take ownership of the
[email protected]369537e82008-11-19 18:27:56267 // port and deallocate it in our destructor.
[email protected]c0028792010-01-12 00:39:15268 explicit ReceivePort(mach_port_t receive_port);
[email protected]369537e82008-11-19 18:27:56269
[email protected]b88a7492010-09-17 12:28:32270 // Create a new Mach port for receiving messages
[email protected]369537e82008-11-19 18:27:56271 ReceivePort();
272
273 ~ReceivePort();
[email protected]5062bb02008-11-20 21:11:20274
[email protected]b88a7492010-09-17 12:28:32275 // Waits on the Mach port until message received or timeout. If |timeout| is
276 // MACH_MSG_TIMEOUT_NONE, this method waits forever.
[email protected]369537e82008-11-19 18:27:56277 kern_return_t WaitForMessage(MachReceiveMessage *out_message,
278 mach_msg_timeout_t timeout);
[email protected]5062bb02008-11-20 21:11:20279
[email protected]b88a7492010-09-17 12:28:32280 // The underlying Mach port that we wrap
[email protected]369537e82008-11-19 18:27:56281 mach_port_t GetPort() const { return port_; }
282
283 private:
[email protected]369537e82008-11-19 18:27:56284 mach_port_t port_;
285 kern_return_t init_result_;
[email protected]5062bb02008-11-20 21:11:20286
287 DISALLOW_COPY_AND_ASSIGN(ReceivePort);
[email protected]369537e82008-11-19 18:27:56288};
289
290//==============================================================================
[email protected]b88a7492010-09-17 12:28:32291// Represents a Mach port for which we have send rights
[email protected]0bea7252011-08-05 15:34:00292class BASE_EXPORT MachPortSender {
[email protected]369537e82008-11-19 18:27:56293 public:
294 // get a port with send rights corresponding to a named registered service
[email protected]c0028792010-01-12 00:39:15295 explicit MachPortSender(const char *receive_port_name);
[email protected]369537e82008-11-19 18:27:56296
[email protected]5062bb02008-11-20 21:11:20297
[email protected]b88a7492010-09-17 12:28:32298 // Given an already existing Mach port, use it. Does not take ownership of
[email protected]c0028792010-01-12 00:39:15299 // |send_port|.
300 explicit MachPortSender(mach_port_t send_port);
[email protected]5062bb02008-11-20 21:11:20301
[email protected]369537e82008-11-19 18:27:56302 kern_return_t SendMessage(MachSendMessage &message,
303 mach_msg_timeout_t timeout);
[email protected]5062bb02008-11-20 21:11:20304
[email protected]369537e82008-11-19 18:27:56305 private:
[email protected]369537e82008-11-19 18:27:56306 mach_port_t send_port_;
307 kern_return_t init_result_;
[email protected]5062bb02008-11-20 21:11:20308
309 DISALLOW_COPY_AND_ASSIGN(MachPortSender);
[email protected]369537e82008-11-19 18:27:56310};
311
[email protected]1fdb095d2010-01-12 21:33:48312} // namespace base
313
[email protected]369537e82008-11-19 18:27:56314#endif // BASE_MACH_IPC_MAC_H_