Home | History | Annotate | Download | only in embedder
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "mojo/embedder/platform_channel_pair.h"
      6 
      7 #include <errno.h>
      8 #include <poll.h>
      9 #include <signal.h>
     10 #include <stdio.h>
     11 #include <sys/socket.h>
     12 #include <sys/types.h>
     13 #include <sys/uio.h>
     14 #include <unistd.h>
     15 
     16 #include <deque>
     17 
     18 #include "base/file_util.h"
     19 #include "base/files/file_path.h"
     20 #include "base/files/scoped_file.h"
     21 #include "base/logging.h"
     22 #include "base/macros.h"
     23 #include "mojo/common/test/test_utils.h"
     24 #include "mojo/embedder/platform_channel_utils_posix.h"
     25 #include "mojo/embedder/platform_handle.h"
     26 #include "mojo/embedder/platform_handle_vector.h"
     27 #include "mojo/embedder/scoped_platform_handle.h"
     28 #include "testing/gtest/include/gtest/gtest.h"
     29 
     30 namespace mojo {
     31 namespace embedder {
     32 namespace {
     33 
     34 void WaitReadable(PlatformHandle h) {
     35   struct pollfd pfds = {};
     36   pfds.fd = h.fd;
     37   pfds.events = POLLIN;
     38   CHECK_EQ(poll(&pfds, 1, -1), 1);
     39 }
     40 
     41 class PlatformChannelPairPosixTest : public testing::Test {
     42  public:
     43   PlatformChannelPairPosixTest() {}
     44   virtual ~PlatformChannelPairPosixTest() {}
     45 
     46   virtual void SetUp() OVERRIDE {
     47     // Make sure |SIGPIPE| isn't being ignored.
     48     struct sigaction action = {};
     49     action.sa_handler = SIG_DFL;
     50     ASSERT_EQ(0, sigaction(SIGPIPE, &action, &old_action_));
     51   }
     52 
     53   virtual void TearDown() OVERRIDE {
     54     // Restore the |SIGPIPE| handler.
     55     ASSERT_EQ(0, sigaction(SIGPIPE, &old_action_, NULL));
     56   }
     57 
     58  private:
     59   struct sigaction old_action_;
     60 
     61   DISALLOW_COPY_AND_ASSIGN(PlatformChannelPairPosixTest);
     62 };
     63 
     64 TEST_F(PlatformChannelPairPosixTest, NoSigPipe) {
     65   PlatformChannelPair channel_pair;
     66   ScopedPlatformHandle server_handle = channel_pair.PassServerHandle().Pass();
     67   ScopedPlatformHandle client_handle = channel_pair.PassClientHandle().Pass();
     68 
     69   // Write to the client.
     70   static const char kHello[] = "hello";
     71   EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
     72             write(client_handle.get().fd, kHello, sizeof(kHello)));
     73 
     74   // Close the client.
     75   client_handle.reset();
     76 
     77   // Read from the server; this should be okay.
     78   char buffer[100] = {};
     79   EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
     80             read(server_handle.get().fd, buffer, sizeof(buffer)));
     81   EXPECT_STREQ(kHello, buffer);
     82 
     83   // Try reading again.
     84   ssize_t result = read(server_handle.get().fd, buffer, sizeof(buffer));
     85   // We should probably get zero (for "end of file"), but -1 would also be okay.
     86   EXPECT_TRUE(result == 0 || result == -1);
     87   if (result == -1)
     88     PLOG(WARNING) << "read (expected 0 for EOF)";
     89 
     90   // Test our replacement for |write()|/|send()|.
     91   result = PlatformChannelWrite(server_handle.get(), kHello, sizeof(kHello));
     92   EXPECT_EQ(-1, result);
     93   if (errno != EPIPE)
     94     PLOG(WARNING) << "write (expected EPIPE)";
     95 
     96   // Test our replacement for |writev()|/|sendv()|.
     97   struct iovec iov[2] = {
     98     { const_cast<char*>(kHello), sizeof(kHello) },
     99     { const_cast<char*>(kHello), sizeof(kHello) }
    100   };
    101   result = PlatformChannelWritev(server_handle.get(), iov, 2);
    102   EXPECT_EQ(-1, result);
    103   if (errno != EPIPE)
    104     PLOG(WARNING) << "write (expected EPIPE)";
    105 }
    106 
    107 TEST_F(PlatformChannelPairPosixTest, SendReceiveData) {
    108   PlatformChannelPair channel_pair;
    109   ScopedPlatformHandle server_handle = channel_pair.PassServerHandle().Pass();
    110   ScopedPlatformHandle client_handle = channel_pair.PassClientHandle().Pass();
    111 
    112   for (size_t i = 0; i < 10; i++) {
    113     std::string send_string(1 << i, 'A' + i);
    114 
    115     EXPECT_EQ(static_cast<ssize_t>(send_string.size()),
    116               PlatformChannelWrite(server_handle.get(), send_string.data(),
    117                                    send_string.size()));
    118 
    119     WaitReadable(client_handle.get());
    120 
    121     char buf[10000] = {};
    122     std::deque<PlatformHandle> received_handles;
    123     ssize_t result = PlatformChannelRecvmsg(client_handle.get(), buf,
    124                                             sizeof(buf), &received_handles);
    125     EXPECT_EQ(static_cast<ssize_t>(send_string.size()), result);
    126     EXPECT_EQ(send_string, std::string(buf, static_cast<size_t>(result)));
    127     EXPECT_TRUE(received_handles.empty());
    128   }
    129 }
    130 
    131 TEST_F(PlatformChannelPairPosixTest, SendReceiveFDs) {
    132   static const char kHello[] = "hello";
    133 
    134   PlatformChannelPair channel_pair;
    135   ScopedPlatformHandle server_handle = channel_pair.PassServerHandle().Pass();
    136   ScopedPlatformHandle client_handle = channel_pair.PassClientHandle().Pass();
    137 
    138   for (size_t i = 1; i < kPlatformChannelMaxNumHandles; i++) {
    139     // Make |i| files, with the j-th file consisting of j copies of the digit i.
    140     PlatformHandleVector platform_handles;
    141     for (size_t j = 1; j <= i; j++) {
    142       base::FilePath ignored;
    143       base::ScopedFILE fp(base::CreateAndOpenTemporaryFile(&ignored));
    144       ASSERT_TRUE(fp);
    145       fwrite(std::string(j, '0' + i).data(), 1, j, fp.get());
    146       platform_handles.push_back(
    147           test::PlatformHandleFromFILE(fp.Pass()).release());
    148       ASSERT_TRUE(platform_handles.back().is_valid());
    149     }
    150 
    151     // Send the FDs (+ "hello").
    152     struct iovec iov = { const_cast<char*>(kHello), sizeof(kHello) };
    153     // We assume that the |sendmsg()| actually sends all the data.
    154     EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
    155               PlatformChannelSendmsgWithHandles(server_handle.get(), &iov, 1,
    156                                                 &platform_handles[0],
    157                                                 platform_handles.size()));
    158 
    159     WaitReadable(client_handle.get());
    160 
    161     char buf[100] = {};
    162     std::deque<PlatformHandle> received_handles;
    163     // We assume that the |recvmsg()| actually reads all the data.
    164     EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
    165               PlatformChannelRecvmsg(client_handle.get(), buf, sizeof(buf),
    166                                      &received_handles));
    167     EXPECT_STREQ(kHello, buf);
    168     EXPECT_EQ(i, received_handles.size());
    169 
    170     for (size_t j = 0; !received_handles.empty(); j++) {
    171       base::ScopedFILE fp(test::FILEFromPlatformHandle(
    172           ScopedPlatformHandle(received_handles.front()), "rb"));
    173       received_handles.pop_front();
    174       ASSERT_TRUE(fp);
    175       rewind(fp.get());
    176       char read_buf[100];
    177       size_t bytes_read = fread(read_buf, 1, sizeof(read_buf), fp.get());
    178       EXPECT_EQ(j + 1, bytes_read);
    179       EXPECT_EQ(std::string(j + 1, '0' + i), std::string(read_buf, bytes_read));
    180     }
    181   }
    182 }
    183 
    184 TEST_F(PlatformChannelPairPosixTest, AppendReceivedFDs) {
    185   static const char kHello[] = "hello";
    186 
    187   PlatformChannelPair channel_pair;
    188   ScopedPlatformHandle server_handle = channel_pair.PassServerHandle().Pass();
    189   ScopedPlatformHandle client_handle = channel_pair.PassClientHandle().Pass();
    190 
    191   const std::string file_contents("hello world");
    192 
    193   {
    194     base::FilePath ignored;
    195     base::ScopedFILE fp(base::CreateAndOpenTemporaryFile(&ignored));
    196     ASSERT_TRUE(fp);
    197     fwrite(file_contents.data(), 1, file_contents.size(), fp.get());
    198     PlatformHandleVector platform_handles;
    199     platform_handles.push_back(
    200         test::PlatformHandleFromFILE(fp.Pass()).release());
    201     ASSERT_TRUE(platform_handles.back().is_valid());
    202 
    203     // Send the FD (+ "hello").
    204     struct iovec iov = { const_cast<char*>(kHello), sizeof(kHello) };
    205     // We assume that the |sendmsg()| actually sends all the data.
    206     EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
    207               PlatformChannelSendmsgWithHandles(server_handle.get(), &iov, 1,
    208                                                 &platform_handles[0],
    209                                                 platform_handles.size()));
    210   }
    211 
    212   WaitReadable(client_handle.get());
    213 
    214   // Start with an invalid handle in the deque.
    215   std::deque<PlatformHandle> received_handles;
    216   received_handles.push_back(PlatformHandle());
    217 
    218   char buf[100] = {};
    219   // We assume that the |recvmsg()| actually reads all the data.
    220   EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
    221             PlatformChannelRecvmsg(client_handle.get(), buf, sizeof(buf),
    222                                    &received_handles));
    223   EXPECT_STREQ(kHello, buf);
    224   ASSERT_EQ(2u, received_handles.size());
    225   EXPECT_FALSE(received_handles[0].is_valid());
    226   EXPECT_TRUE(received_handles[1].is_valid());
    227 
    228   {
    229     base::ScopedFILE fp(test::FILEFromPlatformHandle(
    230         ScopedPlatformHandle(received_handles[1]), "rb"));
    231     received_handles[1] = PlatformHandle();
    232     ASSERT_TRUE(fp);
    233     rewind(fp.get());
    234     char read_buf[100];
    235     size_t bytes_read = fread(read_buf, 1, sizeof(read_buf), fp.get());
    236     EXPECT_EQ(file_contents.size(), bytes_read);
    237     EXPECT_EQ(file_contents, std::string(read_buf, bytes_read));
    238   }
    239 }
    240 
    241 }  // namespace
    242 }  // namespace embedder
    243 }  // namespace mojo
    244