• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   COMPILE_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   COMPILE_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   COMPILE_ASSERT(kMaxMessageNumBytes % kMessageAlignment == 0,
52                  kMessageAlignment_not_a_multiple_of_alignment);
53 };
54 
View(size_t message_size,const void * buffer)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(buffer_, message_size,
59                                               &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 
IsValid(size_t serialized_platform_handle_size,const char ** error_message) const65 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 
MessageInTransit(Type type,Subtype subtype,uint32_t num_bytes,const void * bytes)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*>(base::AlignedAlloc(main_buffer_size_,
94                                                          kMessageAlignment))) {
95   DCHECK_LE(num_bytes, kMaxMessageNumBytes);
96 
97   // |total_size| is updated below, from the other values.
98   header()->type = type;
99   header()->subtype = subtype;
100   header()->source_id = kInvalidEndpointId;
101   header()->destination_id = kInvalidEndpointId;
102   header()->num_bytes = num_bytes;
103   header()->unused = 0;
104   // Note: If dispatchers are subsequently attached, then |total_size| will have
105   // to be adjusted.
106   UpdateTotalSize();
107 
108   if (bytes) {
109     memcpy(MessageInTransit::bytes(), bytes, num_bytes);
110     memset(static_cast<char*>(MessageInTransit::bytes()) + num_bytes, 0,
111            main_buffer_size_ - sizeof(Header) - num_bytes);
112   } else {
113     memset(MessageInTransit::bytes(), 0, main_buffer_size_ - sizeof(Header));
114   }
115 }
116 
MessageInTransit(const View & message_view)117 MessageInTransit::MessageInTransit(const View& message_view)
118     : main_buffer_size_(message_view.main_buffer_size()),
119       main_buffer_(static_cast<char*>(base::AlignedAlloc(main_buffer_size_,
120                                                          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 
~MessageInTransit()129 MessageInTransit::~MessageInTransit() {
130   if (dispatchers_) {
131     for (size_t i = 0; i < dispatchers_->size(); i++) {
132       if (!(*dispatchers_)[i])
133         continue;
134 
135       DCHECK((*dispatchers_)[i]->HasOneRef());
136       (*dispatchers_)[i]->Close();
137     }
138   }
139 }
140 
141 // static
GetNextMessageSize(const void * buffer,size_t buffer_size,size_t * next_message_size)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(reinterpret_cast<uintptr_t>(buffer) %
150                 MessageInTransit::kMessageAlignment, 0u);
151 
152   if (buffer_size < sizeof(Header))
153     return false;
154 
155   const Header* header = static_cast<const Header*>(buffer);
156   *next_message_size = header->total_size;
157   DCHECK_EQ(*next_message_size % kMessageAlignment, 0u);
158   return true;
159 }
160 
SetDispatchers(scoped_ptr<DispatcherVector> dispatchers)161 void MessageInTransit::SetDispatchers(
162     scoped_ptr<DispatcherVector> dispatchers) {
163   DCHECK(dispatchers);
164   DCHECK(!dispatchers_);
165   DCHECK(!transport_data_);
166 
167   dispatchers_ = dispatchers.Pass();
168 #ifndef NDEBUG
169   for (size_t i = 0; i < dispatchers_->size(); i++)
170     DCHECK(!(*dispatchers_)[i] || (*dispatchers_)[i]->HasOneRef());
171 #endif
172 }
173 
SetTransportData(scoped_ptr<TransportData> transport_data)174 void MessageInTransit::SetTransportData(
175     scoped_ptr<TransportData> transport_data) {
176   DCHECK(transport_data);
177   DCHECK(!transport_data_);
178   DCHECK(!dispatchers_);
179 
180   transport_data_ = transport_data.Pass();
181 }
182 
SerializeAndCloseDispatchers(Channel * channel)183 void MessageInTransit::SerializeAndCloseDispatchers(Channel* channel) {
184   DCHECK(channel);
185   DCHECK(!transport_data_);
186 
187   if (!dispatchers_ || !dispatchers_->size())
188     return;
189 
190   transport_data_.reset(new TransportData(dispatchers_.Pass(), channel));
191 
192   // Update the sizes in the message header.
193   UpdateTotalSize();
194 }
195 
UpdateTotalSize()196 void MessageInTransit::UpdateTotalSize() {
197   DCHECK_EQ(main_buffer_size_ % kMessageAlignment, 0u);
198   header()->total_size = static_cast<uint32_t>(main_buffer_size_);
199   if (transport_data_) {
200     header()->total_size +=
201         static_cast<uint32_t>(transport_data_->buffer_size());
202   }
203 }
204 
205 }  // namespace system
206 }  // namespace mojo
207