Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(509)

Side by Side Diff: chrome/common/ipc_channel_posix.cc

Issue 20027: Capability: passing fds over IPC (Closed)
Patch Set: ... Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/common/ipc_channel_posix.h ('k') | chrome/common/ipc_message.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/common/ipc_channel_posix.h ('k') | chrome/common/ipc_message.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698