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)"; |
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 #if DCHECK_IS_ON |
| 174 { |
| 175 base::AutoLock locker(lock_); |
| 176 DCHECK(local_id_to_endpoint_info_map_.find(local_id) != |
| 177 local_id_to_endpoint_info_map_.end()); |
| 178 } |
| 179 #endif |
128 | 180 |
129 DCHECK(local_id_to_endpoint_info_map_.find(local_id) != | 181 if (!SendControlMessage( |
130 local_id_to_endpoint_info_map_.end()); | 182 MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint, |
131 | 183 local_id, remote_id)) { |
132 scoped_ptr<MessageInTransit> message(new MessageInTransit( | 184 HandleLocalError(base::StringPrintf( |
133 MessageInTransit::kTypeChannel, | 185 "Failed to send message to run remote message pipe endpoint (local ID " |
134 MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint, | 186 "%u, remote ID %u)", |
135 0, 0, NULL)); | 187 static_cast<unsigned>(local_id), static_cast<unsigned>(remote_id))); |
136 message->set_source_id(local_id); | |
137 message->set_destination_id(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 } | 188 } |
143 } | 189 } |
144 | 190 |
145 bool Channel::WriteMessage(scoped_ptr<MessageInTransit> message) { | 191 bool Channel::WriteMessage(scoped_ptr<MessageInTransit> message) { |
146 base::AutoLock locker(lock_); | 192 base::AutoLock locker(lock_); |
147 if (!raw_channel_.get()) { | 193 if (!raw_channel_.get()) { |
148 // TODO(vtl): I think this is probably not an error condition, but I should | 194 // TODO(vtl): I think this is probably not an error condition, but I should |
149 // think about it (and the shutdown sequence) more carefully. | 195 // think about it (and the shutdown sequence) more carefully. |
150 LOG(WARNING) << "WriteMessage() after shutdown"; | 196 LOG(WARNING) << "WriteMessage() after shutdown"; |
151 return false; | 197 return false; |
152 } | 198 } |
153 | 199 |
154 return raw_channel_->WriteMessage(message.Pass()); | 200 return raw_channel_->WriteMessage(message.Pass()); |
155 } | 201 } |
156 | 202 |
157 bool Channel::IsWriteBufferEmpty() { | 203 bool Channel::IsWriteBufferEmpty() { |
158 base::AutoLock locker(lock_); | 204 base::AutoLock locker(lock_); |
159 DCHECK(raw_channel_.get()); | 205 DCHECK(raw_channel_.get()); |
160 return raw_channel_->IsWriteBufferEmpty(); | 206 return raw_channel_->IsWriteBufferEmpty(); |
161 } | 207 } |
162 | 208 |
163 void Channel::DetachMessagePipeEndpoint(MessageInTransit::EndpointId local_id) { | 209 void Channel::DetachMessagePipeEndpoint( |
| 210 MessageInTransit::EndpointId local_id, |
| 211 MessageInTransit::EndpointId remote_id) { |
164 DCHECK_NE(local_id, MessageInTransit::kInvalidEndpointId); | 212 DCHECK_NE(local_id, MessageInTransit::kInvalidEndpointId); |
165 | 213 |
166 base::AutoLock locker_(lock_); | 214 bool should_send_remove_message = false; |
167 local_id_to_endpoint_info_map_.erase(local_id); | 215 { |
| 216 base::AutoLock locker_(lock_); |
| 217 IdToEndpointInfoMap::iterator it = |
| 218 local_id_to_endpoint_info_map_.find(local_id); |
| 219 DCHECK(it != local_id_to_endpoint_info_map_.end()); |
| 220 |
| 221 switch (it->second.state) { |
| 222 case EndpointInfo::STATE_NORMAL: |
| 223 it->second.state = EndpointInfo::STATE_WAIT_REMOTE_REMOVE_ACK; |
| 224 it->second.message_pipe = NULL; |
| 225 should_send_remove_message = |
| 226 (remote_id != MessageInTransit::kInvalidEndpointId); |
| 227 break; |
| 228 case EndpointInfo::STATE_WAIT_LOCAL_DETACH: |
| 229 local_id_to_endpoint_info_map_.erase(it); |
| 230 break; |
| 231 case EndpointInfo::STATE_WAIT_REMOTE_REMOVE_ACK: |
| 232 NOTREACHED(); |
| 233 break; |
| 234 case EndpointInfo::STATE_WAIT_LOCAL_DETACH_AND_REMOTE_REMOVE_ACK: |
| 235 it->second.state = EndpointInfo::STATE_WAIT_REMOTE_REMOVE_ACK; |
| 236 break; |
| 237 } |
| 238 } |
| 239 if (!should_send_remove_message) |
| 240 return; |
| 241 |
| 242 if (!SendControlMessage( |
| 243 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint, |
| 244 local_id, remote_id)) { |
| 245 HandleLocalError(base::StringPrintf( |
| 246 "Failed to send message to remove remote message pipe endpoint (local " |
| 247 "ID %u, remote ID %u)", |
| 248 static_cast<unsigned>(local_id), static_cast<unsigned>(remote_id))); |
| 249 } |
168 } | 250 } |
169 | 251 |
170 Channel::~Channel() { | 252 Channel::~Channel() { |
171 // The channel should have been shut down first. | 253 // The channel should have been shut down first. |
172 DCHECK(!raw_channel_.get()); | 254 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 } | 255 } |
178 | 256 |
179 void Channel::OnReadMessage(const MessageInTransit::View& message_view) { | 257 void Channel::OnReadMessage(const MessageInTransit::View& message_view) { |
180 // Note: |ValidateReadMessage()| will call |HandleRemoteError()| if necessary. | 258 // Note: |ValidateReadMessage()| will call |HandleRemoteError()| if necessary. |
181 if (!ValidateReadMessage(message_view)) | 259 if (!ValidateReadMessage(message_view)) |
182 return; | 260 return; |
183 | 261 |
184 switch (message_view.type()) { | 262 switch (message_view.type()) { |
185 case MessageInTransit::kTypeMessagePipeEndpoint: | 263 case MessageInTransit::kTypeMessagePipeEndpoint: |
186 case MessageInTransit::kTypeMessagePipe: | 264 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 | 320 // 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 | 321 // 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 | 322 // die even for Debug builds, since handling this properly needs to be |
245 // tested (TODO(vtl)). | 323 // tested (TODO(vtl)). |
246 DLOG(ERROR) << "This should not happen under normal operation."; | 324 DLOG(ERROR) << "This should not happen under normal operation."; |
247 return; | 325 return; |
248 } | 326 } |
249 endpoint_info = it->second; | 327 endpoint_info = it->second; |
250 } | 328 } |
251 | 329 |
| 330 // Ignore messages for zombie endpoints (not an error). |
| 331 if (endpoint_info.state != EndpointInfo::STATE_NORMAL) { |
| 332 DVLOG(2) << "Ignoring downstream message for zombie endpoint (local ID = " |
| 333 << local_id << ", remote ID = " << message_view.source_id() << ")"; |
| 334 return; |
| 335 } |
| 336 |
252 // We need to duplicate the message, because |EnqueueMessage()| will take | 337 // We need to duplicate the message, because |EnqueueMessage()| will take |
253 // ownership of it. | 338 // ownership of it. |
254 scoped_ptr<MessageInTransit> message(new MessageInTransit(message_view)); | 339 scoped_ptr<MessageInTransit> message(new MessageInTransit(message_view)); |
255 message->DeserializeDispatchers(this); | 340 message->DeserializeDispatchers(this); |
256 MojoResult result = endpoint_info.message_pipe->EnqueueMessage( | 341 MojoResult result = endpoint_info.message_pipe->EnqueueMessage( |
257 MessagePipe::GetPeerPort(endpoint_info.port), message.Pass(), NULL); | 342 MessagePipe::GetPeerPort(endpoint_info.port), message.Pass(), NULL); |
258 if (result != MOJO_RESULT_OK) { | 343 if (result != MOJO_RESULT_OK) { |
259 // TODO(vtl): This might be a "non-error", e.g., if the destination endpoint | 344 // 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" | 345 // 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 | 346 // error, e.g., if the remote side is sending invalid control messages (to |
262 // the message pipe). | 347 // the message pipe). |
263 HandleLocalError(base::StringPrintf( | 348 HandleLocalError(base::StringPrintf( |
264 "Failed to enqueue message to local destination ID %u (result %d)", | 349 "Failed to enqueue message to local ID %u (result %d)", |
265 static_cast<unsigned>(local_id), static_cast<int>(result))); | 350 static_cast<unsigned>(local_id), static_cast<int>(result))); |
266 return; | 351 return; |
267 } | 352 } |
268 } | 353 } |
269 | 354 |
270 void Channel::OnReadMessageForChannel( | 355 void Channel::OnReadMessageForChannel( |
271 const MessageInTransit::View& message_view) { | 356 const MessageInTransit::View& message_view) { |
272 DCHECK_EQ(message_view.type(), MessageInTransit::kTypeChannel); | 357 DCHECK_EQ(message_view.type(), MessageInTransit::kTypeChannel); |
273 | 358 |
274 switch (message_view.subtype()) { | 359 switch (message_view.subtype()) { |
275 case MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint: | 360 case MessageInTransit::kSubtypeChannelRunMessagePipeEndpoint: |
276 // TODO(vtl): FIXME -- Error handling (also validation of | 361 DVLOG(2) << "Handling channel message to run message pipe (local ID " |
277 // source/destination IDs). | 362 << 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() << ")"; | 363 << message_view.source_id() << ")"; |
281 if (!RunMessagePipeEndpoint(message_view.destination_id(), | 364 if (!RunMessagePipeEndpoint(message_view.destination_id(), |
282 message_view.source_id())) | 365 message_view.source_id())) { |
283 HandleRemoteError("Received invalid channel run message pipe message"); | 366 HandleRemoteError( |
| 367 "Received invalid channel message to run message pipe"); |
| 368 } |
| 369 break; |
| 370 case MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint: |
| 371 DVLOG(2) << "Handling channel message to remove message pipe (local ID " |
| 372 << message_view.destination_id() << ", remote ID " |
| 373 << message_view.source_id() << ")"; |
| 374 if (!RemoveMessagePipeEndpoint(message_view.destination_id(), |
| 375 message_view.source_id())) { |
| 376 HandleRemoteError( |
| 377 "Received invalid channel message to remove message pipe"); |
| 378 } |
| 379 break; |
| 380 case MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck: |
| 381 DVLOG(2) << "Handling channel message to ack remove message pipe (local " |
| 382 "ID " |
| 383 << message_view.destination_id() << ", remote ID " |
| 384 << message_view.source_id() << ")"; |
| 385 if (!RemoveMessagePipeEndpoint(message_view.destination_id(), |
| 386 message_view.source_id())) { |
| 387 HandleRemoteError( |
| 388 "Received invalid channel message to ack remove message pipe"); |
| 389 } |
284 break; | 390 break; |
285 default: | 391 default: |
286 HandleRemoteError("Received invalid channel message"); | 392 HandleRemoteError("Received invalid channel message"); |
287 NOTREACHED(); | 393 NOTREACHED(); |
288 break; | 394 break; |
289 } | 395 } |
290 } | 396 } |
291 | 397 |
| 398 bool Channel::RemoveMessagePipeEndpoint( |
| 399 MessageInTransit::EndpointId local_id, |
| 400 MessageInTransit::EndpointId remote_id) { |
| 401 EndpointInfo endpoint_info; |
| 402 { |
| 403 base::AutoLock locker(lock_); |
| 404 |
| 405 IdToEndpointInfoMap::iterator it = |
| 406 local_id_to_endpoint_info_map_.find(local_id); |
| 407 if (it == local_id_to_endpoint_info_map_.end()) { |
| 408 DVLOG(2) << "Remove message pipe error: not found"; |
| 409 return false; |
| 410 } |
| 411 |
| 412 // If it's waiting for the remove ack, just do it and return. |
| 413 if (it->second.state == EndpointInfo::STATE_WAIT_REMOTE_REMOVE_ACK) { |
| 414 local_id_to_endpoint_info_map_.erase(it); |
| 415 return true; |
| 416 } |
| 417 |
| 418 if (it->second.state != EndpointInfo::STATE_NORMAL) { |
| 419 DVLOG(2) << "Remove message pipe error: wrong state"; |
| 420 return false; |
| 421 } |
| 422 |
| 423 it->second.state = EndpointInfo::STATE_WAIT_LOCAL_DETACH; |
| 424 endpoint_info = it->second; |
| 425 it->second.message_pipe = NULL; |
| 426 } |
| 427 |
| 428 if (!SendControlMessage( |
| 429 MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck, |
| 430 local_id, remote_id)) { |
| 431 HandleLocalError(base::StringPrintf( |
| 432 "Failed to send message to remove remote message pipe endpoint ack " |
| 433 "(local ID %u, remote ID %u)", |
| 434 static_cast<unsigned>(local_id), static_cast<unsigned>(remote_id))); |
| 435 } |
| 436 |
| 437 endpoint_info.message_pipe->OnRemove(endpoint_info.port); |
| 438 |
| 439 return true; |
| 440 } |
| 441 |
| 442 bool Channel::SendControlMessage(MessageInTransit::Subtype subtype, |
| 443 MessageInTransit::EndpointId local_id, |
| 444 MessageInTransit::EndpointId remote_id) { |
| 445 DVLOG(2) << "Sending channel control message: subtype " << subtype |
| 446 << ", local ID " << local_id << ", remote ID " << remote_id; |
| 447 scoped_ptr<MessageInTransit> message(new MessageInTransit( |
| 448 MessageInTransit::kTypeChannel, subtype, 0, 0, NULL)); |
| 449 message->set_source_id(local_id); |
| 450 message->set_destination_id(remote_id); |
| 451 return WriteMessage(message.Pass()); |
| 452 } |
| 453 |
292 void Channel::HandleRemoteError(const base::StringPiece& error_message) { | 454 void Channel::HandleRemoteError(const base::StringPiece& error_message) { |
293 // TODO(vtl): Is this how we really want to handle this? Probably we want to | 455 // 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. | 456 // terminate the connection, since it's spewing invalid stuff. |
295 LOG(WARNING) << error_message; | 457 LOG(WARNING) << error_message; |
296 } | 458 } |
297 | 459 |
298 void Channel::HandleLocalError(const base::StringPiece& error_message) { | 460 void Channel::HandleLocalError(const base::StringPiece& error_message) { |
299 // TODO(vtl): Is this how we really want to handle this? | 461 // TODO(vtl): Is this how we really want to handle this? |
| 462 // Sometimes we'll want to propagate the error back to the message pipe |
| 463 // (endpoint), and notify it that the remote is (effectively) closed. |
| 464 // Sometimes we'll want to kill the channel (and notify all the endpoints that |
| 465 // their remotes are dead. |
300 LOG(WARNING) << error_message; | 466 LOG(WARNING) << error_message; |
301 } | 467 } |
302 | 468 |
303 } // namespace system | 469 } // namespace system |
304 } // namespace mojo | 470 } // namespace mojo |
OLD | NEW |