Home | History | Annotate | Download | only in system
      1 // Copyright 2013 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.
      4 
      5 #include "mojo/system/message_in_transit.h"
      6 
      7 #include <string.h>
      8 
      9 #include "base/compiler_specific.h"
     10 #include "base/logging.h"
     11 #include "mojo/system/constants.h"
     12 #include "mojo/system/transport_data.h"
     13 
     14 namespace mojo {
     15 namespace system {
     16 
     17 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type
     18     MessageInTransit::kTypeMessagePipeEndpoint;
     19 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type
     20     MessageInTransit::kTypeMessagePipe;
     21 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type
     22     MessageInTransit::kTypeChannel;
     23 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type
     24     MessageInTransit::kTypeRawChannel;
     25 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
     26     MessageInTransit::kSubtypeMessagePipeEndpointData;
     27 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
     28     MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint;
     29 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
     30     MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint;
     31 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
     32     MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck;
     33 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype
     34     MessageInTransit::kSubtypeRawChannelPosixExtraPlatformHandles;
     35 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::EndpointId
     36     MessageInTransit::kInvalidEndpointId;
     37 STATIC_CONST_MEMBER_DEFINITION const size_t MessageInTransit::kMessageAlignment;
     38 
     39 struct MessageInTransit::PrivateStructForCompileAsserts {
     40   // The size of |Header| must be a multiple of the alignment.
     41   static_assert(sizeof(Header) % kMessageAlignment == 0,
     42                 "sizeof(MessageInTransit::Header) invalid");
     43   // Avoid dangerous situations, but making sure that the size of the "header" +
     44   // the size of the data fits into a 31-bit number.
     45   static_assert(static_cast<uint64_t>(sizeof(Header)) + kMaxMessageNumBytes <=
     46                     0x7fffffffULL,
     47                 "kMaxMessageNumBytes too big");
     48 
     49   // We assume (to avoid extra rounding code) that the maximum message (data)
     50   // size is a multiple of the alignment.
     51   static_assert(kMaxMessageNumBytes % kMessageAlignment == 0,
     52                 "kMessageAlignment not a multiple of alignment");
     53 };
     54 
     55 MessageInTransit::View::View(size_t message_size, const void* buffer)
     56     : buffer_(buffer) {
     57   size_t next_message_size = 0;
     58   DCHECK(MessageInTransit::GetNextMessageSize(
     59       buffer_, message_size, &next_message_size));
     60   DCHECK_EQ(message_size, next_message_size);
     61   // This should be equivalent.
     62   DCHECK_EQ(message_size, total_size());
     63 }
     64 
     65 bool MessageInTransit::View::IsValid(size_t serialized_platform_handle_size,
     66                                      const char** error_message) const {
     67   // Note: This also implies a check on the |main_buffer_size()|, which is just
     68   // |RoundUpMessageAlignment(sizeof(Header) + num_bytes())|.
     69   if (num_bytes() > kMaxMessageNumBytes) {
     70     *error_message = "Message data payload too large";
     71     return false;
     72   }
     73 
     74   if (transport_data_buffer_size() > 0) {
     75     const char* e =
     76         TransportData::ValidateBuffer(serialized_platform_handle_size,
     77                                       transport_data_buffer(),
     78                                       transport_data_buffer_size());
     79     if (e) {
     80       *error_message = e;
     81       return false;
     82     }
     83   }
     84 
     85   return true;
     86 }
     87 
     88 MessageInTransit::MessageInTransit(Type type,
     89                                    Subtype subtype,
     90                                    uint32_t num_bytes,
     91                                    const void* bytes)
     92     : main_buffer_size_(RoundUpMessageAlignment(sizeof(Header) + num_bytes)),
     93       main_buffer_(static_cast<char*>(
     94           base::AlignedAlloc(main_buffer_size_, kMessageAlignment))) {
     95   ConstructorHelper(type, subtype, num_bytes);
     96   if (bytes) {
     97     memcpy(MessageInTransit::bytes(), bytes, num_bytes);
     98     memset(static_cast<char*>(MessageInTransit::bytes()) + num_bytes,
     99            0,
    100            main_buffer_size_ - sizeof(Header) - num_bytes);
    101   } else {
    102     memset(MessageInTransit::bytes(), 0, main_buffer_size_ - sizeof(Header));
    103   }
    104 }
    105 
    106 MessageInTransit::MessageInTransit(Type type,
    107                                    Subtype subtype,
    108                                    uint32_t num_bytes,
    109                                    UserPointer<const void> bytes)
    110     : main_buffer_size_(RoundUpMessageAlignment(sizeof(Header) + num_bytes)),
    111       main_buffer_(static_cast<char*>(
    112           base::AlignedAlloc(main_buffer_size_, kMessageAlignment))) {
    113   ConstructorHelper(type, subtype, num_bytes);
    114   bytes.GetArray(MessageInTransit::bytes(), num_bytes);
    115 }
    116 
    117 MessageInTransit::MessageInTransit(const View& message_view)
    118     : main_buffer_size_(message_view.main_buffer_size()),
    119       main_buffer_(static_cast<char*>(
    120           base::AlignedAlloc(main_buffer_size_, kMessageAlignment))) {
    121   DCHECK_GE(main_buffer_size_, sizeof(Header));
    122   DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u);
    123 
    124   memcpy(main_buffer_.get(), message_view.main_buffer(), main_buffer_size_);
    125   DCHECK_EQ(main_buffer_size_,
    126             RoundUpMessageAlignment(sizeof(Header) + num_bytes()));
    127 }
    128 
    129 MessageInTransit::~MessageInTransit() {
    130   if (dispatchers_) {
    131     for (size_t i = 0; i < dispatchers_->size(); i++) {
    132       if (!(*dispatchers_)[i].get())
    133         continue;
    134 
    135       DCHECK((*dispatchers_)[i]->HasOneRef());
    136       (*dispatchers_)[i]->Close();
    137     }
    138   }
    139 }
    140 
    141 // static
    142 bool MessageInTransit::GetNextMessageSize(const void* buffer,
    143                                           size_t buffer_size,
    144                                           size_t* next_message_size) {
    145   DCHECK(next_message_size);
    146   if (!buffer_size)
    147     return false;
    148   DCHECK(buffer);
    149   DCHECK_EQ(
    150       reinterpret_cast<uintptr_t>(buffer) % MessageInTransit::kMessageAlignment,
    151       0u);
    152 
    153   if (buffer_size < sizeof(Header))
    154     return false;
    155 
    156   const Header* header = static_cast<const Header*>(buffer);
    157   *next_message_size = header->total_size;
    158   DCHECK_EQ(*next_message_size % kMessageAlignment, 0u);
    159   return true;
    160 }
    161 
    162 void MessageInTransit::SetDispatchers(
    163     scoped_ptr<DispatcherVector> dispatchers) {
    164   DCHECK(dispatchers);
    165   DCHECK(!dispatchers_);
    166   DCHECK(!transport_data_);
    167 
    168   dispatchers_ = dispatchers.Pass();
    169 #ifndef NDEBUG
    170   for (size_t i = 0; i < dispatchers_->size(); i++)
    171     DCHECK(!(*dispatchers_)[i].get() || (*dispatchers_)[i]->HasOneRef());
    172 #endif
    173 }
    174 
    175 void MessageInTransit::SetTransportData(
    176     scoped_ptr<TransportData> transport_data) {
    177   DCHECK(transport_data);
    178   DCHECK(!transport_data_);
    179   DCHECK(!dispatchers_);
    180 
    181   transport_data_ = transport_data.Pass();
    182 }
    183 
    184 void MessageInTransit::SerializeAndCloseDispatchers(Channel* channel) {
    185   DCHECK(channel);
    186   DCHECK(!transport_data_);
    187 
    188   if (!dispatchers_ || !dispatchers_->size())
    189     return;
    190 
    191   transport_data_.reset(new TransportData(dispatchers_.Pass(), channel));
    192 
    193   // Update the sizes in the message header.
    194   UpdateTotalSize();
    195 }
    196 
    197 void MessageInTransit::ConstructorHelper(Type type,
    198                                          Subtype subtype,
    199                                          uint32_t num_bytes) {
    200   DCHECK_LE(num_bytes, kMaxMessageNumBytes);
    201 
    202   // |total_size| is updated below, from the other values.
    203   header()->type = type;
    204   header()->subtype = subtype;
    205   header()->source_id = kInvalidEndpointId;
    206   header()->destination_id = kInvalidEndpointId;
    207   header()->num_bytes = num_bytes;
    208   header()->unused = 0;
    209   // Note: If dispatchers are subsequently attached, then |total_size| will have
    210   // to be adjusted.
    211   UpdateTotalSize();
    212 }
    213 
    214 void MessageInTransit::UpdateTotalSize() {
    215   DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u);
    216   header()->total_size = static_cast<uint32_t>(main_buffer_size_);
    217   if (transport_data_) {
    218     header()->total_size +=
    219         static_cast<uint32_t>(transport_data_->buffer_size());
    220   }
    221 }
    222 
    223 }  // namespace system
    224 }  // namespace mojo
    225