| OLD | NEW |
| 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2008 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 "chrome/common/ipc_channel_posix.h" | 5 #include "chrome/common/ipc_channel_posix.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <stddef.h> | 9 #include <stddef.h> |
| 10 #include <sys/types.h> | 10 #include <sys/types.h> |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 | 21 |
| 22 #include "base/command_line.h" | 22 #include "base/command_line.h" |
| 23 #include "base/lock.h" | 23 #include "base/lock.h" |
| 24 #include "base/logging.h" | 24 #include "base/logging.h" |
| 25 #include "base/process_util.h" | 25 #include "base/process_util.h" |
| 26 #include "base/scoped_ptr.h" | 26 #include "base/scoped_ptr.h" |
| 27 #include "base/string_util.h" | 27 #include "base/string_util.h" |
| 28 #include "base/singleton.h" | 28 #include "base/singleton.h" |
| 29 #include "chrome/common/chrome_counters.h" | 29 #include "chrome/common/chrome_counters.h" |
| 30 #include "chrome/common/chrome_switches.h" | 30 #include "chrome/common/chrome_switches.h" |
| 31 #include "chrome/common/file_descriptor_posix.h" |
| 31 #include "chrome/common/ipc_message_utils.h" | 32 #include "chrome/common/ipc_message_utils.h" |
| 32 | 33 |
| 33 namespace IPC { | 34 namespace IPC { |
| 34 | 35 |
| 35 //------------------------------------------------------------------------------ | 36 //------------------------------------------------------------------------------ |
| 36 namespace { | 37 namespace { |
| 37 | 38 |
| 38 // When running as a browser, we install the client socket in a specific file | 39 // When running as a browser, we install the client socket in a specific file |
| 39 // descriptor number (@kClientChannelFd). However, we also have to support the | 40 // descriptor number (@kClientChannelFd). However, we also have to support the |
| 40 // case where we are running unittests in the same process. | 41 // case where we are running unittests in the same process. |
| (...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 } | 351 } |
| 351 | 352 |
| 352 if (!waiting_connect_) | 353 if (!waiting_connect_) |
| 353 return ProcessOutgoingMessages(); | 354 return ProcessOutgoingMessages(); |
| 354 return true; | 355 return true; |
| 355 } | 356 } |
| 356 | 357 |
| 357 bool Channel::ChannelImpl::ProcessIncomingMessages() { | 358 bool Channel::ChannelImpl::ProcessIncomingMessages() { |
| 358 ssize_t bytes_read = 0; | 359 ssize_t bytes_read = 0; |
| 359 | 360 |
| 361 struct msghdr msg = {0}; |
| 362 struct iovec iov = {input_buf_, Channel::kReadBufferSize}; |
| 363 |
| 364 msg.msg_iov = &iov; |
| 365 msg.msg_iovlen = 1; |
| 366 msg.msg_control = input_cmsg_buf_; |
| 367 msg.msg_controllen = sizeof(input_cmsg_buf_); |
| 368 |
| 360 for (;;) { | 369 for (;;) { |
| 361 if (bytes_read == 0) { | 370 if (bytes_read == 0) { |
| 362 if (pipe_ == -1) | 371 if (pipe_ == -1) |
| 363 return false; | 372 return false; |
| 364 | 373 |
| 365 // Read from pipe. | 374 // Read from pipe. |
| 366 // recv() returns 0 if the connection has closed or EAGAIN if no data is | 375 // recvmsg() returns 0 if the connection has closed or EAGAIN if no data |
| 367 // waiting on the pipe. | 376 // is waiting on the pipe. |
| 368 do { | 377 do { |
| 369 bytes_read = read(pipe_, input_buf_, Channel::kReadBufferSize); | 378 bytes_read = recvmsg(pipe_, &msg, MSG_DONTWAIT); |
| 370 } while (bytes_read == -1 && errno == EINTR); | 379 } while (bytes_read == -1 && errno == EINTR); |
| 371 | 380 |
| 372 if (bytes_read < 0) { | 381 if (bytes_read < 0) { |
| 373 if (errno == EAGAIN) { | 382 if (errno == EAGAIN) { |
| 374 return true; | 383 return true; |
| 375 } else { | 384 } else { |
| 376 LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno); | 385 LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno); |
| 377 return false; | 386 return false; |
| 378 } | 387 } |
| 379 } else if (bytes_read == 0) { | 388 } else if (bytes_read == 0) { |
| 380 // The pipe has closed... | 389 // The pipe has closed... |
| 381 Close(); | 390 Close(); |
| 382 return false; | 391 return false; |
| 383 } | 392 } |
| 384 } | 393 } |
| 385 DCHECK(bytes_read); | 394 DCHECK(bytes_read); |
| 386 | 395 |
| 387 if (client_pipe_ != -1) { | 396 if (client_pipe_ != -1) { |
| 388 Singleton<PipeMap>()->Remove(pipe_name_); | 397 Singleton<PipeMap>()->Remove(pipe_name_); |
| 389 close(client_pipe_); | 398 close(client_pipe_); |
| 390 client_pipe_ = -1; | 399 client_pipe_ = -1; |
| 391 } | 400 } |
| 392 | 401 |
| 402 // a pointer to an array of |num_wire_fds| file descriptors from the read |
| 403 const int* wire_fds; |
| 404 unsigned num_wire_fds = 0; |
| 405 |
| 406 // walk the list of control messages and, if we find an array of file |
| 407 // descriptors, save a pointer to the array |
| 408 for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg; |
| 409 cmsg = CMSG_NXTHDR(&msg, cmsg)) { |
| 410 if (cmsg->cmsg_level == SOL_SOCKET && |
| 411 cmsg->cmsg_type == SCM_RIGHTS) { |
| 412 const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0); |
| 413 DCHECK(payload_len % sizeof(int) == 0); |
| 414 wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg)); |
| 415 num_wire_fds = payload_len / 4; |
| 416 |
| 417 if (msg.msg_flags & MSG_CTRUNC) { |
| 418 LOG(ERROR) << "SCM_RIGHTS message was truncated" |
| 419 << " cmsg_len:" << cmsg->cmsg_len |
| 420 << " fd:" << pipe_; |
| 421 for (unsigned i = 0; i < num_wire_fds; ++i) |
| 422 close(wire_fds[i]); |
| 423 return false; |
| 424 } |
| 425 break; |
| 426 } |
| 427 } |
| 428 |
| 393 // Process messages from input buffer. | 429 // Process messages from input buffer. |
| 394 const char *p; | 430 const char *p; |
| 395 const char *end; | 431 const char *end; |
| 396 if (input_overflow_buf_.empty()) { | 432 if (input_overflow_buf_.empty()) { |
| 397 p = input_buf_; | 433 p = input_buf_; |
| 398 end = p + bytes_read; | 434 end = p + bytes_read; |
| 399 } else { | 435 } else { |
| 400 if (input_overflow_buf_.size() > | 436 if (input_overflow_buf_.size() > |
| 401 static_cast<size_t>(kMaximumMessageSize - bytes_read)) { | 437 static_cast<size_t>(kMaximumMessageSize - bytes_read)) { |
| 402 input_overflow_buf_.clear(); | 438 input_overflow_buf_.clear(); |
| 403 LOG(ERROR) << "IPC message is too big"; | 439 LOG(ERROR) << "IPC message is too big"; |
| 404 return false; | 440 return false; |
| 405 } | 441 } |
| 406 input_overflow_buf_.append(input_buf_, bytes_read); | 442 input_overflow_buf_.append(input_buf_, bytes_read); |
| 407 p = input_overflow_buf_.data(); | 443 p = input_overflow_buf_.data(); |
| 408 end = p + input_overflow_buf_.size(); | 444 end = p + input_overflow_buf_.size(); |
| 409 } | 445 } |
| 410 | 446 |
| 447 // A pointer to an array of |num_fds| file descriptors which includes any |
| 448 // fds that have spilled over from a previous read. |
| 449 const int* fds; |
| 450 unsigned num_fds; |
| 451 unsigned fds_i = 0; // the index of the first unused descriptor |
| 452 |
| 453 if (input_overflow_fds_.empty()) { |
| 454 fds = wire_fds; |
| 455 num_fds = num_wire_fds; |
| 456 } else { |
| 457 const size_t prev_size = input_overflow_fds_.size(); |
| 458 input_overflow_fds_.resize(prev_size + num_wire_fds); |
| 459 memcpy(&input_overflow_fds_[prev_size], wire_fds, |
| 460 num_wire_fds * sizeof(int)); |
| 461 fds = &input_overflow_fds_[0]; |
| 462 num_fds = input_overflow_fds_.size(); |
| 463 } |
| 464 |
| 411 while (p < end) { | 465 while (p < end) { |
| 412 const char* message_tail = Message::FindNext(p, end); | 466 const char* message_tail = Message::FindNext(p, end); |
| 413 if (message_tail) { | 467 if (message_tail) { |
| 414 int len = static_cast<int>(message_tail - p); | 468 int len = static_cast<int>(message_tail - p); |
| 415 const Message m(p, len); | 469 const Message m(p, len); |
| 470 if (m.header()->num_fds) { |
| 471 // the message has file descriptors |
| 472 if (m.header()->num_fds > num_fds - fds_i) { |
| 473 // the message has been completely received, but we didn't get |
| 474 // enough file descriptors. |
| 475 LOG(WARNING) << "Message needs unreceived descriptors" |
| 476 << " channel:" << this |
| 477 << " message-type:" << m.type() |
| 478 << " header()->num_fds:" << m.header()->num_fds |
| 479 << " num_fds:" << num_fds |
| 480 << " fds_i:" << fds_i; |
| 481 // close the existing file descriptors so that we don't leak them |
| 482 for (unsigned i = fds_i; i < num_fds; ++i) |
| 483 close(fds[i]); |
| 484 input_overflow_fds_.clear(); |
| 485 return false; |
| 486 } |
| 487 |
| 488 m.descriptor_set()->SetDescriptors(&fds[fds_i], m.header()->num_fds); |
| 489 fds_i += m.header()->num_fds; |
| 490 } |
| 416 #ifdef IPC_MESSAGE_DEBUG_EXTRA | 491 #ifdef IPC_MESSAGE_DEBUG_EXTRA |
| 417 DLOG(INFO) << "received message on channel @" << this << | 492 DLOG(INFO) << "received message on channel @" << this << |
| 418 " with type " << m.type(); | 493 " with type " << m.type(); |
| 419 #endif | 494 #endif |
| 420 if (m.routing_id() == MSG_ROUTING_NONE && | 495 if (m.routing_id() == MSG_ROUTING_NONE && |
| 421 m.type() == HELLO_MESSAGE_TYPE) { | 496 m.type() == HELLO_MESSAGE_TYPE) { |
| 422 // The Hello message contains only the process id. | 497 // The Hello message contains only the process id. |
| 423 listener_->OnChannelConnected(MessageIterator(m).NextInt()); | 498 listener_->OnChannelConnected(MessageIterator(m).NextInt()); |
| 424 } else { | 499 } else { |
| 425 listener_->OnMessageReceived(m); | 500 listener_->OnMessageReceived(m); |
| 426 } | 501 } |
| 427 p = message_tail; | 502 p = message_tail; |
| 428 } else { | 503 } else { |
| 429 // Last message is partial. | 504 // Last message is partial. |
| 430 break; | 505 break; |
| 431 } | 506 } |
| 432 } | 507 } |
| 433 input_overflow_buf_.assign(p, end - p); | 508 input_overflow_buf_.assign(p, end - p); |
| 509 input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]); |
| 434 | 510 |
| 435 bytes_read = 0; // Get more data. | 511 bytes_read = 0; // Get more data. |
| 436 } | 512 } |
| 437 | 513 |
| 438 return true; | 514 return true; |
| 439 } | 515 } |
| 440 | 516 |
| 441 bool Channel::ChannelImpl::ProcessOutgoingMessages() { | 517 bool Channel::ChannelImpl::ProcessOutgoingMessages() { |
| 442 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's | 518 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's |
| 443 // no connection? | 519 // no connection? |
| 444 is_blocked_on_write_ = false; | 520 is_blocked_on_write_ = false; |
| 445 | 521 |
| 446 if (output_queue_.empty()) | 522 if (output_queue_.empty()) |
| 447 return true; | 523 return true; |
| 448 | 524 |
| 449 if (pipe_ == -1) | 525 if (pipe_ == -1) |
| 450 return false; | 526 return false; |
| 451 | 527 |
| 452 // Write out all the messages we can till the write blocks or there are no | 528 // Write out all the messages we can till the write blocks or there are no |
| 453 // more outgoing messages. | 529 // more outgoing messages. |
| 454 while (!output_queue_.empty()) { | 530 while (!output_queue_.empty()) { |
| 455 Message* msg = output_queue_.front(); | 531 Message* msg = output_queue_.front(); |
| 456 | 532 |
| 457 size_t amt_to_write = msg->size() - message_send_bytes_written_; | 533 size_t amt_to_write = msg->size() - message_send_bytes_written_; |
| 458 DCHECK(amt_to_write != 0); | 534 DCHECK(amt_to_write != 0); |
| 459 const char *out_bytes = reinterpret_cast<const char*>(msg->data()) + | 535 const char *out_bytes = reinterpret_cast<const char*>(msg->data()) + |
| 460 message_send_bytes_written_; | 536 message_send_bytes_written_; |
| 461 ssize_t bytes_written = -1; | 537 ssize_t bytes_written = -1; |
| 462 do { | 538 do { |
| 463 bytes_written = write(pipe_, out_bytes, amt_to_write); | 539 struct msghdr msgh = {0}; |
| 540 struct iovec iov = {const_cast<char*>(out_bytes), amt_to_write}; |
| 541 msgh.msg_iov = &iov; |
| 542 msgh.msg_iovlen = 1; |
| 543 char buf[CMSG_SPACE( |
| 544 sizeof(int[DescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]))]; |
| 545 |
| 546 if (message_send_bytes_written_ == 0 && |
| 547 !msg->descriptor_set()->empty()) { |
| 548 // This is the first chunk of a message which has descriptors to send |
| 549 struct cmsghdr *cmsg; |
| 550 const unsigned num_fds = msg->descriptor_set()->size(); |
| 551 |
| 552 DCHECK_LE(num_fds, DescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE); |
| 553 |
| 554 msgh.msg_control = buf; |
| 555 msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds); |
| 556 cmsg = CMSG_FIRSTHDR(&msgh); |
| 557 cmsg->cmsg_level = SOL_SOCKET; |
| 558 cmsg->cmsg_type = SCM_RIGHTS; |
| 559 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds); |
| 560 msg->descriptor_set()->GetDescriptors( |
| 561 reinterpret_cast<int*>(CMSG_DATA(cmsg))); |
| 562 msgh.msg_controllen = cmsg->cmsg_len; |
| 563 |
| 564 msg->header()->num_fds = num_fds; |
| 565 } |
| 566 |
| 567 bytes_written = sendmsg(pipe_, &msgh, MSG_DONTWAIT); |
| 568 if (bytes_written > 0) |
| 569 msg->descriptor_set()->CommitAll(); |
| 464 } while (bytes_written == -1 && errno == EINTR); | 570 } while (bytes_written == -1 && errno == EINTR); |
| 465 | 571 |
| 466 if (bytes_written < 0 && errno != EAGAIN) { | 572 if (bytes_written < 0 && errno != EAGAIN) { |
| 467 LOG(ERROR) << "pipe error: " << strerror(errno); | 573 LOG(ERROR) << "pipe error: " << strerror(errno); |
| 468 return false; | 574 return false; |
| 469 } | 575 } |
| 470 | 576 |
| 471 if (static_cast<size_t>(bytes_written) != amt_to_write) { | 577 if (static_cast<size_t>(bytes_written) != amt_to_write) { |
| 472 if (bytes_written > 0) { | 578 if (bytes_written > 0) { |
| 473 // If write() fails with EAGAIN then bytes_written will be -1. | 579 // If write() fails with EAGAIN then bytes_written will be -1. |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 614 } | 720 } |
| 615 | 721 |
| 616 // Unlink the FIFO | 722 // Unlink the FIFO |
| 617 unlink(pipe_name_.c_str()); | 723 unlink(pipe_name_.c_str()); |
| 618 | 724 |
| 619 while (!output_queue_.empty()) { | 725 while (!output_queue_.empty()) { |
| 620 Message* m = output_queue_.front(); | 726 Message* m = output_queue_.front(); |
| 621 output_queue_.pop(); | 727 output_queue_.pop(); |
| 622 delete m; | 728 delete m; |
| 623 } | 729 } |
| 730 |
| 731 // Close any outstanding, received file descriptors |
| 732 for (std::vector<int>::iterator |
| 733 i = input_overflow_fds_.begin(); i != input_overflow_fds_.end(); ++i) { |
| 734 close(*i); |
| 735 } |
| 736 input_overflow_fds_.clear(); |
| 624 } | 737 } |
| 625 | 738 |
| 626 //------------------------------------------------------------------------------ | 739 //------------------------------------------------------------------------------ |
| 627 // Channel's methods simply call through to ChannelImpl. | 740 // Channel's methods simply call through to ChannelImpl. |
| 628 Channel::Channel(const std::wstring& channel_id, Mode mode, | 741 Channel::Channel(const std::wstring& channel_id, Mode mode, |
| 629 Listener* listener) | 742 Listener* listener) |
| 630 : channel_impl_(new ChannelImpl(channel_id, mode, listener)) { | 743 : channel_impl_(new ChannelImpl(channel_id, mode, listener)) { |
| 631 } | 744 } |
| 632 | 745 |
| 633 Channel::~Channel() { | 746 Channel::~Channel() { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 653 void Channel::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) { | 766 void Channel::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) { |
| 654 return channel_impl_->GetClientFileDescriptorMapping(src_fd, dest_fd); | 767 return channel_impl_->GetClientFileDescriptorMapping(src_fd, dest_fd); |
| 655 } | 768 } |
| 656 | 769 |
| 657 void Channel::OnClientConnected() { | 770 void Channel::OnClientConnected() { |
| 658 return channel_impl_->OnClientConnected(); | 771 return channel_impl_->OnClientConnected(); |
| 659 } | 772 } |
| 660 | 773 |
| 661 | 774 |
| 662 } // namespace IPC | 775 } // namespace IPC |
| OLD | NEW |