1
// Copyright (c) 2007, Google Inc.
2
// All rights reserved.
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are
8
// * Redistributions of source code must retain the above copyright
9
// notice, this list of conditions and the following disclaimer.
10
// * Redistributions in binary form must reproduce the above
11
// copyright notice, this list of conditions and the following disclaimer
12
// in the documentation and/or other materials provided with the
14
// * Neither the name of Google Inc. nor the names of its
15
// contributors may be used to endorse or promote products derived from
16
// this software without specific prior written permission.
18
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
// Some helpful wrappers for using Mach IPC calls
38
#import <mach/message.h>
39
#import <servers/bootstrap.h>
42
#import <CoreServices/CoreServices.h>
44
//==============================================================================
47
// The three main classes of interest are
49
// MachMessage: a wrapper for a mach message of the following form
52
// optional descriptors
53
// optional extra message data
55
// MachReceiveMessage and MachSendMessage subclass MachMessage
56
// and are used instead of MachMessage which is an abstract base class
59
// Represents a mach port for which we have receive rights
62
// Represents a mach port for which we have send rights
64
// Here's an example to receive a message on a server port:
66
// // This creates our named server port
67
// ReceivePort receivePort("com.Google.MyService");
69
// MachReceiveMessage message;
70
// kern_return_t result = receivePort.WaitForMessage(&message, 0);
72
// if (result == KERN_SUCCESS && message.GetMessageID() == 57) {
73
// mach_port_t task = message.GetTranslatedPort(0);
74
// mach_port_t thread = message.GetTranslatedPort(1);
76
// char *messageString = message.GetData();
78
// printf("message string = %s\n", messageString);
81
// Here is an example of using these classes to send a message to this port:
83
// // send to already named port
84
// MachPortSender sender("com.Google.MyService");
85
// MachSendMessage message(57); // our message ID is 57
87
// // add some ports to be translated for us
88
// message.AddDescriptor(mach_task_self()); // our task
89
// message.AddDescriptor(mach_thread_self()); // this thread
91
// char messageString[] = "Hello server!\n";
92
// message.SetData(messageString, strlen(messageString)+1);
94
// kern_return_t result = sender.SendMessage(message, 1000); // timeout 1000ms
97
namespace google_breakpad {
98
#define PRINT_MACH_RESULT(result_, message_) \
99
printf(message_" %s (%d)\n", mach_error_string(result_), result_ );
101
//==============================================================================
102
// A wrapper class for mach_msg_port_descriptor_t (with same memory layout)
103
// with convenient constructors and accessors
104
class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
106
// General-purpose constructor
107
MachMsgPortDescriptor(mach_port_t in_name,
108
mach_msg_type_name_t in_disposition) {
112
disposition = in_disposition;
113
type = MACH_MSG_PORT_DESCRIPTOR;
116
// For passing send rights to a port
117
MachMsgPortDescriptor(mach_port_t in_name) {
121
disposition = MACH_MSG_TYPE_COPY_SEND;
122
type = MACH_MSG_PORT_DESCRIPTOR;
126
MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) {
130
disposition = desc.disposition;
134
mach_port_t GetMachPort() const {
138
mach_msg_type_name_t GetDisposition() const {
143
operator mach_port_t() const {
144
return GetMachPort();
148
//==============================================================================
149
// MachMessage: a wrapper for a mach message
150
// (mach_msg_header_t, mach_msg_body_t, extra data)
152
// This considerably simplifies the construction of a message for sending
153
// and the getting at relevant data and descriptors for the receiver.
155
// Currently the combined size of the descriptors plus data must be
156
// less than 1024. But as a benefit no memory allocation is necessary.
158
// TODO: could consider adding malloc() support for very large messages
160
// A MachMessage object is used by ReceivePort::WaitForMessage
161
// and MachPortSender::SendMessage
166
// The receiver of the message can retrieve the raw data this way
167
u_int8_t *GetData() {
168
return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
171
u_int32_t GetDataLength() {
172
return EndianU32_LtoN(GetDataPacket()->data_length);
175
// The message ID may be used as a code identifying the type of message
176
void SetMessageID(int32_t message_id) {
177
GetDataPacket()->id = EndianU32_NtoL(message_id);
180
int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
182
// Adds a descriptor (typically a mach port) to be translated
183
// returns true if successful, otherwise not enough space
184
bool AddDescriptor(const MachMsgPortDescriptor &desc);
186
int GetDescriptorCount() const { return body.msgh_descriptor_count; }
187
MachMsgPortDescriptor *GetDescriptor(int n);
189
// Convenience method which gets the mach port described by the descriptor
190
mach_port_t GetTranslatedPort(int n);
192
// A simple message is one with no descriptors
193
bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
195
// Sets raw data for the message (returns false if not enough space)
196
bool SetData(void *data, int32_t data_length);
199
// Consider this an abstract base class - must create an actual instance
200
// of MachReceiveMessage or MachSendMessage
203
memset(this, 0, sizeof(MachMessage));
206
friend class ReceivePort;
207
friend class MachPortSender;
209
// Represents raw data in our message
210
struct MessageDataPacket {
211
int32_t id; // little-endian
212
int32_t data_length; // little-endian
213
u_int8_t data[1]; // actual size limited by sizeof(MachMessage)
216
MessageDataPacket* GetDataPacket();
218
void SetDescriptorCount(int n);
219
void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
221
// Returns total message size setting msgh_size in the header to this value
222
mach_msg_size_t CalculateSize();
224
mach_msg_header_t head;
225
mach_msg_body_t body;
226
u_int8_t padding[1024]; // descriptors and data may be embedded here
229
//==============================================================================
230
// MachReceiveMessage and MachSendMessage are useful to separate the idea
231
// of a mach message being sent and being received, and adds increased type
233
// ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
234
// MachPortSender::SendMessage() only accepts a MachSendMessage
236
//==============================================================================
237
class MachReceiveMessage : public MachMessage {
239
MachReceiveMessage() : MachMessage() {};
242
//==============================================================================
243
class MachSendMessage : public MachMessage {
245
MachSendMessage(int32_t message_id);
248
//==============================================================================
249
// Represents a mach port for which we have receive rights
252
// Creates a new mach port for receiving messages and registers a name for it
253
explicit ReceivePort(const char *receive_port_name);
255
// Given an already existing mach port, use it. We take ownership of the
256
// port and deallocate it in our destructor.
257
explicit ReceivePort(mach_port_t receive_port);
259
// Create a new mach port for receiving messages
264
// Waits on the mach port until message received or timeout
265
kern_return_t WaitForMessage(MachReceiveMessage *out_message,
266
mach_msg_timeout_t timeout);
268
// The underlying mach port that we wrap
269
mach_port_t GetPort() const { return port_; }
272
ReceivePort(const ReceivePort&); // disable copy c-tor
275
kern_return_t init_result_;
278
//==============================================================================
279
// Represents a mach port for which we have send rights
280
class MachPortSender {
282
// get a port with send rights corresponding to a named registered service
283
explicit MachPortSender(const char *receive_port_name);
286
// Given an already existing mach port, use it.
287
explicit MachPortSender(mach_port_t send_port);
289
kern_return_t SendMessage(MachSendMessage &message,
290
mach_msg_timeout_t timeout);
293
MachPortSender(const MachPortSender&); // disable copy c-tor
295
mach_port_t send_port_;
296
kern_return_t init_result_;
299
} // namespace google_breakpad
301
#endif // MACH_IPC_H__