| 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 12 matching lines...) Expand all Loading... |
| 23 context.handler = channel; | 23 context.handler = channel; |
| 24 } | 24 } |
| 25 | 25 |
| 26 Channel::ChannelImpl::State::~State() { | 26 Channel::ChannelImpl::State::~State() { |
| 27 COMPILE_ASSERT(!offsetof(Channel::ChannelImpl::State, context), | 27 COMPILE_ASSERT(!offsetof(Channel::ChannelImpl::State, context), |
| 28 starts_with_io_context); | 28 starts_with_io_context); |
| 29 } | 29 } |
| 30 | 30 |
| 31 Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle &channel_handle, | 31 Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle &channel_handle, |
| 32 Mode mode, Listener* listener) | 32 Mode mode, Listener* listener) |
| 33 : ALLOW_THIS_IN_INITIALIZER_LIST(input_state_(this)), | 33 : ChannelReader(listener), |
| 34 ALLOW_THIS_IN_INITIALIZER_LIST(input_state_(this)), |
| 34 ALLOW_THIS_IN_INITIALIZER_LIST(output_state_(this)), | 35 ALLOW_THIS_IN_INITIALIZER_LIST(output_state_(this)), |
| 35 pipe_(INVALID_HANDLE_VALUE), | 36 pipe_(INVALID_HANDLE_VALUE), |
| 36 listener_(listener), | |
| 37 waiting_connect_(mode & MODE_SERVER_FLAG), | 37 waiting_connect_(mode & MODE_SERVER_FLAG), |
| 38 processing_incoming_(false), | 38 processing_incoming_(false), |
| 39 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | 39 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { |
| 40 CreatePipe(channel_handle, mode); | 40 CreatePipe(channel_handle, mode); |
| 41 } | 41 } |
| 42 | 42 |
| 43 Channel::ChannelImpl::~ChannelImpl() { | 43 Channel::ChannelImpl::~ChannelImpl() { |
| 44 Close(); | 44 Close(); |
| 45 } | 45 } |
| 46 | 46 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 | 106 |
| 107 | 107 |
| 108 Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData( | 108 Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData( |
| 109 char* buffer, | 109 char* buffer, |
| 110 int buffer_len, | 110 int buffer_len, |
| 111 int* /* bytes_read */) { | 111 int* /* bytes_read */) { |
| 112 if (INVALID_HANDLE_VALUE == pipe_) | 112 if (INVALID_HANDLE_VALUE == pipe_) |
| 113 return READ_FAILED; | 113 return READ_FAILED; |
| 114 | 114 |
| 115 DWORD bytes_read = 0; | 115 DWORD bytes_read = 0; |
| 116 BOOL ok = ReadFile(pipe_, input_buf_, Channel::kReadBufferSize, | 116 BOOL ok = ReadFile(pipe_, buffer, buffer_len, |
| 117 &bytes_read, &input_state_.context.overlapped); | 117 &bytes_read, &input_state_.context.overlapped); |
| 118 if (!ok) { | 118 if (!ok) { |
| 119 DWORD err = GetLastError(); | 119 DWORD err = GetLastError(); |
| 120 if (err == ERROR_IO_PENDING) { | 120 if (err == ERROR_IO_PENDING) { |
| 121 input_state_.is_pending = true; | 121 input_state_.is_pending = true; |
| 122 return READ_PENDING; | 122 return READ_PENDING; |
| 123 } | 123 } |
| 124 LOG(ERROR) << "pipe error: " << err; | 124 LOG(ERROR) << "pipe error: " << err; |
| 125 return READ_FAILED; | 125 return READ_FAILED; |
| 126 } | 126 } |
| 127 | 127 |
| 128 // We could return READ_SUCCEEDED here. But the way that this code is | 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 | 129 // structured we instead go back to the message loop. Our completion port |
| 130 // will be signalled even in the "synchronously completed" state. | 130 // will be signalled even in the "synchronously completed" state. |
| 131 // | 131 // |
| 132 // This allows us to potentially process some outgoing messages and | 132 // This allows us to potentially process some outgoing messages and |
| 133 // interleave other work on this thread when we're getting hammered with | 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 | 134 // input messages. Potentially, this could be tuned to be more efficient |
| 135 // with some testing. | 135 // with some testing. |
| 136 input_state_.is_pending = true; | 136 input_state_.is_pending = true; |
| 137 return READ_PENDING; | 137 return READ_PENDING; |
| 138 } | 138 } |
| 139 | 139 |
| 140 bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) { | 140 bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) { |
| 141 // We don't need to do anything here. |
| 141 return true; | 142 return true; |
| 142 } | 143 } |
| 143 | 144 |
| 144 void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { | 145 void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { |
| 145 // The hello message contains one parameter containing the PID. | 146 // The hello message contains one parameter containing the PID. |
| 146 listener_->OnChannelConnected(MessageIterator(msg).NextInt()); | 147 listener()->OnChannelConnected(MessageIterator(msg).NextInt()); |
| 147 } | 148 } |
| 148 | 149 |
| 149 bool Channel::ChannelImpl::DidEmptyInputBuffers() { | 150 bool Channel::ChannelImpl::DidEmptyInputBuffers() { |
| 151 // We don't need to do anything here. |
| 150 return true; | 152 return true; |
| 151 } | 153 } |
| 152 | 154 |
| 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 | |
| 210 // static | 155 // static |
| 211 const std::wstring Channel::ChannelImpl::PipeName( | 156 const std::wstring Channel::ChannelImpl::PipeName( |
| 212 const std::string& channel_id) { | 157 const std::string& channel_id) { |
| 213 std::string name("\\\\.\\pipe\\chrome."); | 158 std::string name("\\\\.\\pipe\\chrome."); |
| 214 return ASCIIToWide(name.append(channel_id)); | 159 return ASCIIToWide(name.append(channel_id)); |
| 215 } | 160 } |
| 216 | 161 |
| 217 bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle, | 162 bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle, |
| 218 Mode mode) { | 163 Mode mode) { |
| 219 DCHECK_EQ(INVALID_HANDLE_VALUE, pipe_); | 164 DCHECK_EQ(INVALID_HANDLE_VALUE, pipe_); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 // The pipe is being closed. | 298 // The pipe is being closed. |
| 354 return false; | 299 return false; |
| 355 default: | 300 default: |
| 356 NOTREACHED(); | 301 NOTREACHED(); |
| 357 return false; | 302 return false; |
| 358 } | 303 } |
| 359 | 304 |
| 360 return true; | 305 return true; |
| 361 } | 306 } |
| 362 | 307 |
| 363 bool Channel::ChannelImpl::ProcessIncomingMessages() { | |
| 364 while (true) { | |
| 365 int bytes_read = 0; | |
| 366 ReadState read_state = ReadData(input_buf_, Channel::kReadBufferSize, | |
| 367 &bytes_read); | |
| 368 if (read_state == READ_FAILED) | |
| 369 return false; | |
| 370 if (read_state == READ_PENDING) | |
| 371 return true; | |
| 372 DCHECK(bytes_read > 0); | |
| 373 if (!DispatchInputData(input_buf_, bytes_read)) | |
| 374 return false; | |
| 375 } | |
| 376 } | |
| 377 | |
| 378 bool Channel::ChannelImpl::ProcessOutgoingMessages( | 308 bool Channel::ChannelImpl::ProcessOutgoingMessages( |
| 379 MessageLoopForIO::IOContext* context, | 309 MessageLoopForIO::IOContext* context, |
| 380 DWORD bytes_written) { | 310 DWORD bytes_written) { |
| 381 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's | 311 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's |
| 382 // no connection? | 312 // no connection? |
| 383 DCHECK(thread_check_->CalledOnValidThread()); | 313 DCHECK(thread_check_->CalledOnValidThread()); |
| 384 | 314 |
| 385 if (output_state_.is_pending) { | 315 if (output_state_.is_pending) { |
| 386 DCHECK(context); | 316 DCHECK(context); |
| 387 output_state_.is_pending = false; | 317 output_state_.is_pending = false; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 // Request more data. | 398 // Request more data. |
| 469 if (ok) | 399 if (ok) |
| 470 ok = ProcessIncomingMessages(); | 400 ok = ProcessIncomingMessages(); |
| 471 } else { | 401 } else { |
| 472 DCHECK(context == &output_state_.context); | 402 DCHECK(context == &output_state_.context); |
| 473 ok = ProcessOutgoingMessages(context, bytes_transfered); | 403 ok = ProcessOutgoingMessages(context, bytes_transfered); |
| 474 } | 404 } |
| 475 if (!ok && INVALID_HANDLE_VALUE != pipe_) { | 405 if (!ok && INVALID_HANDLE_VALUE != pipe_) { |
| 476 // We don't want to re-enter Close(). | 406 // We don't want to re-enter Close(). |
| 477 Close(); | 407 Close(); |
| 478 listener_->OnChannelError(); | 408 listener()->OnChannelError(); |
| 479 } | 409 } |
| 480 } | 410 } |
| 481 | 411 |
| 482 //------------------------------------------------------------------------------ | 412 //------------------------------------------------------------------------------ |
| 483 // Channel's methods simply call through to ChannelImpl. | 413 // Channel's methods simply call through to ChannelImpl. |
| 484 Channel::Channel(const IPC::ChannelHandle &channel_handle, Mode mode, | 414 Channel::Channel(const IPC::ChannelHandle &channel_handle, Mode mode, |
| 485 Listener* listener) | 415 Listener* listener) |
| 486 : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) { | 416 : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) { |
| 487 } | 417 } |
| 488 | 418 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 505 bool Channel::Send(Message* message) { | 435 bool Channel::Send(Message* message) { |
| 506 return channel_impl_->Send(message); | 436 return channel_impl_->Send(message); |
| 507 } | 437 } |
| 508 | 438 |
| 509 // static | 439 // static |
| 510 bool Channel::IsNamedServerInitialized(const std::string& channel_id) { | 440 bool Channel::IsNamedServerInitialized(const std::string& channel_id) { |
| 511 return ChannelImpl::IsNamedServerInitialized(channel_id); | 441 return ChannelImpl::IsNamedServerInitialized(channel_id); |
| 512 } | 442 } |
| 513 | 443 |
| 514 } // namespace IPC | 444 } // namespace IPC |
| OLD | NEW |