OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ipc/ipc_channel_win.h" | 5 #include "ipc/ipc_channel_win.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 | 8 |
9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 // static | 97 // static |
98 bool Channel::ChannelImpl::IsNamedServerInitialized( | 98 bool Channel::ChannelImpl::IsNamedServerInitialized( |
99 const std::string& channel_id) { | 99 const std::string& channel_id) { |
100 if (WaitNamedPipe(PipeName(channel_id).c_str(), 1)) | 100 if (WaitNamedPipe(PipeName(channel_id).c_str(), 1)) |
101 return true; | 101 return true; |
102 // If ERROR_SEM_TIMEOUT occurred, the pipe exists but is handling another | 102 // If ERROR_SEM_TIMEOUT occurred, the pipe exists but is handling another |
103 // connection. | 103 // connection. |
104 return GetLastError() == ERROR_SEM_TIMEOUT; | 104 return GetLastError() == ERROR_SEM_TIMEOUT; |
105 } | 105 } |
106 | 106 |
| 107 |
| 108 Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData( |
| 109 char* buffer, |
| 110 int buffer_len, |
| 111 int* /* bytes_read */) { |
| 112 if (INVALID_HANDLE_VALUE == pipe_) |
| 113 return READ_FAILED; |
| 114 |
| 115 DWORD bytes_read = 0; |
| 116 BOOL ok = ReadFile(pipe_, input_buf_, Channel::kReadBufferSize, |
| 117 &bytes_read, &input_state_.context.overlapped); |
| 118 if (!ok) { |
| 119 DWORD err = GetLastError(); |
| 120 if (err == ERROR_IO_PENDING) { |
| 121 input_state_.is_pending = true; |
| 122 return READ_PENDING; |
| 123 } |
| 124 LOG(ERROR) << "pipe error: " << err; |
| 125 return READ_FAILED; |
| 126 } |
| 127 |
| 128 // We could return READ_SUCCEEDED here. But the way that this code is |
| 129 // structured we instead go back to the message loop. Our completion port |
| 130 // will be signalled even in the "synchronously completed" state. |
| 131 // |
| 132 // This allows us to potentially process some outgoing messages and |
| 133 // interleave other work on this thread when we're getting hammered with |
| 134 // input messages. Potentially, this could be tuned to be more efficient |
| 135 // with some testing. |
| 136 input_state_.is_pending = true; |
| 137 return READ_PENDING; |
| 138 } |
| 139 |
| 140 bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) { |
| 141 return true; |
| 142 } |
| 143 |
| 144 void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { |
| 145 // The hello message contains one parameter containing the PID. |
| 146 listener_->OnChannelConnected(MessageIterator(msg).NextInt()); |
| 147 } |
| 148 |
| 149 bool Channel::ChannelImpl::DidEmptyInputBuffers() { |
| 150 return true; |
| 151 } |
| 152 |
| 153 bool Channel::ChannelImpl::DispatchInputData(const char* input_data, |
| 154 int input_data_len) { |
| 155 const char* p; |
| 156 const char* end; |
| 157 |
| 158 // Possibly combine with the overflow buffer to make a larger buffer. |
| 159 if (input_overflow_buf_.empty()) { |
| 160 p = input_data; |
| 161 end = input_data + input_data_len; |
| 162 } else { |
| 163 if (input_overflow_buf_.size() > |
| 164 kMaximumMessageSize - input_data_len) { |
| 165 input_overflow_buf_.clear(); |
| 166 LOG(ERROR) << "IPC message is too big"; |
| 167 return false; |
| 168 } |
| 169 input_overflow_buf_.append(input_data, input_data_len); |
| 170 p = input_overflow_buf_.data(); |
| 171 end = p + input_overflow_buf_.size(); |
| 172 } |
| 173 |
| 174 // Dispatch all complete messages in the data buffer. |
| 175 while (p < end) { |
| 176 const char* message_tail = Message::FindNext(p, end); |
| 177 if (message_tail) { |
| 178 int len = static_cast<int>(message_tail - p); |
| 179 Message m(p, len); |
| 180 if (!WillDispatchInputMessage(&m)) |
| 181 return false; |
| 182 |
| 183 if (IsHelloMessage(m)) |
| 184 HandleHelloMessage(m); |
| 185 else |
| 186 listener_->OnMessageReceived(m); |
| 187 p = message_tail; |
| 188 } else { |
| 189 // Last message is partial. |
| 190 break; |
| 191 } |
| 192 } |
| 193 |
| 194 // Save any partial data in the overflow buffer. |
| 195 input_overflow_buf_.assign(p, end - p); |
| 196 |
| 197 if (input_overflow_buf_.empty() && !DidEmptyInputBuffers()) |
| 198 return false; |
| 199 return true; |
| 200 } |
| 201 |
| 202 bool Channel::ChannelImpl::IsHelloMessage(const Message& m) const { |
| 203 return m.routing_id() == MSG_ROUTING_NONE && m.type() == HELLO_MESSAGE_TYPE; |
| 204 } |
| 205 |
| 206 bool Channel::ChannelImpl::AsyncReadComplete(int bytes_read) { |
| 207 return DispatchInputData(input_buf_, bytes_read); |
| 208 } |
| 209 |
107 // static | 210 // static |
108 const std::wstring Channel::ChannelImpl::PipeName( | 211 const std::wstring Channel::ChannelImpl::PipeName( |
109 const std::string& channel_id) { | 212 const std::string& channel_id) { |
110 std::string name("\\\\.\\pipe\\chrome."); | 213 std::string name("\\\\.\\pipe\\chrome."); |
111 return ASCIIToWide(name.append(channel_id)); | 214 return ASCIIToWide(name.append(channel_id)); |
112 } | 215 } |
113 | 216 |
114 bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle, | 217 bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle, |
115 Mode mode) { | 218 Mode mode) { |
116 DCHECK_EQ(INVALID_HANDLE_VALUE, pipe_); | 219 DCHECK_EQ(INVALID_HANDLE_VALUE, pipe_); |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 // The pipe is being closed. | 353 // The pipe is being closed. |
251 return false; | 354 return false; |
252 default: | 355 default: |
253 NOTREACHED(); | 356 NOTREACHED(); |
254 return false; | 357 return false; |
255 } | 358 } |
256 | 359 |
257 return true; | 360 return true; |
258 } | 361 } |
259 | 362 |
260 bool Channel::ChannelImpl::ProcessIncomingMessages( | 363 bool Channel::ChannelImpl::ProcessIncomingMessages() { |
261 MessageLoopForIO::IOContext* context, | 364 while (true) { |
262 DWORD bytes_read) { | 365 int bytes_read = 0; |
263 DCHECK(thread_check_->CalledOnValidThread()); | 366 ReadState read_state = ReadData(input_buf_, Channel::kReadBufferSize, |
264 if (input_state_.is_pending) { | 367 &bytes_read); |
265 input_state_.is_pending = false; | 368 if (read_state == READ_FAILED) |
266 DCHECK(context); | |
267 | |
268 if (!context || !bytes_read) | |
269 return false; | 369 return false; |
270 } else { | 370 if (read_state == READ_PENDING) |
271 // This happens at channel initialization. | 371 return true; |
272 DCHECK(!bytes_read && context == &input_state_.context); | 372 DCHECK(bytes_read > 0); |
| 373 if (!DispatchInputData(input_buf_, bytes_read)) |
| 374 return false; |
273 } | 375 } |
274 | |
275 for (;;) { | |
276 if (bytes_read == 0) { | |
277 if (INVALID_HANDLE_VALUE == pipe_) | |
278 return false; | |
279 | |
280 // Read from pipe... | |
281 BOOL ok = ReadFile(pipe_, | |
282 input_buf_, | |
283 Channel::kReadBufferSize, | |
284 &bytes_read, | |
285 &input_state_.context.overlapped); | |
286 if (!ok) { | |
287 DWORD err = GetLastError(); | |
288 if (err == ERROR_IO_PENDING) { | |
289 input_state_.is_pending = true; | |
290 return true; | |
291 } | |
292 LOG(ERROR) << "pipe error: " << err; | |
293 return false; | |
294 } | |
295 input_state_.is_pending = true; | |
296 return true; | |
297 } | |
298 DCHECK(bytes_read); | |
299 | |
300 // Process messages from input buffer. | |
301 | |
302 const char* p, *end; | |
303 if (input_overflow_buf_.empty()) { | |
304 p = input_buf_; | |
305 end = p + bytes_read; | |
306 } else { | |
307 if (input_overflow_buf_.size() > (kMaximumMessageSize - bytes_read)) { | |
308 input_overflow_buf_.clear(); | |
309 LOG(ERROR) << "IPC message is too big"; | |
310 return false; | |
311 } | |
312 input_overflow_buf_.append(input_buf_, bytes_read); | |
313 p = input_overflow_buf_.data(); | |
314 end = p + input_overflow_buf_.size(); | |
315 } | |
316 | |
317 while (p < end) { | |
318 const char* message_tail = Message::FindNext(p, end); | |
319 if (message_tail) { | |
320 int len = static_cast<int>(message_tail - p); | |
321 const Message m(p, len); | |
322 DVLOG(2) << "received message on channel @" << this | |
323 << " with type " << m.type(); | |
324 if (m.routing_id() == MSG_ROUTING_NONE && | |
325 m.type() == HELLO_MESSAGE_TYPE) { | |
326 // The Hello message contains only the process id. | |
327 listener_->OnChannelConnected(MessageIterator(m).NextInt()); | |
328 } else { | |
329 listener_->OnMessageReceived(m); | |
330 } | |
331 p = message_tail; | |
332 } else { | |
333 // Last message is partial. | |
334 break; | |
335 } | |
336 } | |
337 input_overflow_buf_.assign(p, end - p); | |
338 | |
339 bytes_read = 0; // Get more data. | |
340 } | |
341 | |
342 return true; | |
343 } | 376 } |
344 | 377 |
345 bool Channel::ChannelImpl::ProcessOutgoingMessages( | 378 bool Channel::ChannelImpl::ProcessOutgoingMessages( |
346 MessageLoopForIO::IOContext* context, | 379 MessageLoopForIO::IOContext* context, |
347 DWORD bytes_written) { | 380 DWORD bytes_written) { |
348 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's | 381 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's |
349 // no connection? | 382 // no connection? |
350 DCHECK(thread_check_->CalledOnValidThread()); | 383 DCHECK(thread_check_->CalledOnValidThread()); |
351 | 384 |
352 if (output_state_.is_pending) { | 385 if (output_state_.is_pending) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 } | 426 } |
394 | 427 |
395 DVLOG(2) << "sent message @" << m << " on channel @" << this | 428 DVLOG(2) << "sent message @" << m << " on channel @" << this |
396 << " with type " << m->type(); | 429 << " with type " << m->type(); |
397 | 430 |
398 output_state_.is_pending = true; | 431 output_state_.is_pending = true; |
399 return true; | 432 return true; |
400 } | 433 } |
401 | 434 |
402 void Channel::ChannelImpl::OnIOCompleted(MessageLoopForIO::IOContext* context, | 435 void Channel::ChannelImpl::OnIOCompleted(MessageLoopForIO::IOContext* context, |
403 DWORD bytes_transfered, DWORD error) { | 436 DWORD bytes_transfered, |
404 bool ok; | 437 DWORD error) { |
| 438 bool ok = true; |
405 DCHECK(thread_check_->CalledOnValidThread()); | 439 DCHECK(thread_check_->CalledOnValidThread()); |
406 if (context == &input_state_.context) { | 440 if (context == &input_state_.context) { |
407 if (waiting_connect_) { | 441 if (waiting_connect_) { |
408 if (!ProcessConnection()) | 442 if (!ProcessConnection()) |
409 return; | 443 return; |
410 // We may have some messages queued up to send... | 444 // We may have some messages queued up to send... |
411 if (!output_queue_.empty() && !output_state_.is_pending) | 445 if (!output_queue_.empty() && !output_state_.is_pending) |
412 ProcessOutgoingMessages(NULL, 0); | 446 ProcessOutgoingMessages(NULL, 0); |
413 if (input_state_.is_pending) | 447 if (input_state_.is_pending) |
414 return; | 448 return; |
415 // else, fall-through and look for incoming messages... | 449 // else, fall-through and look for incoming messages... |
416 } | 450 } |
417 // we don't support recursion through OnMessageReceived yet! | 451 |
| 452 // We don't support recursion through OnMessageReceived yet! |
418 DCHECK(!processing_incoming_); | 453 DCHECK(!processing_incoming_); |
419 AutoReset<bool> auto_reset_processing_incoming(&processing_incoming_, true); | 454 AutoReset<bool> auto_reset_processing_incoming(&processing_incoming_, true); |
420 ok = ProcessIncomingMessages(context, bytes_transfered); | 455 |
| 456 // Process the new data. |
| 457 if (input_state_.is_pending) { |
| 458 // This is the normal case for everything except the initialization step. |
| 459 input_state_.is_pending = false; |
| 460 if (!bytes_transfered) |
| 461 ok = false; |
| 462 else |
| 463 ok = AsyncReadComplete(bytes_transfered); |
| 464 } else { |
| 465 DCHECK(!bytes_transfered); |
| 466 } |
| 467 |
| 468 // Request more data. |
| 469 if (ok) |
| 470 ok = ProcessIncomingMessages(); |
421 } else { | 471 } else { |
422 DCHECK(context == &output_state_.context); | 472 DCHECK(context == &output_state_.context); |
423 ok = ProcessOutgoingMessages(context, bytes_transfered); | 473 ok = ProcessOutgoingMessages(context, bytes_transfered); |
424 } | 474 } |
425 if (!ok && INVALID_HANDLE_VALUE != pipe_) { | 475 if (!ok && INVALID_HANDLE_VALUE != pipe_) { |
426 // We don't want to re-enter Close(). | 476 // We don't want to re-enter Close(). |
427 Close(); | 477 Close(); |
428 listener_->OnChannelError(); | 478 listener_->OnChannelError(); |
429 } | 479 } |
430 } | 480 } |
(...skipping 24 matching lines...) Expand all Loading... |
455 bool Channel::Send(Message* message) { | 505 bool Channel::Send(Message* message) { |
456 return channel_impl_->Send(message); | 506 return channel_impl_->Send(message); |
457 } | 507 } |
458 | 508 |
459 // static | 509 // static |
460 bool Channel::IsNamedServerInitialized(const std::string& channel_id) { | 510 bool Channel::IsNamedServerInitialized(const std::string& channel_id) { |
461 return ChannelImpl::IsNamedServerInitialized(channel_id); | 511 return ChannelImpl::IsNamedServerInitialized(channel_id); |
462 } | 512 } |
463 | 513 |
464 } // namespace IPC | 514 } // namespace IPC |
OLD | NEW |