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/channel.h" | 5 #include "mojo/system/channel.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
12 #include "mojo/system/message_pipe_endpoint.h" | 12 #include "mojo/system/message_pipe_endpoint.h" |
13 | 13 |
14 namespace mojo { | 14 namespace mojo { |
15 namespace system { | 15 namespace system { |
16 | 16 |
17 COMPILE_ASSERT(Channel::kBootstrapEndpointId != | 17 COMPILE_ASSERT(Channel::kBootstrapEndpointId != |
18 MessageInTransit::kInvalidEndpointId, | 18 MessageInTransit::kInvalidEndpointId, |
19 kBootstrapEndpointId_is_invalid); | 19 kBootstrapEndpointId_is_invalid); |
20 | 20 |
21 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::EndpointId | 21 STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::EndpointId |
22 Channel::kBootstrapEndpointId; | 22 Channel::kBootstrapEndpointId; |
23 | 23 |
24 Channel::EndpointInfo::EndpointInfo() { | 24 Channel::EndpointInfo::EndpointInfo() |
25 : state(STATE_NORMAL), | |
26 port() { | |
25 } | 27 } |
26 | 28 |
27 Channel::EndpointInfo::EndpointInfo(scoped_refptr<MessagePipe> message_pipe, | 29 Channel::EndpointInfo::EndpointInfo(scoped_refptr<MessagePipe> message_pipe, |
28 unsigned port) | 30 unsigned port) |
29 : message_pipe(message_pipe), | 31 : state(STATE_NORMAL), |
32 message_pipe(message_pipe), | |
30 port(port) { | 33 port(port) { |
31 } | 34 } |
32 | 35 |
33 Channel::EndpointInfo::~EndpointInfo() { | 36 Channel::EndpointInfo::~EndpointInfo() { |
34 } | 37 } |
35 | 38 |
36 Channel::Channel() | 39 Channel::Channel() |
37 : next_local_id_(kBootstrapEndpointId) { | 40 : next_local_id_(kBootstrapEndpointId) { |
38 } | 41 } |
39 | 42 |
(...skipping 15 matching lines...) Expand all Loading... | |
55 } | 58 } |
56 | 59 |
57 void Channel::Shutdown() { | 60 void Channel::Shutdown() { |
58 DCHECK(creation_thread_checker_.CalledOnValidThread()); | 61 DCHECK(creation_thread_checker_.CalledOnValidThread()); |
59 | 62 |
60 base::AutoLock locker(lock_); | 63 base::AutoLock locker(lock_); |
61 DCHECK(raw_channel_.get()); | 64 DCHECK(raw_channel_.get()); |
62 raw_channel_->Shutdown(); | 65 raw_channel_->Shutdown(); |
63 raw_channel_.reset(); | 66 raw_channel_.reset(); |
64 | 67 |
65 // This should not occur, but it probably mostly results in leaking; | 68 // This shouldn't usually occur, but it should be okay if all the endpoints |
66 // (Explicitly clearing the |local_id_to_endpoint_info_map_| would likely put | 69 // are zombies (i.e., waiting to be removed, and not actually having any |
67 // things in an inconsistent state, which is worse. Note that if the map is | 70 // references to |MessagePipe|s). |
68 // nonempty, we probably won't be destroyed, since the endpoints have a | 71 // TODO(vtl): To make this actually okay, we need to make sure the other side |
69 // reference to us.) | 72 // channels being killed off properly. |
70 LOG_IF(ERROR, !local_id_to_endpoint_info_map_.empty()) | 73 LOG_IF(WARNING, !local_id_to_endpoint_info_map_.empty()) |
71 << "Channel shutting down with endpoints still attached"; | 74 << "Channel shutting down with endpoints still attached " |
72 // TODO(vtl): This currently blows up, but the fix will be nontrivial. | 75 "(hopefully all zombies)"; |
darin (slow to review)
2014/04/16 21:33:43
nit: indentation
viettrungluu
2014/04/16 22:25:01
Done.
| |
73 // crbug.com/360081 | 76 |
74 //DCHECK(local_id_to_endpoint_info_map_.empty()); | 77 #ifndef NDEBUG |
78 // Check that everything left is a zombie. (Note: We don't explicitly clear | |
79 // |local_id_to_endpoint_info_map_|, since that would likely put us in an | |
80 // inconsistent state if we have non-zombies.) | |
81 for (IdToEndpointInfoMap::const_iterator it = | |
82 local_id_to_endpoint_info_map_.begin(); | |
83 it != local_id_to_endpoint_info_map_.end(); | |
84 ++it) { | |
85 DCHECK_NE(it->second.state, EndpointInfo::STATE_NORMAL); | |
86 DCHECK(!it->second.message_pipe.get()); | |
87 } | |
88 #endif | |
75 } | 89 } |
76 | 90 |
77 MessageInTransit::EndpointId Channel::AttachMessagePipeEndpoint( | 91 MessageInTransit::EndpointId Channel::AttachMessagePipeEndpoint( |
78 scoped_refptr<MessagePipe> message_pipe, unsigned port) { | 92 scoped_refptr<MessagePipe> message_pipe, |
93 unsigned port) { | |
94 DCHECK(message_pipe); | |
79 DCHECK(port == 0 || port == 1); | 95 DCHECK(port == 0 || port == 1); |
80 // Note: This assertion must *not* be done under |lock_|. | |
81 DCHECK_EQ(message_pipe->GetType(port), MessagePipeEndpoint::kTypeProxy); | |
82 | 96 |
83 MessageInTransit::EndpointId local_id; | 97 MessageInTransit::EndpointId local_id; |
84 { | 98 { |
85 base::AutoLock locker(lock_); | 99 base::AutoLock locker(lock_); |
86 | 100 |
87 while (next_local_id_ == MessageInTransit::kInvalidEndpointId || | 101 while (next_local_id_ == MessageInTransit::kInvalidEndpointId || |
88 local_id_to_endpoint_info_map_.find(next_local_id_) != | 102 local_id_to_endpoint_info_map_.find(next_local_id_) != |
89 local_id_to_endpoint_info_map_.end()) | 103 local_id_to_endpoint_info_map_.end()) |
90 next_local_id_++; | 104 next_local_id_++; |
91 | 105 |
92 local_id = next_local_id_; | 106 local_id = next_local_id_; |
93 next_local_id_++; | 107 next_local_id_++; |
94 | 108 |
95 // TODO(vtl): Use emplace when we move to C++11 unordered_maps. (It'll avoid | 109 // TODO(vtl): Use emplace when we move to C++11 unordered_maps. (It'll avoid |
96 // some expensive reference count increment/decrements.) Once this is done, | 110 // some expensive reference count increment/decrements.) Once this is done, |
97 // we should be able to delete |EndpointInfo|'s default constructor. | 111 // we should be able to delete |EndpointInfo|'s default constructor. |
98 local_id_to_endpoint_info_map_[local_id] = EndpointInfo(message_pipe, port); | 112 local_id_to_endpoint_info_map_[local_id] = EndpointInfo(message_pipe, port); |
99 } | 113 } |
100 | 114 |
101 message_pipe->Attach(port, scoped_refptr<Channel>(this), local_id); | 115 // This might fail if that port got an |OnPeerClose()| before attaching. |
102 return local_id; | 116 if (message_pipe->Attach(port, scoped_refptr<Channel>(this), local_id)) |
117 return local_id; | |
118 | |
119 // Note: If it failed, quite possibly the endpoint info was removed from that | |
120 // map (there's a race between us adding it to the map above and calling | |
121 // |Attach()|). And even if an entry exists for |local_id|, we need to check | |
122 // that it's the one we added (and not some other one that was added since). | |
123 { | |
124 base::AutoLock locker(lock_); | |
125 IdToEndpointInfoMap::iterator it = | |
126 local_id_to_endpoint_info_map_.find(local_id); | |
127 if (it != local_id_to_endpoint_info_map_.end() && | |
128 it->second.message_pipe.get() == message_pipe.get() && | |
129 it->second.port == port) { | |
130 DCHECK_EQ(it->second.state, EndpointInfo::STATE_NORMAL); | |
131 // TODO(vtl): FIXME -- This is wrong. We need to specify (to | |
132 // |AttachMessagePipeEndpoint()| who's going to be responsible for calling | |
133 // |RunMessagePipeEndpoint()| ("us", or the remote by sending us a | |
134 // |kSubtypeChannelRunMessagePipeEndpoint|). If the remote is going to | |
135 // run, then we'll get messages to an "invalid" local ID (for running, for | |
136 // removal). | |
137 local_id_to_endpoint_info_map_.erase(it); | |
138 } | |
139 } | |
140 return MessageInTransit::kInvalidEndpointId; | |
103 } | 141 } |
104 | 142 |
105 bool Channel::RunMessagePipeEndpoint(MessageInTransit::EndpointId local_id, | 143 bool Channel::RunMessagePipeEndpoint(MessageInTransit::EndpointId local_id, |
106 MessageInTransit::EndpointId remote_id) { | 144 MessageInTransit::EndpointId remote_id) { |
107 EndpointInfo endpoint_info; | 145 EndpointInfo endpoint_info; |
108 { | 146 { |
109 base::AutoLock locker(lock_); | 147 base::AutoLock locker(lock_); |
110 | 148 |
111 IdToEndpointInfoMap::const_iterator it = | 149 IdToEndpointInfoMap::const_iterator it = |
112 local_id_to_endpoint_info_map_.find(local_id); | 150 local_id_to_endpoint_info_map_.find(local_id); |
113 if (it == local_id_to_endpoint_info_map_.end()) | 151 if (it == local_id_to_endpoint_info_map_.end()) |
114 return false; | 152 return false; |
115 endpoint_info = it->second; | 153 endpoint_info = it->second; |
116 } | 154 } |
117 | 155 |
156 // Assume that this was in response to |kSubtypeChannelRunMessagePipeEndpoint| | |
157 // and ignore it. | |
158 if (endpoint_info.state != EndpointInfo::STATE_NORMAL) { | |
159 DVLOG(2) << "Ignoring run message pipe endpoint for zombie endpoint " | |
160 "(local ID " << local_id << ", remote ID " << remote_id << ")"; | |
161 return true; | |
162 } | |
163 | |
118 // TODO(vtl): FIXME -- We need to handle the case that message pipe is already | 164 // TODO(vtl): FIXME -- We need to handle the case that message pipe is already |
119 // running when we're here due to |kSubtypeChannelRunMessagePipeEndpoint|). | 165 // running when we're here due to |kSubtypeChannelRunMessagePipeEndpoint|). |
120 endpoint_info.message_pipe->Run(endpoint_info.port, remote_id); | 166 endpoint_info.message_pipe->Run(endpoint_info.port, remote_id); |
121 return true; | 167 return true; |
122 } | 168 } |
123 | 169 |
124 void Channel::RunRemoteMessagePipeEndpoint( | 170 void Channel::RunRemoteMessagePipeEndpoint( |
125 MessageInTransit::EndpointId local_id, | 171 MessageInTransit::EndpointId local_id, |
126 MessageInTransit::EndpointId remote_id) { | 172 MessageInTransit::EndpointId remote_id) { |
127 base::AutoLock locker(lock_); | 173 base::AutoLock locker(lock_); |
128 | |
129 DCHECK(local_id_to_endpoint_info_map_.find(local_id) != | 174 DCHECK(local_id_to_endpoint_info_map_.find(local_id) != |
130 local_id_to_endpoint_info_map_.end()); | 175 local_id_to_endpoint_info_map_.end()); |
131 | 176 if (!SendControlMessage( |
132 scoped_ptr<MessageInTransit> message(new MessageInTransit( | 177 MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint, |
133 MessageInTransit::kTypeChannel, | 178 local_id, remote_id)) { |
134 MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint, | 179 HandleLocalError(base::StringPrintf( |
135 0, 0, NULL)); | 180 "Failed to send message to run remote message pipe endpoint (local ID " |
136 message->set_source_id(local_id); | 181 "%u, remote ID %u)", |
137 message->set_destination_id(remote_id); | 182 static_cast<unsigned>(local_id), static_cast<unsigned>(remote_id))); |
138 if (!raw_channel_->WriteMessage(message.Pass())) { | |
139 // TODO(vtl): FIXME -- I guess we should report the error back somehow so | |
140 // that the dispatcher can be closed? | |
141 CHECK(false) << "Not yet handled"; | |
142 } | 183 } |
143 } | 184 } |
144 | 185 |
145 bool Channel::WriteMessage(scoped_ptr<MessageInTransit> message) { | 186 bool Channel::WriteMessage(scoped_ptr<MessageInTransit> message) { |
146 base::AutoLock locker(lock_); | 187 base::AutoLock locker(lock_); |
147 if (!raw_channel_.get()) { | 188 if (!raw_channel_.get()) { |
148 // TODO(vtl): I think this is probably not an error condition, but I should | 189 // TODO(vtl): I think this is probably not an error condition, but I should |
149 // think about it (and the shutdown sequence) more carefully. | 190 // think about it (and the shutdown sequence) more carefully. |
150 LOG(WARNING) << "WriteMessage() after shutdown"; | 191 LOG(WARNING) << "WriteMessage() after shutdown"; |
151 return false; | 192 return false; |
152 } | 193 } |
153 | 194 |
154 return raw_channel_->WriteMessage(message.Pass()); | 195 return raw_channel_->WriteMessage(message.Pass()); |
155 } | 196 } |
156 | 197 |
157 bool Channel::IsWriteBufferEmpty() { | 198 bool Channel::IsWriteBufferEmpty() { |
158 base::AutoLock locker(lock_); | 199 base::AutoLock locker(lock_); |
159 DCHECK(raw_channel_.get()); | 200 DCHECK(raw_channel_.get()); |
160 return raw_channel_->IsWriteBufferEmpty(); | 201 return raw_channel_->IsWriteBufferEmpty(); |
161 } | 202 } |
162 | 203 |
163 void Channel::DetachMessagePipeEndpoint(MessageInTransit::EndpointId local_id) { | 204 void Channel::DetachMessagePipeEndpoint( |
205 MessageInTransit::EndpointId local_id, | |
206 MessageInTransit::EndpointId remote_id) { | |
164 DCHECK_NE(local_id, MessageInTransit::kInvalidEndpointId); | 207 DCHECK_NE(local_id, MessageInTransit::kInvalidEndpointId); |
165 | 208 |
166 base::AutoLock locker_(lock_); | 209 bool should_send_remove_message = false; |
167 local_id_to_endpoint_info_map_.erase(local_id); | 210 { |
211 base::AutoLock locker_(lock_); | |
212 IdToEndpointInfoMap::iterator it = | |
213 local_id_to_endpoint_info_map_.find(local_id); | |
214 DCHECK(it != local_id_to_endpoint_info_map_.end()); | |
215 | |
216 switch (it->second.state) { | |
217 case EndpointInfo::STATE_NORMAL: | |
218 it->second.state = EndpointInfo::STATE_WAIT_REMOTE_REMOVE_ACK; | |
219 it->second.message_pipe = NULL; | |
220 should_send_remove_message = | |
221 (remote_id != MessageInTransit::kInvalidEndpointId); | |
222 break; | |
223 case EndpointInfo::STATE_WAIT_LOCAL_DETACH: | |
224 local_id_to_endpoint_info_map_.erase(it); | |
225 break; | |
226 case EndpointInfo::STATE_WAIT_REMOTE_REMOVE_ACK: | |
227 NOTREACHED(); | |
228 break; | |
229 case EndpointInfo::STATE_WAIT_LOCAL_DETACH_AND_REMOTE_REMOVE_ACK: | |
230 it->second.state = EndpointInfo::STATE_WAIT_REMOTE_REMOVE_ACK; | |
231 break; | |
232 } | |
233 } | |
234 if (!should_send_remove_message) | |
235 return; | |
236 | |
237 if (!SendControlMessage( | |
238 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint, | |
239 local_id, remote_id)) { | |
240 HandleLocalError(base::StringPrintf( | |
241 "Failed to send message to remove remote message pipe endpoint (local " | |
242 "ID %u, remote ID %u)", | |
243 static_cast<unsigned>(local_id), static_cast<unsigned>(remote_id))); | |
244 } | |
168 } | 245 } |
169 | 246 |
170 Channel::~Channel() { | 247 Channel::~Channel() { |
171 // The channel should have been shut down first. | 248 // The channel should have been shut down first. |
172 DCHECK(!raw_channel_.get()); | 249 DCHECK(!raw_channel_.get()); |
173 | |
174 DLOG_IF(WARNING, !local_id_to_endpoint_info_map_.empty()) | |
175 << "Destroying Channel with " << local_id_to_endpoint_info_map_.size() | |
176 << " endpoints still present"; | |
177 } | 250 } |
178 | 251 |
179 void Channel::OnReadMessage(const MessageInTransit::View& message_view) { | 252 void Channel::OnReadMessage(const MessageInTransit::View& message_view) { |
180 // Note: |ValidateReadMessage()| will call |HandleRemoteError()| if necessary. | 253 // Note: |ValidateReadMessage()| will call |HandleRemoteError()| if necessary. |
181 if (!ValidateReadMessage(message_view)) | 254 if (!ValidateReadMessage(message_view)) |
182 return; | 255 return; |
183 | 256 |
184 switch (message_view.type()) { | 257 switch (message_view.type()) { |
185 case MessageInTransit::kTypeMessagePipeEndpoint: | 258 case MessageInTransit::kTypeMessagePipeEndpoint: |
186 case MessageInTransit::kTypeMessagePipe: | 259 case MessageInTransit::kTypeMessagePipe: |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
242 // This is strongly indicative of some problem. However, it's not a fatal | 315 // This is strongly indicative of some problem. However, it's not a fatal |
243 // error, since it may indicate a bug (or hostile) remote process. Don't | 316 // error, since it may indicate a bug (or hostile) remote process. Don't |
244 // die even for Debug builds, since handling this properly needs to be | 317 // die even for Debug builds, since handling this properly needs to be |
245 // tested (TODO(vtl)). | 318 // tested (TODO(vtl)). |
246 DLOG(ERROR) << "This should not happen under normal operation."; | 319 DLOG(ERROR) << "This should not happen under normal operation."; |
247 return; | 320 return; |
248 } | 321 } |
249 endpoint_info = it->second; | 322 endpoint_info = it->second; |
250 } | 323 } |
251 | 324 |
325 // Ignore messages for zombie endpoints (not an error). | |
326 if (endpoint_info.state != EndpointInfo::STATE_NORMAL) { | |
327 DVLOG(2) << "Ignoring downstream message for zombie endpoint (local ID = " | |
328 << local_id << ", remote ID = " << message_view.source_id() << ")"; | |
329 return; | |
330 } | |
331 | |
252 // We need to duplicate the message, because |EnqueueMessage()| will take | 332 // We need to duplicate the message, because |EnqueueMessage()| will take |
253 // ownership of it. | 333 // ownership of it. |
254 scoped_ptr<MessageInTransit> message(new MessageInTransit(message_view)); | 334 scoped_ptr<MessageInTransit> message(new MessageInTransit(message_view)); |
255 message->DeserializeDispatchers(this); | 335 message->DeserializeDispatchers(this); |
256 MojoResult result = endpoint_info.message_pipe->EnqueueMessage( | 336 MojoResult result = endpoint_info.message_pipe->EnqueueMessage( |
257 MessagePipe::GetPeerPort(endpoint_info.port), message.Pass(), NULL); | 337 MessagePipe::GetPeerPort(endpoint_info.port), message.Pass(), NULL); |
258 if (result != MOJO_RESULT_OK) { | 338 if (result != MOJO_RESULT_OK) { |
259 // TODO(vtl): This might be a "non-error", e.g., if the destination endpoint | 339 // TODO(vtl): This might be a "non-error", e.g., if the destination endpoint |
260 // has been closed (in an unavoidable race). This might also be a "remote" | 340 // has been closed (in an unavoidable race). This might also be a "remote" |
261 // error, e.g., if the remote side is sending invalid control messages (to | 341 // error, e.g., if the remote side is sending invalid control messages (to |
262 // the message pipe). | 342 // the message pipe). |
263 HandleLocalError(base::StringPrintf( | 343 HandleLocalError(base::StringPrintf( |
264 "Failed to enqueue message to local destination ID %u (result %d)", | 344 "Failed to enqueue message to local ID %u (result %d)", |
265 static_cast<unsigned>(local_id), static_cast<int>(result))); | 345 static_cast<unsigned>(local_id), static_cast<int>(result))); |
266 return; | 346 return; |
267 } | 347 } |
268 } | 348 } |
269 | 349 |
270 void Channel::OnReadMessageForChannel( | 350 void Channel::OnReadMessageForChannel( |
271 const MessageInTransit::View& message_view) { | 351 const MessageInTransit::View& message_view) { |
272 DCHECK_EQ(message_view.type(), MessageInTransit::kTypeChannel); | 352 DCHECK_EQ(message_view.type(), MessageInTransit::kTypeChannel); |
273 | 353 |
274 switch (message_view.subtype()) { | 354 switch (message_view.subtype()) { |
275 case MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint: | 355 case MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint: |
276 // TODO(vtl): FIXME -- Error handling (also validation of | 356 DVLOG(2) << "Handling channel message to run message pipe (local ID " |
277 // source/destination IDs). | 357 << message_view.destination_id() << ", remote ID " |
278 DVLOG(2) << "Handling channel message to run message pipe (local ID = " | |
279 << message_view.destination_id() << ", remote ID = " | |
280 << message_view.source_id() << ")"; | 358 << message_view.source_id() << ")"; |
281 if (!RunMessagePipeEndpoint(message_view.destination_id(), | 359 if (!RunMessagePipeEndpoint(message_view.destination_id(), |
282 message_view.source_id())) | 360 message_view.source_id())) { |
283 HandleRemoteError("Received invalid channel run message pipe message"); | 361 HandleRemoteError( |
362 "Received invalid channel message to run message pipe"); | |
363 } | |
364 break; | |
365 case MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint: | |
366 DVLOG(2) << "Handling channel message to remove message pipe (local ID " | |
367 << message_view.destination_id() << ", remote ID " | |
368 << message_view.source_id() << ")"; | |
369 if (!RemoveMessagePipeEndpoint(message_view.destination_id(), | |
370 message_view.source_id())) { | |
371 HandleRemoteError( | |
372 "Received invalid channel message to remove message pipe"); | |
373 } | |
374 break; | |
375 case MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck: | |
376 DVLOG(2) << "Handling channel message to ack remove message pipe (local " | |
377 "ID " | |
378 << message_view.destination_id() << ", remote ID " | |
379 << message_view.source_id() << ")"; | |
380 if (!RemoveMessagePipeEndpoint(message_view.destination_id(), | |
381 message_view.source_id())) { | |
382 HandleRemoteError( | |
383 "Received invalid channel message to ack remove message pipe"); | |
384 } | |
284 break; | 385 break; |
285 default: | 386 default: |
286 HandleRemoteError("Received invalid channel message"); | 387 HandleRemoteError("Received invalid channel message"); |
287 NOTREACHED(); | 388 NOTREACHED(); |
288 break; | 389 break; |
289 } | 390 } |
290 } | 391 } |
291 | 392 |
393 bool Channel::RemoveMessagePipeEndpoint( | |
394 MessageInTransit::EndpointId local_id, | |
395 MessageInTransit::EndpointId remote_id) { | |
396 EndpointInfo endpoint_info; | |
397 { | |
398 base::AutoLock locker(lock_); | |
399 | |
400 IdToEndpointInfoMap::iterator it = | |
401 local_id_to_endpoint_info_map_.find(local_id); | |
402 if (it == local_id_to_endpoint_info_map_.end()) { | |
403 DVLOG(2) << "Remove message pipe error: not found"; | |
404 return false; | |
405 } | |
406 | |
407 // If it's waiting for the remove ack, just do it and return. | |
408 if (it->second.state == EndpointInfo::STATE_WAIT_REMOTE_REMOVE_ACK) { | |
409 local_id_to_endpoint_info_map_.erase(it); | |
410 return true; | |
411 } | |
412 | |
413 if (it->second.state != EndpointInfo::STATE_NORMAL) { | |
414 DVLOG(2) << "Remove message pipe error: wrong state"; | |
415 return false; | |
416 } | |
417 | |
418 it->second.state = EndpointInfo::STATE_WAIT_LOCAL_DETACH; | |
419 endpoint_info = it->second; | |
420 it->second.message_pipe = NULL; | |
421 } | |
422 | |
423 if (!SendControlMessage( | |
424 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck, | |
425 local_id, remote_id)) { | |
426 HandleLocalError(base::StringPrintf( | |
427 "Failed to send message to remove remote message pipe endpoint ack " | |
428 "(local ID %u, remote ID %u)", | |
429 static_cast<unsigned>(local_id), static_cast<unsigned>(remote_id))); | |
430 } | |
431 | |
432 endpoint_info.message_pipe->OnRemove(endpoint_info.port); | |
433 | |
434 return true; | |
435 } | |
436 | |
437 bool Channel::SendControlMessage(MessageInTransit::Subtype subtype, | |
438 MessageInTransit::EndpointId local_id, | |
439 MessageInTransit::EndpointId remote_id) { | |
440 DVLOG(2) << "Sending channel control message: subtype " << subtype | |
441 << ", local ID " << local_id << ", remote ID " << remote_id; | |
442 scoped_ptr<MessageInTransit> message(new MessageInTransit( | |
443 MessageInTransit::kTypeChannel, subtype, 0, 0, NULL)); | |
444 message->set_source_id(local_id); | |
445 message->set_destination_id(remote_id); | |
446 return raw_channel_->WriteMessage(message.Pass()); | |
447 } | |
448 | |
292 void Channel::HandleRemoteError(const base::StringPiece& error_message) { | 449 void Channel::HandleRemoteError(const base::StringPiece& error_message) { |
293 // TODO(vtl): Is this how we really want to handle this? Probably we want to | 450 // TODO(vtl): Is this how we really want to handle this? Probably we want to |
294 // terminate the connection, since it's spewing invalid stuff. | 451 // terminate the connection, since it's spewing invalid stuff. |
295 LOG(WARNING) << error_message; | 452 LOG(WARNING) << error_message; |
296 } | 453 } |
297 | 454 |
298 void Channel::HandleLocalError(const base::StringPiece& error_message) { | 455 void Channel::HandleLocalError(const base::StringPiece& error_message) { |
299 // TODO(vtl): Is this how we really want to handle this? | 456 // TODO(vtl): Is this how we really want to handle this? |
457 // Sometimes we'll want to propagate the error back to the message pipe | |
458 // (endpoint), and notify it that the remote is (effectively) closed. | |
459 // Sometimes we'll want to kill the channel (and notify all the endpoints that | |
460 // their remotes are dead. | |
300 LOG(WARNING) << error_message; | 461 LOG(WARNING) << error_message; |
301 } | 462 } |
302 | 463 |
303 } // namespace system | 464 } // namespace system |
304 } // namespace mojo | 465 } // namespace mojo |
OLD | NEW |