OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/system/message_pipe.h" | 5 #include "mojo/system/message_pipe.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "mojo/system/channel.h" | 8 #include "mojo/system/channel.h" |
9 #include "mojo/system/local_message_pipe_endpoint.h" | 9 #include "mojo/system/local_message_pipe_endpoint.h" |
10 #include "mojo/system/message_in_transit.h" | 10 #include "mojo/system/message_in_transit.h" |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 // TODO(vtl): Handle flags. | 67 // TODO(vtl): Handle flags. |
68 MojoResult MessagePipe::WriteMessage( | 68 MojoResult MessagePipe::WriteMessage( |
69 unsigned port, | 69 unsigned port, |
70 const void* bytes, | 70 const void* bytes, |
71 uint32_t num_bytes, | 71 uint32_t num_bytes, |
72 std::vector<DispatcherTransport>* transports, | 72 std::vector<DispatcherTransport>* transports, |
73 MojoWriteMessageFlags flags) { | 73 MojoWriteMessageFlags flags) { |
74 DCHECK(port == 0 || port == 1); | 74 DCHECK(port == 0 || port == 1); |
75 uint32_t num_handles = | 75 uint32_t num_handles = |
76 transports ? static_cast<uint32_t>(transports->size()) : 0; | 76 transports ? static_cast<uint32_t>(transports->size()) : 0; |
77 return EnqueueMessage( | 77 return EnqueueMessageInternal( |
78 GetPeerPort(port), | 78 GetPeerPort(port), |
79 make_scoped_ptr(new MessageInTransit( | 79 make_scoped_ptr(new MessageInTransit( |
80 MessageInTransit::kTypeMessagePipeEndpoint, | 80 MessageInTransit::kTypeMessagePipeEndpoint, |
81 MessageInTransit::kSubtypeMessagePipeEndpointData, | 81 MessageInTransit::kSubtypeMessagePipeEndpointData, |
82 num_bytes, num_handles, bytes)), | 82 num_bytes, num_handles, bytes)), |
83 transports); | 83 transports); |
84 } | 84 } |
85 | 85 |
86 MojoResult MessagePipe::ReadMessage( | 86 MojoResult MessagePipe::ReadMessage( |
87 unsigned port, | 87 unsigned port, |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 | 138 |
139 scoped_ptr<MessagePipeEndpoint> replacement_endpoint( | 139 scoped_ptr<MessagePipeEndpoint> replacement_endpoint( |
140 new ProxyMessagePipeEndpoint( | 140 new ProxyMessagePipeEndpoint( |
141 static_cast<LocalMessagePipeEndpoint*>(endpoints_[port].get()), | 141 static_cast<LocalMessagePipeEndpoint*>(endpoints_[port].get()), |
142 is_peer_open)); | 142 is_peer_open)); |
143 endpoints_[port].swap(replacement_endpoint); | 143 endpoints_[port].swap(replacement_endpoint); |
144 } | 144 } |
145 | 145 |
146 MojoResult MessagePipe::EnqueueMessage( | 146 MojoResult MessagePipe::EnqueueMessage( |
147 unsigned port, | 147 unsigned port, |
148 scoped_ptr<MessageInTransit> message, | 148 scoped_ptr<MessageInTransit> message) { |
149 std::vector<DispatcherTransport>* transports) { | 149 return EnqueueMessageInternal(port, message.Pass(), NULL); |
150 DCHECK(port == 0 || port == 1); | |
151 DCHECK(message.get()); | |
152 if (message->num_handles() == 0) { | |
153 // If |message->num_handles()| is 0, then |transports| should be null and | |
154 // |message| should not have dispatchers. | |
155 DCHECK(!transports); | |
156 DCHECK(!message->has_dispatchers()); | |
157 } else { | |
158 // Otherwise either |transports| must be (non-null and) of the right size | |
159 // and the message shouldn't have dispatchers, or |transports| must be null | |
160 // and the message should have the right number of dispatchers. | |
161 DCHECK((transports && transports->size() == message->num_handles() && | |
162 !message->has_dispatchers()) || | |
163 (!transports && message->has_dispatchers() && | |
164 message->dispatchers()->size() == message->num_handles())); | |
165 } | |
166 | |
167 if (message->type() == MessageInTransit::kTypeMessagePipe) { | |
168 DCHECK(!transports); | |
169 return HandleControlMessage(port, message.Pass()); | |
170 } | |
171 | |
172 DCHECK_EQ(message->type(), MessageInTransit::kTypeMessagePipeEndpoint); | |
173 | |
174 base::AutoLock locker(lock_); | |
175 DCHECK(endpoints_[GetPeerPort(port)].get()); | |
176 | |
177 // The destination port need not be open, unlike the source port. | |
178 if (!endpoints_[port].get()) | |
179 return MOJO_RESULT_FAILED_PRECONDITION; | |
180 | |
181 if (transports) { | |
182 DCHECK(!message->dispatchers()); | |
183 | |
184 // You're not allowed to send either handle to a message pipe over the | |
185 // message pipe, so check for this. (The case of trying to write a handle to | |
186 // itself is taken care of by |Core|. That case kind of makes sense, but | |
187 // leads to complications if, e.g., both sides try to do the same thing with | |
188 // their respective handles simultaneously. The other case, of trying to | |
189 // write the peer handle to a handle, doesn't make sense -- since no handle | |
190 // will be available to read the message from.) | |
191 for (size_t i = 0; i < transports->size(); i++) { | |
192 if (!(*transports)[i].is_valid()) | |
193 continue; | |
194 if ((*transports)[i].GetType() == Dispatcher::kTypeMessagePipe) { | |
195 MessagePipeDispatcherTransport mp_transport((*transports)[i]); | |
196 if (mp_transport.GetMessagePipe() == this) { | |
197 // The other case should have been disallowed by |Core|. (Note: |port| | |
198 // is the peer port of the handle given to |WriteMessage()|.) | |
199 DCHECK_EQ(mp_transport.GetPort(), port); | |
200 return MOJO_RESULT_INVALID_ARGUMENT; | |
201 } | |
202 } | |
203 } | |
204 | |
205 // Clone the dispatchers and attach them to the message. (This must be done | |
206 // as a separate loop, since we want to leave the dispatchers alone on | |
207 // failure.) | |
208 scoped_ptr<std::vector<scoped_refptr<Dispatcher> > > | |
209 dispatchers(new std::vector<scoped_refptr<Dispatcher> >()); | |
210 dispatchers->reserve(transports->size()); | |
211 for (size_t i = 0; i < transports->size(); i++) { | |
212 if ((*transports)[i].is_valid()) { | |
213 dispatchers->push_back( | |
214 (*transports)[i].CreateEquivalentDispatcherAndClose()); | |
215 } else { | |
216 LOG(WARNING) << "Enqueueing null dispatcher"; | |
217 dispatchers->push_back(scoped_refptr<Dispatcher>()); | |
218 } | |
219 } | |
220 message->SetDispatchers(dispatchers.Pass()); | |
221 } | |
222 | |
223 // The endpoint's |EnqueueMessage()| may not report failure. | |
224 endpoints_[port]->EnqueueMessage(message.Pass()); | |
225 return MOJO_RESULT_OK; | |
226 } | 150 } |
227 | 151 |
228 bool MessagePipe::Attach(unsigned port, | 152 bool MessagePipe::Attach(unsigned port, |
229 scoped_refptr<Channel> channel, | 153 scoped_refptr<Channel> channel, |
230 MessageInTransit::EndpointId local_id) { | 154 MessageInTransit::EndpointId local_id) { |
231 DCHECK(port == 0 || port == 1); | 155 DCHECK(port == 0 || port == 1); |
232 DCHECK(channel.get()); | 156 DCHECK(channel.get()); |
233 DCHECK_NE(local_id, MessageInTransit::kInvalidEndpointId); | 157 DCHECK_NE(local_id, MessageInTransit::kInvalidEndpointId); |
234 | 158 |
235 base::AutoLock locker(lock_); | 159 base::AutoLock locker(lock_); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 } | 192 } |
269 | 193 |
270 MessagePipe::~MessagePipe() { | 194 MessagePipe::~MessagePipe() { |
271 // Owned by the dispatchers. The owning dispatchers should only release us via | 195 // Owned by the dispatchers. The owning dispatchers should only release us via |
272 // their |Close()| method, which should inform us of being closed via our | 196 // their |Close()| method, which should inform us of being closed via our |
273 // |Close()|. Thus these should already be null. | 197 // |Close()|. Thus these should already be null. |
274 DCHECK(!endpoints_[0].get()); | 198 DCHECK(!endpoints_[0].get()); |
275 DCHECK(!endpoints_[1].get()); | 199 DCHECK(!endpoints_[1].get()); |
276 } | 200 } |
277 | 201 |
| 202 MojoResult MessagePipe::EnqueueMessageInternal( |
| 203 unsigned port, |
| 204 scoped_ptr<MessageInTransit> message, |
| 205 std::vector<DispatcherTransport>* transports) { |
| 206 DCHECK(port == 0 || port == 1); |
| 207 DCHECK(message.get()); |
| 208 |
| 209 if (message->type() == MessageInTransit::kTypeMessagePipe) { |
| 210 DCHECK(!transports); |
| 211 return HandleControlMessage(port, message.Pass()); |
| 212 } |
| 213 |
| 214 DCHECK_EQ(message->type(), MessageInTransit::kTypeMessagePipeEndpoint); |
| 215 |
| 216 base::AutoLock locker(lock_); |
| 217 DCHECK(endpoints_[GetPeerPort(port)].get()); |
| 218 |
| 219 // The destination port need not be open, unlike the source port. |
| 220 if (!endpoints_[port].get()) |
| 221 return MOJO_RESULT_FAILED_PRECONDITION; |
| 222 |
| 223 if (transports) { |
| 224 MojoResult result = AttachTransportsNoLock(port, message.get(), transports); |
| 225 if (result != MOJO_RESULT_OK) |
| 226 return result; |
| 227 } |
| 228 |
| 229 if (message->has_dispatchers()) |
| 230 DCHECK_EQ(message->dispatchers()->size(), message->num_handles()); |
| 231 |
| 232 // The endpoint's |EnqueueMessage()| may not report failure. |
| 233 endpoints_[port]->EnqueueMessage(message.Pass()); |
| 234 return MOJO_RESULT_OK; |
| 235 } |
| 236 |
| 237 MojoResult MessagePipe::AttachTransportsNoLock( |
| 238 unsigned port, |
| 239 MessageInTransit* message, |
| 240 std::vector<DispatcherTransport>* transports) { |
| 241 DCHECK(!message->has_dispatchers()); |
| 242 DCHECK_EQ(transports->size(), message->num_handles()); |
| 243 |
| 244 // You're not allowed to send either handle to a message pipe over the message |
| 245 // pipe, so check for this. (The case of trying to write a handle to itself is |
| 246 // taken care of by |Core|. That case kind of makes sense, but leads to |
| 247 // complications if, e.g., both sides try to do the same thing with their |
| 248 // respective handles simultaneously. The other case, of trying to write the |
| 249 // peer handle to a handle, doesn't make sense -- since no handle will be |
| 250 // available to read the message from.) |
| 251 for (size_t i = 0; i < transports->size(); i++) { |
| 252 if (!(*transports)[i].is_valid()) |
| 253 continue; |
| 254 if ((*transports)[i].GetType() == Dispatcher::kTypeMessagePipe) { |
| 255 MessagePipeDispatcherTransport mp_transport((*transports)[i]); |
| 256 if (mp_transport.GetMessagePipe() == this) { |
| 257 // The other case should have been disallowed by |Core|. (Note: |port| |
| 258 // is the peer port of the handle given to |WriteMessage()|.) |
| 259 DCHECK_EQ(mp_transport.GetPort(), port); |
| 260 return MOJO_RESULT_INVALID_ARGUMENT; |
| 261 } |
| 262 } |
| 263 } |
| 264 |
| 265 // Clone the dispatchers and attach them to the message. (This must be done as |
| 266 // a separate loop, since we want to leave the dispatchers alone on failure.) |
| 267 scoped_ptr<std::vector<scoped_refptr<Dispatcher> > > |
| 268 dispatchers(new std::vector<scoped_refptr<Dispatcher> >()); |
| 269 dispatchers->reserve(transports->size()); |
| 270 for (size_t i = 0; i < transports->size(); i++) { |
| 271 if ((*transports)[i].is_valid()) { |
| 272 dispatchers->push_back( |
| 273 (*transports)[i].CreateEquivalentDispatcherAndClose()); |
| 274 } else { |
| 275 LOG(WARNING) << "Enqueueing null dispatcher"; |
| 276 dispatchers->push_back(scoped_refptr<Dispatcher>()); |
| 277 } |
| 278 } |
| 279 message->SetDispatchers(dispatchers.Pass()); |
| 280 return MOJO_RESULT_OK; |
| 281 } |
| 282 |
278 MojoResult MessagePipe::HandleControlMessage( | 283 MojoResult MessagePipe::HandleControlMessage( |
279 unsigned /*port*/, | 284 unsigned /*port*/, |
280 scoped_ptr<MessageInTransit> message) { | 285 scoped_ptr<MessageInTransit> message) { |
281 LOG(WARNING) << "Unrecognized MessagePipe control message subtype " | 286 LOG(WARNING) << "Unrecognized MessagePipe control message subtype " |
282 << message->subtype(); | 287 << message->subtype(); |
283 return MOJO_RESULT_UNKNOWN; | 288 return MOJO_RESULT_UNKNOWN; |
284 } | 289 } |
285 | 290 |
286 } // namespace system | 291 } // namespace system |
287 } // namespace mojo | 292 } // namespace mojo |
OLD | NEW |