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

changeset 0
6474c204b198
     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_

mercurial