Chromium Code Reviews| 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, but instead we go back to the message loop. Our completion | |
|
rvargas (doing something else)
2012/03/02 02:22:08
nit: this comment needs some rewording.
| |
| 130 // port 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); |
|
brettw
2012/03/01 21:24:16
This check moved to OnIOCompleted.
| |
| 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) { | |
|
brettw
2012/03/01 21:24:16
This code moved to ReadData
| |
| 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; | |
|
brettw
2012/03/01 21:24:16
The rest of this loop moved to DispatchInputData
| |
| 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; | |
|
rvargas (doing something else)
2012/03/02 02:22:08
It may be better to move this block to AsyncReadCo
brettw
2012/03/02 05:31:18
I was going to make AsyncReadComplete cross-platfo
rvargas (doing something else)
2012/03/02 18:44:17
OK.
Does that mean that AsyncReadComplete is goin
| |
| 460 if (!bytes_transfered) | |
| 461 ok = false; | |
| 462 else | |
| 463 ok = AsyncReadComplete(bytes_transfered); | |
|
brettw
2012/03/01 21:24:16
ProcessIncomingMessages doesn't need any parameter
| |
| 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 |