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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
     2 // Use of this source code is governed by a BSD-style license that can be
     3 // found in the LICENSE file.
     5 #include "chrome/common/mach_ipc_mac.h"
     7 #import <Foundation/Foundation.h>
     9 #include <stdio.h>
    10 #include "base/logging.h"
    12 //==============================================================================
    13 MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
    14   Initialize(message_id);
    15 }
    17 MachSendMessage::MachSendMessage(void *storage, size_t storage_length,
    18                                  int32_t message_id)
    19     : MachMessage(storage, storage_length) {
    20   Initialize(message_id);
    21 }
    23 void MachSendMessage::Initialize(int32_t message_id) {
    24   Head()->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
    26   // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage()
    27   Head()->msgh_local_port = MACH_PORT_NULL;
    28   Head()->msgh_reserved = 0;
    29   Head()->msgh_id = 0;
    31   SetDescriptorCount(0);  // start out with no descriptors
    33   SetMessageID(message_id);
    34   SetData(NULL, 0);       // client may add data later
    35 }
    37 //==============================================================================
    38 MachMessage::MachMessage()
    39     : storage_(new MachMessageData),  // Allocate storage_ ourselves
    40       storage_length_bytes_(sizeof(MachMessageData)),
    41       own_storage_(true) {
    42   memset(storage_, 0, storage_length_bytes_);
    43 }
    45 //==============================================================================
    46 MachMessage::MachMessage(void *storage, size_t storage_length)
    47     : storage_(static_cast<MachMessageData*>(storage)),
    48       storage_length_bytes_(storage_length),
    49       own_storage_(false) {
    50   DCHECK(storage);
    51   DCHECK(storage_length >= kEmptyMessageSize);
    52 }
    54 //==============================================================================
    55 MachMessage::~MachMessage() {
    56   if (own_storage_) {
    57     delete storage_;
    58     storage_ = NULL;
    59   }
    60 }
    62 //==============================================================================
    63 // returns true if successful
    64 bool MachMessage::SetData(const void* data,
    65                           int32_t data_length) {
    66   // Enforce the fact that it's only safe to call this method once on a
    67   // message.
    68   DCHECK(GetDataPacket()->data_length == 0);
    70   // first check to make sure we have enough space
    71   int size = CalculateSize();
    72   int new_size = size + data_length;
    74   if ((unsigned)new_size > storage_length_bytes_) {
    75     return false;  // not enough space
    76   }
    78   GetDataPacket()->data_length = EndianU32_NtoL(data_length);
    79   if (data) memcpy(GetDataPacket()->data, data, data_length);
    81   // Update the Mach header with the new aligned size of the message.
    82   CalculateSize();
    84   return true;
    85 }
    87 //==============================================================================
    88 // calculates and returns the total size of the message
    89 // Currently, the entire message MUST fit inside of the MachMessage
    90 //    messsage size <= EmptyMessageSize()
    91 int MachMessage::CalculateSize() {
    92   int size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t);
    94   // add space for MessageDataPacket
    95   int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3;
    96   size += 2*sizeof(int32_t) + alignedDataLength;
    98   // add space for descriptors
    99   size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor);
   101   Head()->msgh_size = size;
   103   return size;
   104 }
   106 //==============================================================================
   107 MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
   108   int desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
   109   MessageDataPacket *packet =
   110     reinterpret_cast<MessageDataPacket*>(storage_->padding + desc_size);
   112   return packet;
   113 }
   115 //==============================================================================
   116 void MachMessage::SetDescriptor(int n,
   117                                 const MachMsgPortDescriptor &desc) {
   118   MachMsgPortDescriptor *desc_array =
   119     reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
   120   desc_array[n] = desc;
   121 }
   123 //==============================================================================
   124 // returns true if successful otherwise there was not enough space
   125 bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
   126   // first check to make sure we have enough space
   127   int size = CalculateSize();
   128   int new_size = size + sizeof(MachMsgPortDescriptor);
   130   if ((unsigned)new_size > storage_length_bytes_) {
   131     return false;  // not enough space
   132   }
   134   // unfortunately, we need to move the data to allow space for the
   135   // new descriptor
   136   u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
   137   bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
   139   SetDescriptor(GetDescriptorCount(), desc);
   140   SetDescriptorCount(GetDescriptorCount() + 1);
   142   CalculateSize();
   144   return true;
   145 }
   147 //==============================================================================
   148 void MachMessage::SetDescriptorCount(int n) {
   149   storage_->body.msgh_descriptor_count = n;
   151   if (n > 0) {
   152     Head()->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
   153   } else {
   154     Head()->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
   155   }
   156 }
   158 //==============================================================================
   159 MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
   160   if (n < GetDescriptorCount()) {
   161     MachMsgPortDescriptor *desc =
   162         reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
   163     return desc + n;
   164   }
   166   return nil;
   167 }
   169 //==============================================================================
   170 mach_port_t MachMessage::GetTranslatedPort(int n) {
   171   if (n < GetDescriptorCount()) {
   172     return GetDescriptor(n)->GetMachPort();
   173   }
   174   return MACH_PORT_NULL;
   175 }
   177 #pragma mark -
   179 //==============================================================================
   180 // create a new mach port for receiving messages and register a name for it
   181 ReceivePort::ReceivePort(const char *receive_port_name) {
   182   mach_port_t current_task = mach_task_self();
   184   init_result_ = mach_port_allocate(current_task,
   185                                     MACH_PORT_RIGHT_RECEIVE,
   186                                     &port_);
   188   if (init_result_ != KERN_SUCCESS)
   189     return;
   191   init_result_ = mach_port_insert_right(current_task,
   192                                         port_,
   193                                         port_,
   194                                         MACH_MSG_TYPE_MAKE_SEND);
   196   if (init_result_ != KERN_SUCCESS)
   197     return;
   199   NSPort *ns_port = [NSMachPort portWithMachPort:port_];
   200   NSString *port_name = [NSString stringWithUTF8String:receive_port_name];
   201   [[NSMachBootstrapServer sharedInstance] registerPort:ns_port name:port_name];
   202 }
   204 //==============================================================================
   205 // create a new mach port for receiving messages
   206 ReceivePort::ReceivePort() {
   207   mach_port_t current_task = mach_task_self();
   209   init_result_ = mach_port_allocate(current_task,
   210                                     MACH_PORT_RIGHT_RECEIVE,
   211                                     &port_);
   213   if (init_result_ != KERN_SUCCESS)
   214     return;
   216   init_result_ =   mach_port_insert_right(current_task,
   217                                           port_,
   218                                           port_,
   219                                           MACH_MSG_TYPE_MAKE_SEND);
   220 }
   222 //==============================================================================
   223 // Given an already existing mach port, use it.  We take ownership of the
   224 // port and deallocate it in our destructor.
   225 ReceivePort::ReceivePort(mach_port_t receive_port)
   226   : port_(receive_port),
   227     init_result_(KERN_SUCCESS) {
   228 }
   230 //==============================================================================
   231 ReceivePort::~ReceivePort() {
   232   if (init_result_ == KERN_SUCCESS)
   233     mach_port_deallocate(mach_task_self(), port_);
   234 }
   236 //==============================================================================
   237 kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
   238                                           mach_msg_timeout_t timeout) {
   239   if (!out_message) {
   240     return KERN_INVALID_ARGUMENT;
   241   }
   243   // return any error condition encountered in constructor
   244   if (init_result_ != KERN_SUCCESS)
   245     return init_result_;
   247   out_message->Head()->msgh_bits = 0;
   248   out_message->Head()->msgh_local_port = port_;
   249   out_message->Head()->msgh_remote_port = MACH_PORT_NULL;
   250   out_message->Head()->msgh_reserved = 0;
   251   out_message->Head()->msgh_id = 0;
   253   kern_return_t result = mach_msg(out_message->Head(),
   254                                   MACH_RCV_MSG | MACH_RCV_TIMEOUT,
   255                                   0,
   256                                   out_message->MaxSize(),
   257                                   port_,
   258                                   timeout,              // timeout in ms
   259                                   MACH_PORT_NULL);
   261   return result;
   262 }
   264 #pragma mark -
   266 //==============================================================================
   267 // get a port with send rights corresponding to a named registered service
   268 MachPortSender::MachPortSender(const char *receive_port_name) {
   269   mach_port_t bootstrap_port = 0;
   270   init_result_ = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
   272   if (init_result_ != KERN_SUCCESS)
   273     return;
   275   init_result_ = bootstrap_look_up(bootstrap_port,
   276                     const_cast<char*>(receive_port_name),
   277                     &send_port_);
   278 }
   280 //==============================================================================
   281 MachPortSender::MachPortSender(mach_port_t send_port)
   282   : send_port_(send_port),
   283     init_result_(KERN_SUCCESS) {
   284 }
   286 //==============================================================================
   287 kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
   288                                           mach_msg_timeout_t timeout) {
   289   if (message.Head()->msgh_size == 0) {
   290     NOTREACHED();
   291     return KERN_INVALID_VALUE;    // just for safety -- never should occur
   292   };
   294   if (init_result_ != KERN_SUCCESS)
   295     return init_result_;
   297   message.Head()->msgh_remote_port = send_port_;
   299   kern_return_t result = mach_msg(message.Head(),
   300                                   MACH_SEND_MSG | MACH_SEND_TIMEOUT,
   301                                   message.Head()->msgh_size,
   302                                   0,
   303                                   MACH_PORT_NULL,
   304                                   timeout,              // timeout in ms
   305                                   MACH_PORT_NULL);
   307   return result;
   308 }

mercurial