Mojo: Make PlatformChannelRecvmsg() append handles to a deque instead.

This is part 1 (of N) of my rearranging things to make passing FDs
actually work correctly.

R=yzshen@chromium.org

Review URL: https://codereview.chromium.org/292983007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271849 0039d316-1c4b-4281-b951-d872f2087c98
parent 9058c2e6
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <sys/uio.h> #include <sys/uio.h>
#include <unistd.h> #include <unistd.h>
#include <vector> #include <deque>
#include "base/file_util.h" #include "base/file_util.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include "base/macros.h" #include "base/macros.h"
#include "mojo/common/test/test_utils.h" #include "mojo/common/test/test_utils.h"
#include "mojo/embedder/platform_channel_utils_posix.h" #include "mojo/embedder/platform_channel_utils_posix.h"
#include "mojo/embedder/platform_handle.h"
#include "mojo/embedder/platform_handle_vector.h"
#include "mojo/embedder/scoped_platform_handle.h" #include "mojo/embedder/scoped_platform_handle.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -117,12 +119,12 @@ TEST_F(PlatformChannelPairPosixTest, SendReceiveData) { ...@@ -117,12 +119,12 @@ TEST_F(PlatformChannelPairPosixTest, SendReceiveData) {
WaitReadable(client_handle.get()); WaitReadable(client_handle.get());
char buf[10000] = {}; char buf[10000] = {};
ScopedPlatformHandleVectorPtr received_handles; std::deque<PlatformHandle> received_handles;
ssize_t result = PlatformChannelRecvmsg(client_handle.get(), buf, ssize_t result = PlatformChannelRecvmsg(client_handle.get(), buf,
sizeof(buf), &received_handles); sizeof(buf), &received_handles);
EXPECT_EQ(static_cast<ssize_t>(send_string.size()), result); EXPECT_EQ(static_cast<ssize_t>(send_string.size()), result);
EXPECT_EQ(send_string, std::string(buf, static_cast<size_t>(result))); EXPECT_EQ(send_string, std::string(buf, static_cast<size_t>(result)));
EXPECT_FALSE(received_handles); EXPECT_TRUE(received_handles.empty());
} }
} }
...@@ -152,17 +154,17 @@ TEST_F(PlatformChannelPairPosixTest, SendReceiveFDs) { ...@@ -152,17 +154,17 @@ TEST_F(PlatformChannelPairPosixTest, SendReceiveFDs) {
WaitReadable(client_handle.get()); WaitReadable(client_handle.get());
char buf[100] = { 'a' }; char buf[100] = { 'a' };
ScopedPlatformHandleVectorPtr received_handles; std::deque<PlatformHandle> received_handles;
EXPECT_EQ(1, PlatformChannelRecvmsg(client_handle.get(), buf, sizeof(buf), EXPECT_EQ(1, PlatformChannelRecvmsg(client_handle.get(), buf, sizeof(buf),
&received_handles)); &received_handles));
EXPECT_EQ('\0', buf[0]); EXPECT_EQ('\0', buf[0]);
ASSERT_TRUE(received_handles); ASSERT_FALSE(received_handles.empty());
EXPECT_EQ(i, received_handles->size()); EXPECT_EQ(i, received_handles.size());
for (size_t j = 0; j < received_handles->size(); j++) { for (size_t j = 0; !received_handles.empty(); j++) {
base::ScopedFILE fp(test::FILEFromPlatformHandle( base::ScopedFILE fp(test::FILEFromPlatformHandle(
ScopedPlatformHandle((*received_handles)[j]), "rb")); ScopedPlatformHandle(received_handles.front()), "rb"));
(*received_handles)[j] = PlatformHandle(); received_handles.pop_front();
ASSERT_TRUE(fp); ASSERT_TRUE(fp);
rewind(fp.get()); rewind(fp.get());
char read_buf[100]; char read_buf[100];
...@@ -198,23 +200,22 @@ TEST_F(PlatformChannelPairPosixTest, AppendReceivedFDs) { ...@@ -198,23 +200,22 @@ TEST_F(PlatformChannelPairPosixTest, AppendReceivedFDs) {
WaitReadable(client_handle.get()); WaitReadable(client_handle.get());
// Start with an invalid handle in the vector. // Start with an invalid handle in the deque.
ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector()); std::deque<PlatformHandle> received_handles;
handles->push_back(PlatformHandle()); received_handles.push_back(PlatformHandle());
char buf[100] = { 'a' }; char buf[100] = { 'a' };
EXPECT_EQ(1, PlatformChannelRecvmsg(client_handle.get(), buf, sizeof(buf), EXPECT_EQ(1, PlatformChannelRecvmsg(client_handle.get(), buf, sizeof(buf),
&handles)); &received_handles));
EXPECT_EQ('\0', buf[0]); EXPECT_EQ('\0', buf[0]);
ASSERT_TRUE(handles); ASSERT_EQ(2u, received_handles.size());
ASSERT_EQ(2u, handles->size()); EXPECT_FALSE(received_handles[0].is_valid());
EXPECT_FALSE((*handles)[0].is_valid()); EXPECT_TRUE(received_handles[1].is_valid());
EXPECT_TRUE((*handles)[1].is_valid());
{ {
base::ScopedFILE fp(test::FILEFromPlatformHandle( base::ScopedFILE fp(test::FILEFromPlatformHandle(
ScopedPlatformHandle((*handles)[1]), "rb")); ScopedPlatformHandle(received_handles[1]), "rb"));
(*handles)[1] = PlatformHandle(); received_handles[1] = PlatformHandle();
ASSERT_TRUE(fp); ASSERT_TRUE(fp);
rewind(fp.get()); rewind(fp.get());
char read_buf[100]; char read_buf[100];
......
...@@ -105,10 +105,10 @@ bool PlatformChannelSendHandles(PlatformHandle h, ...@@ -105,10 +105,10 @@ bool PlatformChannelSendHandles(PlatformHandle h,
ssize_t PlatformChannelRecvmsg(PlatformHandle h, ssize_t PlatformChannelRecvmsg(PlatformHandle h,
void* buf, void* buf,
size_t num_bytes, size_t num_bytes,
ScopedPlatformHandleVectorPtr* handles) { std::deque<PlatformHandle>* platform_handles) {
DCHECK(buf); DCHECK(buf);
DCHECK_GT(num_bytes, 0u); DCHECK_GT(num_bytes, 0u);
DCHECK(handles); DCHECK(platform_handles);
struct iovec iov = { buf, num_bytes }; struct iovec iov = { buf, num_bytes };
char cmsg_buf[CMSG_SPACE(kPlatformChannelMaxNumHandles * sizeof(int))]; char cmsg_buf[CMSG_SPACE(kPlatformChannelMaxNumHandles * sizeof(int))];
...@@ -137,10 +137,8 @@ ssize_t PlatformChannelRecvmsg(PlatformHandle h, ...@@ -137,10 +137,8 @@ ssize_t PlatformChannelRecvmsg(PlatformHandle h,
size_t num_fds = payload_length / sizeof(int); size_t num_fds = payload_length / sizeof(int);
const int* fds = reinterpret_cast<int*>(CMSG_DATA(cmsg)); const int* fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
for (size_t i = 0; i < num_fds; i++) { for (size_t i = 0; i < num_fds; i++) {
if (!*handles) platform_handles->push_back(PlatformHandle(fds[i]));
(*handles).reset(new PlatformHandleVector()); DCHECK(platform_handles->back().is_valid());
(*handles)->push_back(PlatformHandle(fds[i]));
DCHECK((*handles)->back().is_valid());
} }
} }
} }
......
...@@ -8,11 +8,10 @@ ...@@ -8,11 +8,10 @@
#include <stddef.h> #include <stddef.h>
#include <sys/types.h> // For |ssize_t|. #include <sys/types.h> // For |ssize_t|.
#include <vector> #include <deque>
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "mojo/embedder/platform_handle.h" #include "mojo/embedder/platform_handle.h"
#include "mojo/embedder/platform_handle_vector.h"
#include "mojo/system/system_impl_export.h" #include "mojo/system/system_impl_export.h"
struct iovec; // Declared in <sys/uio.h>. struct iovec; // Declared in <sys/uio.h>.
...@@ -48,14 +47,13 @@ MOJO_SYSTEM_IMPL_EXPORT bool PlatformChannelSendHandles(PlatformHandle h, ...@@ -48,14 +47,13 @@ MOJO_SYSTEM_IMPL_EXPORT bool PlatformChannelSendHandles(PlatformHandle h,
size_t num_handles); size_t num_handles);
// Wrapper around |recvmsg()|, which will extract any attached file descriptors // Wrapper around |recvmsg()|, which will extract any attached file descriptors
// (in the control message) to |PlatformHandle|s. (This also handles |EINTR|.) // (in the control message) to |PlatformHandle|s (and append them to
// If |*handles| is null and handles are received, a vector will be allocated; // |platform_handles|). (This also handles |EINTR|.)
// otherwise, any handles received will be appended to the existing vector.
MOJO_SYSTEM_IMPL_EXPORT ssize_t PlatformChannelRecvmsg( MOJO_SYSTEM_IMPL_EXPORT ssize_t PlatformChannelRecvmsg(
PlatformHandle h, PlatformHandle h,
void* buf, void* buf,
size_t num_bytes, size_t num_bytes,
ScopedPlatformHandleVectorPtr* handles); std::deque<PlatformHandle>* platform_handles);
} // namespace embedder } // namespace embedder
} // namespace mojo } // namespace mojo
......
...@@ -2,13 +2,20 @@ ...@@ -2,13 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "mojo/embedder/platform_handle_vector.h" #ifndef MOJO_EMBEDDER_PLATFORM_HANDLE_UTILS_H_
#define MOJO_EMBEDDER_PLATFORM_HANDLE_UTILS_H_
#include "mojo/embedder/platform_handle.h"
#include "mojo/system/system_impl_export.h"
namespace mojo { namespace mojo {
namespace embedder { namespace embedder {
void CloseAllHandles(PlatformHandleVector* platform_handles) { template <typename PlatformHandleContainer>
for (PlatformHandleVector::iterator it = platform_handles->begin(); MOJO_SYSTEM_IMPL_EXPORT inline void CloseAllPlatformHandles(
PlatformHandleContainer* platform_handles) {
for (typename PlatformHandleContainer::iterator it =
platform_handles->begin();
it != platform_handles->end(); it != platform_handles->end();
++it) ++it)
it->CloseIfNecessary(); it->CloseIfNecessary();
...@@ -16,3 +23,5 @@ void CloseAllHandles(PlatformHandleVector* platform_handles) { ...@@ -16,3 +23,5 @@ void CloseAllHandles(PlatformHandleVector* platform_handles) {
} // namespace embedder } // namespace embedder
} // namespace mojo } // namespace mojo
#endif // MOJO_EMBEDDER_PLATFORM_HANDLE_UTILS_H_
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "mojo/embedder/platform_handle.h" #include "mojo/embedder/platform_handle.h"
#include "mojo/embedder/platform_handle_utils.h"
#include "mojo/system/system_impl_export.h" #include "mojo/system/system_impl_export.h"
namespace mojo { namespace mojo {
...@@ -16,14 +17,11 @@ namespace embedder { ...@@ -16,14 +17,11 @@ namespace embedder {
typedef std::vector<PlatformHandle> PlatformHandleVector; typedef std::vector<PlatformHandle> PlatformHandleVector;
MOJO_SYSTEM_IMPL_EXPORT void CloseAllHandles(
PlatformHandleVector* platform_handles);
// A deleter (for use with |scoped_ptr|) which closes all handles and then // A deleter (for use with |scoped_ptr|) which closes all handles and then
// |delete|s the |PlatformHandleVector|. // |delete|s the |PlatformHandleVector|.
struct MOJO_SYSTEM_IMPL_EXPORT PlatformHandleVectorDeleter { struct MOJO_SYSTEM_IMPL_EXPORT PlatformHandleVectorDeleter {
void operator()(PlatformHandleVector* platform_handles) const { void operator()(PlatformHandleVector* platform_handles) const {
CloseAllHandles(platform_handles); CloseAllPlatformHandles(platform_handles);
delete platform_handles; delete platform_handles;
} }
}; };
......
...@@ -152,7 +152,7 @@ ...@@ -152,7 +152,7 @@
'embedder/platform_channel_utils_posix.h', 'embedder/platform_channel_utils_posix.h',
'embedder/platform_handle.cc', 'embedder/platform_handle.cc',
'embedder/platform_handle.h', 'embedder/platform_handle.h',
'embedder/platform_handle_vector.cc', 'embedder/platform_handle_utils.h',
'embedder/platform_handle_vector.h', 'embedder/platform_handle_vector.h',
'embedder/scoped_platform_handle.h', 'embedder/scoped_platform_handle.h',
'system/channel.cc', 'system/channel.cc',
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <unistd.h> #include <unistd.h>
#include <algorithm> #include <algorithm>
#include <deque>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/bind.h" #include "base/bind.h"
...@@ -68,7 +69,7 @@ class RawChannelPosix : public RawChannel, ...@@ -68,7 +69,7 @@ class RawChannelPosix : public RawChannel,
bool pending_read_; bool pending_read_;
embedder::ScopedPlatformHandleVectorPtr read_platform_handles_; std::deque<embedder::PlatformHandle> read_platform_handles_;
// The following members are used on multiple threads and protected by // The following members are used on multiple threads and protected by
// |write_lock()|: // |write_lock()|:
...@@ -102,6 +103,8 @@ RawChannelPosix::~RawChannelPosix() { ...@@ -102,6 +103,8 @@ RawChannelPosix::~RawChannelPosix() {
// These must have been shut down/destroyed on the I/O thread. // These must have been shut down/destroyed on the I/O thread.
DCHECK(!read_watcher_.get()); DCHECK(!read_watcher_.get());
DCHECK(!write_watcher_.get()); DCHECK(!write_watcher_.get());
embedder::CloseAllPlatformHandles(&read_platform_handles_);
} }
size_t RawChannelPosix::GetSerializedPlatformHandleSize() const { size_t RawChannelPosix::GetSerializedPlatformHandleSize() const {
...@@ -117,23 +120,31 @@ RawChannel::IOResult RawChannelPosix::Read(size_t* bytes_read) { ...@@ -117,23 +120,31 @@ RawChannel::IOResult RawChannelPosix::Read(size_t* bytes_read) {
size_t bytes_to_read = 0; size_t bytes_to_read = 0;
read_buffer()->GetBuffer(&buffer, &bytes_to_read); read_buffer()->GetBuffer(&buffer, &bytes_to_read);
size_t old_num_platform_handles = size_t old_num_platform_handles = read_platform_handles_.size();
read_platform_handles_ ? read_platform_handles_->size() : 0;
ssize_t read_result = ssize_t read_result =
embedder::PlatformChannelRecvmsg(fd_.get(), embedder::PlatformChannelRecvmsg(fd_.get(),
buffer, buffer,
bytes_to_read, bytes_to_read,
&read_platform_handles_); &read_platform_handles_);
if (read_platform_handles_ && if (read_platform_handles_.size() > old_num_platform_handles) {
read_platform_handles_->size() > old_num_platform_handles) { DCHECK_LE(read_platform_handles_.size() - old_num_platform_handles,
embedder::kPlatformChannelMaxNumHandles);
if (read_result != 1) { if (read_result != 1) {
LOG(WARNING) << "Invalid control message with platform handles"; LOG(WARNING) << "Invalid control message with platform handles";
return IO_FAILED; return IO_FAILED;
} }
if (read_platform_handles_->size() > TransportData::kMaxPlatformHandles) { // We should never accumulate more than |TransportData::kMaxPlatformHandles
// + embedder::kPlatformChannelMaxNumHandles| handles. (The latter part is
// possible because we could have accumulated all the handles for a message,
// then received the message data plus the first set of handles for the next
// message in the subsequent |recvmsg()|.)
if (read_platform_handles_.size() > (TransportData::kMaxPlatformHandles +
embedder::kPlatformChannelMaxNumHandles)) {
LOG(WARNING) << "Received too many platform handles"; LOG(WARNING) << "Received too many platform handles";
read_platform_handles_.reset(); embedder::CloseAllPlatformHandles(&read_platform_handles_);
read_platform_handles_.clear();
return IO_FAILED; return IO_FAILED;
} }
...@@ -173,13 +184,20 @@ embedder::ScopedPlatformHandleVectorPtr RawChannelPosix::GetReadPlatformHandles( ...@@ -173,13 +184,20 @@ embedder::ScopedPlatformHandleVectorPtr RawChannelPosix::GetReadPlatformHandles(
const void* /*platform_handle_table*/) { const void* /*platform_handle_table*/) {
DCHECK_GT(num_platform_handles, 0u); DCHECK_GT(num_platform_handles, 0u);
if (!read_platform_handles_ || if (read_platform_handles_.size() < num_platform_handles) {
read_platform_handles_->size() != num_platform_handles) { embedder::CloseAllPlatformHandles(&read_platform_handles_);
read_platform_handles_.reset(); read_platform_handles_.clear();
return embedder::ScopedPlatformHandleVectorPtr(); return embedder::ScopedPlatformHandleVectorPtr();
} }
return read_platform_handles_.Pass(); embedder::ScopedPlatformHandleVectorPtr rv(
new embedder::PlatformHandleVector(num_platform_handles));
rv->assign(read_platform_handles_.begin(),
read_platform_handles_.begin() + num_platform_handles);
read_platform_handles_.erase(
read_platform_handles_.begin(),
read_platform_handles_.begin() + num_platform_handles);
return rv.Pass();
} }
RawChannel::IOResult RawChannelPosix::WriteNoLock( RawChannel::IOResult RawChannelPosix::WriteNoLock(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment