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 |