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