diff options
Diffstat (limited to 'base/cmsg_test.cpp')
-rw-r--r-- | base/cmsg_test.cpp | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/base/cmsg_test.cpp b/base/cmsg_test.cpp new file mode 100644 index 000000000..9ee5c8253 --- /dev/null +++ b/base/cmsg_test.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/cmsg.h> + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/unique_fd.h> +#include <gtest/gtest.h> + +#if !defined(_WIN32) + +using android::base::ReceiveFileDescriptors; +using android::base::SendFileDescriptors; +using android::base::unique_fd; + +static ino_t GetInode(int fd) { + struct stat st; + if (fstat(fd, &st) != 0) { + PLOG(FATAL) << "fstat failed"; + } + + return st.st_ino; +} + +struct CmsgTest : ::testing::TestWithParam<bool> { + bool Seqpacket() { return GetParam(); } + + void SetUp() override { + ASSERT_TRUE( + android::base::Socketpair(Seqpacket() ? SOCK_SEQPACKET : SOCK_STREAM, &send, &recv)); + int dup1 = dup(tmp1.fd); + ASSERT_NE(-1, dup1); + int dup2 = dup(tmp2.fd); + ASSERT_NE(-1, dup2); + + fd1.reset(dup1); + fd2.reset(dup2); + + ino1 = GetInode(dup1); + ino2 = GetInode(dup2); + } + + unique_fd send; + unique_fd recv; + + TemporaryFile tmp1; + TemporaryFile tmp2; + + unique_fd fd1; + unique_fd fd2; + + ino_t ino1; + ino_t ino2; +}; + +TEST_P(CmsgTest, smoke) { + ASSERT_EQ(1, SendFileDescriptors(send.get(), "x", 1, fd1.get())); + + char buf[2]; + unique_fd received; + ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 2, &received)); + ASSERT_EQ('x', buf[0]); + ASSERT_NE(-1, received.get()); + + ASSERT_EQ(ino1, GetInode(received.get())); +} + +TEST_P(CmsgTest, msg_trunc) { + ASSERT_EQ(2, SendFileDescriptors(send.get(), "ab", 2, fd1.get(), fd2.get())); + + char buf[2]; + unique_fd received1, received2; + + ssize_t rc = ReceiveFileDescriptors(recv.get(), buf, 1, &received1, &received2); + if (Seqpacket()) { + ASSERT_EQ(-1, rc); + ASSERT_EQ(EMSGSIZE, errno); + ASSERT_EQ(-1, received1.get()); + ASSERT_EQ(-1, received2.get()); + } else { + ASSERT_EQ(1, rc); + ASSERT_NE(-1, received1.get()); + ASSERT_NE(-1, received2.get()); + ASSERT_EQ(ino1, GetInode(received1.get())); + ASSERT_EQ(ino2, GetInode(received2.get())); + ASSERT_EQ(1, read(recv.get(), buf, 2)); + } +} + +TEST_P(CmsgTest, msg_ctrunc) { + ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get(), fd2.get())); + + char buf[2]; + unique_fd received; + ASSERT_EQ(-1, ReceiveFileDescriptors(recv.get(), buf, 1, &received)); + ASSERT_EQ(EMSGSIZE, errno); + ASSERT_EQ(-1, received.get()); +} + +TEST_P(CmsgTest, peek) { + ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get())); + + char buf[2]; + ASSERT_EQ(1, ::recv(recv.get(), buf, sizeof(buf), MSG_PEEK)); + ASSERT_EQ('a', buf[0]); + + unique_fd received; + ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received)); + ASSERT_EQ(ino1, GetInode(received.get())); +} + +TEST_P(CmsgTest, stream_fd_association) { + if (Seqpacket()) { + return; + } + + // fds are associated with the first byte of the write. + ASSERT_EQ(1, TEMP_FAILURE_RETRY(write(send.get(), "a", 1))); + ASSERT_EQ(2, SendFileDescriptors(send.get(), "bc", 2, fd1.get())); + ASSERT_EQ(1, SendFileDescriptors(send.get(), "d", 1, fd2.get())); + char buf[2]; + ASSERT_EQ(2, TEMP_FAILURE_RETRY(read(recv.get(), buf, 2))); + ASSERT_EQ(0, memcmp(buf, "ab", 2)); + + std::vector<unique_fd> received1; + ssize_t rc = ReceiveFileDescriptorVector(recv.get(), buf, 1, 1, &received1); + ASSERT_EQ(1, rc); + ASSERT_EQ('c', buf[0]); + ASSERT_TRUE(received1.empty()); + + unique_fd received2; + rc = ReceiveFileDescriptors(recv.get(), buf, 1, &received2); + ASSERT_EQ(1, rc); + ASSERT_EQ('d', buf[0]); + ASSERT_EQ(ino2, GetInode(received2.get())); +} + +TEST_P(CmsgTest, multiple_fd_ordering) { + ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get(), fd2.get())); + + char buf[2]; + unique_fd received1, received2; + ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received1, &received2)); + + ASSERT_NE(-1, received1.get()); + ASSERT_NE(-1, received2.get()); + + ASSERT_EQ(ino1, GetInode(received1.get())); + ASSERT_EQ(ino2, GetInode(received2.get())); +} + +TEST_P(CmsgTest, separate_fd_ordering) { + ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get())); + ASSERT_EQ(1, SendFileDescriptors(send.get(), "b", 1, fd2.get())); + + char buf[2]; + unique_fd received1, received2; + ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received1)); + ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received2)); + + ASSERT_NE(-1, received1.get()); + ASSERT_NE(-1, received2.get()); + + ASSERT_EQ(ino1, GetInode(received1.get())); + ASSERT_EQ(ino2, GetInode(received2.get())); +} + +TEST_P(CmsgTest, separate_fds_no_coalescing) { + unique_fd sent1(dup(tmp1.fd)); + unique_fd sent2(dup(tmp2.fd)); + + ASSERT_EQ(1, SendFileDescriptors(send.get(), "", 1, fd1.get())); + ASSERT_EQ(1, SendFileDescriptors(send.get(), "", 1, fd2.get())); + + char buf[2]; + std::vector<unique_fd> received; + ASSERT_EQ(1, ReceiveFileDescriptorVector(recv.get(), buf, 2, 2, &received)); + ASSERT_EQ(1U, received.size()); + ASSERT_EQ(ino1, GetInode(received[0].get())); + + ASSERT_EQ(1, ReceiveFileDescriptorVector(recv.get(), buf, 2, 2, &received)); + ASSERT_EQ(1U, received.size()); + ASSERT_EQ(ino2, GetInode(received[0].get())); +} + +INSTANTIATE_TEST_CASE_P(CmsgTest, CmsgTest, testing::Bool()); + +#endif |