| Index: ipc/ipc_channel_posix.cc
|
| diff --git a/ipc/ipc_channel_posix.cc b/ipc/ipc_channel_posix.cc
|
| index 98a7cd8a9fa0ad092a1a47733c8b89acd9f16bf6..a74178a694b99dbaf4e759e30e195461a29d30ef 100644
|
| --- a/ipc/ipc_channel_posix.cc
|
| +++ b/ipc/ipc_channel_posix.cc
|
| @@ -347,6 +347,27 @@ bool Channel::ChannelImpl::Connect() {
|
| return did_connect;
|
| }
|
|
|
| +void Channel::ChannelImpl::CloseFileDescriptors(Message* msg) {
|
| +#if defined(OS_MACOSX)
|
| + // There is a bug on OSX which makes it dangerous to close
|
| + // a file descriptor while it is in transit. So instead we
|
| + // store the file descriptor in a set and send a message to
|
| + // the recipient, which is queued AFTER the message that
|
| + // sent the FD. The recipient will reply to the message,
|
| + // letting us know that it is now safe to close the file
|
| + // descriptor. For more information, see:
|
| + // http://crbug.com/298276
|
| + std::vector<int> to_close;
|
| + msg->file_descriptor_set()->ReleaseFDsToClose(&to_close);
|
| + for (size_t i = 0; i < to_close.size(); i++) {
|
| + fds_to_close_.insert(to_close[i]);
|
| + QueueCloseFDMessage(to_close[i], 2);
|
| + }
|
| +#else
|
| + msg->file_descriptor_set()->CommitAll();
|
| +#endif
|
| +}
|
| +
|
| bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
| DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
|
| // no connection?
|
| @@ -419,7 +440,7 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
| msgh.msg_iov = &iov;
|
| msgh.msg_controllen = 0;
|
| if (bytes_written > 0) {
|
| - msg->file_descriptor_set()->CommitAll();
|
| + CloseFileDescriptors(msg);
|
| }
|
| }
|
| #endif // IPC_USES_READWRITE
|
| @@ -440,7 +461,7 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
| }
|
| }
|
| if (bytes_written > 0)
|
| - msg->file_descriptor_set()->CommitAll();
|
| + CloseFileDescriptors(msg);
|
|
|
| if (bytes_written < 0 && !SocketWriteErrorIsRecoverable()) {
|
| #if defined(OS_MACOSX)
|
| @@ -575,6 +596,17 @@ void Channel::ChannelImpl::ResetToAcceptingConnectionState() {
|
|
|
| // Close any outstanding, received file descriptors.
|
| ClearInputFDs();
|
| +
|
| +#if defined(OS_MACOSX)
|
| + // Clear any outstanding, sent file descriptors.
|
| + for (std::set<int>::iterator i = fds_to_close_.begin();
|
| + i != fds_to_close_.end();
|
| + ++i) {
|
| + if (HANDLE_EINTR(close(*i)) < 0)
|
| + PLOG(ERROR) << "close";
|
| + }
|
| + fds_to_close_.clear();
|
| +#endif
|
| }
|
|
|
| // static
|
| @@ -592,7 +624,6 @@ void Channel::ChannelImpl::SetGlobalPid(int pid) {
|
|
|
| // Called by libevent when we can read from the pipe without blocking.
|
| void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
|
| - bool send_server_hello_msg = false;
|
| if (fd == server_listen_pipe_) {
|
| int new_pipe = 0;
|
| if (!ServerAcceptConnection(server_listen_pipe_, &new_pipe) ||
|
| @@ -631,18 +662,16 @@ void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
|
| if (!AcceptConnection()) {
|
| NOTREACHED() << "AcceptConnection should not fail on server";
|
| }
|
| - send_server_hello_msg = true;
|
| waiting_connect_ = false;
|
| } else if (fd == pipe_) {
|
| if (waiting_connect_ && (mode_ & MODE_SERVER_FLAG)) {
|
| - send_server_hello_msg = true;
|
| waiting_connect_ = false;
|
| }
|
| if (!ProcessIncomingMessages()) {
|
| // ClosePipeOnError may delete this object, so we mustn't call
|
| // ProcessOutgoingMessages.
|
| - send_server_hello_msg = false;
|
| ClosePipeOnError();
|
| + return;
|
| }
|
| } else {
|
| NOTREACHED() << "Unknown pipe " << fd;
|
| @@ -651,9 +680,11 @@ void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
|
| // If we're a server and handshaking, then we want to make sure that we
|
| // only send our handshake message after we've processed the client's.
|
| // This gives us a chance to kill the client if the incoming handshake
|
| - // is invalid.
|
| - if (send_server_hello_msg) {
|
| - ProcessOutgoingMessages();
|
| + // is invalid. This also flushes any closefd messagse.
|
| + if (!is_blocked_on_write_) {
|
| + if (!ProcessOutgoingMessages()) {
|
| + ClosePipeOnError();
|
| + }
|
| }
|
| }
|
|
|
| @@ -902,29 +933,80 @@ void Channel::ChannelImpl::ClearInputFDs() {
|
| input_fds_.clear();
|
| }
|
|
|
| -void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) {
|
| +void Channel::ChannelImpl::QueueCloseFDMessage(int fd, int hops) {
|
| + switch (hops) {
|
| + case 1:
|
| + case 2: {
|
| + // Create the message
|
| + scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE,
|
| + CLOSE_FD_MESSAGE_TYPE,
|
| + IPC::Message::PRIORITY_NORMAL));
|
| + if (!msg->WriteInt(hops - 1) || !msg->WriteInt(fd)) {
|
| + NOTREACHED() << "Unable to pickle close fd.";
|
| + }
|
| + // Send(msg.release());
|
| + output_queue_.push(msg.release());
|
| + break;
|
| + }
|
| +
|
| + default:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| +}
|
| +
|
| +void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) {
|
| // The Hello message contains only the process id.
|
| PickleIterator iter(msg);
|
| - int pid;
|
| - if (!msg.ReadInt(&iter, &pid))
|
| - NOTREACHED();
|
|
|
| -#if defined(IPC_USES_READWRITE)
|
| - if (mode_ & MODE_SERVER_FLAG) {
|
| - // With IPC_USES_READWRITE, the Hello message from the client to the
|
| - // server also contains the fd_pipe_, which will be used for all
|
| - // subsequent file descriptor passing.
|
| - DCHECK_EQ(msg.file_descriptor_set()->size(), 1U);
|
| - base::FileDescriptor descriptor;
|
| - if (!msg.ReadFileDescriptor(&iter, &descriptor)) {
|
| + switch (msg.type()) {
|
| + default:
|
| NOTREACHED();
|
| - }
|
| - fd_pipe_ = descriptor.fd;
|
| - CHECK(descriptor.auto_close);
|
| - }
|
| + break;
|
| +
|
| + case Channel::HELLO_MESSAGE_TYPE:
|
| + int pid;
|
| + if (!msg.ReadInt(&iter, &pid))
|
| + NOTREACHED();
|
| +
|
| +#if defined(IPC_USES_READWRITE)
|
| + if (mode_ & MODE_SERVER_FLAG) {
|
| + // With IPC_USES_READWRITE, the Hello message from the client to the
|
| + // server also contains the fd_pipe_, which will be used for all
|
| + // subsequent file descriptor passing.
|
| + DCHECK_EQ(msg.file_descriptor_set()->size(), 1U);
|
| + base::FileDescriptor descriptor;
|
| + if (!msg.ReadFileDescriptor(&iter, &descriptor)) {
|
| + NOTREACHED();
|
| + }
|
| + fd_pipe_ = descriptor.fd;
|
| + CHECK(descriptor.auto_close);
|
| + }
|
| #endif // IPC_USES_READWRITE
|
| - peer_pid_ = pid;
|
| - listener()->OnChannelConnected(pid);
|
| + peer_pid_ = pid;
|
| + listener()->OnChannelConnected(pid);
|
| + break;
|
| +
|
| +#if defined(OS_MACOSX)
|
| + case Channel::CLOSE_FD_MESSAGE_TYPE:
|
| + int fd, hops;
|
| + if (!msg.ReadInt(&iter, &hops))
|
| + NOTREACHED();
|
| + if (!msg.ReadInt(&iter, &fd))
|
| + NOTREACHED();
|
| + if (hops == 0) {
|
| + if (fds_to_close_.erase(fd) > 0) {
|
| + if (HANDLE_EINTR(close(fd)) < 0)
|
| + PLOG(ERROR) << "close";
|
| + } else {
|
| + NOTREACHED();
|
| + }
|
| + } else {
|
| + QueueCloseFDMessage(fd, hops);
|
| + }
|
| + break;
|
| +#endif
|
| + }
|
| }
|
|
|
| void Channel::ChannelImpl::Close() {
|
|
|