1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <android-base/cmsg.h>
18
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <android-base/unique_fd.h>
22 #include <gtest/gtest.h>
23
24 #if !defined(_WIN32)
25
26 using android::base::ReceiveFileDescriptors;
27 using android::base::SendFileDescriptors;
28 using android::base::unique_fd;
29
GetInode(int fd)30 static ino_t GetInode(int fd) {
31 struct stat st;
32 if (fstat(fd, &st) != 0) {
33 PLOG(FATAL) << "fstat failed";
34 }
35
36 return st.st_ino;
37 }
38
39 struct CmsgTest : ::testing::TestWithParam<bool> {
SeqpacketCmsgTest40 bool Seqpacket() { return GetParam(); }
41
SetUpCmsgTest42 void SetUp() override {
43 ASSERT_TRUE(
44 android::base::Socketpair(Seqpacket() ? SOCK_SEQPACKET : SOCK_STREAM, &send, &recv));
45 int dup1 = dup(tmp1.fd);
46 ASSERT_NE(-1, dup1);
47 int dup2 = dup(tmp2.fd);
48 ASSERT_NE(-1, dup2);
49
50 fd1.reset(dup1);
51 fd2.reset(dup2);
52
53 ino1 = GetInode(dup1);
54 ino2 = GetInode(dup2);
55 }
56
57 unique_fd send;
58 unique_fd recv;
59
60 TemporaryFile tmp1;
61 TemporaryFile tmp2;
62
63 unique_fd fd1;
64 unique_fd fd2;
65
66 ino_t ino1;
67 ino_t ino2;
68 };
69
TEST_P(CmsgTest,smoke)70 TEST_P(CmsgTest, smoke) {
71 ASSERT_EQ(1, SendFileDescriptors(send.get(), "x", 1, fd1.get()));
72
73 char buf[2];
74 unique_fd received;
75 ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 2, &received));
76 ASSERT_EQ('x', buf[0]);
77 ASSERT_NE(-1, received.get());
78
79 ASSERT_EQ(ino1, GetInode(received.get()));
80 }
81
TEST_P(CmsgTest,msg_trunc)82 TEST_P(CmsgTest, msg_trunc) {
83 ASSERT_EQ(2, SendFileDescriptors(send.get(), "ab", 2, fd1.get(), fd2.get()));
84
85 char buf[2];
86 unique_fd received1, received2;
87
88 ssize_t rc = ReceiveFileDescriptors(recv.get(), buf, 1, &received1, &received2);
89 if (Seqpacket()) {
90 ASSERT_EQ(-1, rc);
91 ASSERT_EQ(EMSGSIZE, errno);
92 ASSERT_EQ(-1, received1.get());
93 ASSERT_EQ(-1, received2.get());
94 } else {
95 ASSERT_EQ(1, rc);
96 ASSERT_NE(-1, received1.get());
97 ASSERT_NE(-1, received2.get());
98 ASSERT_EQ(ino1, GetInode(received1.get()));
99 ASSERT_EQ(ino2, GetInode(received2.get()));
100 ASSERT_EQ(1, read(recv.get(), buf, 2));
101 }
102 }
103
TEST_P(CmsgTest,msg_ctrunc)104 TEST_P(CmsgTest, msg_ctrunc) {
105 ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get(), fd2.get()));
106
107 char buf[2];
108 unique_fd received;
109 ASSERT_EQ(-1, ReceiveFileDescriptors(recv.get(), buf, 1, &received));
110 ASSERT_EQ(EMSGSIZE, errno);
111 ASSERT_EQ(-1, received.get());
112 }
113
TEST_P(CmsgTest,peek)114 TEST_P(CmsgTest, peek) {
115 ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get()));
116
117 char buf[2];
118 ASSERT_EQ(1, ::recv(recv.get(), buf, sizeof(buf), MSG_PEEK));
119 ASSERT_EQ('a', buf[0]);
120
121 unique_fd received;
122 ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received));
123 ASSERT_EQ(ino1, GetInode(received.get()));
124 }
125
TEST_P(CmsgTest,stream_fd_association)126 TEST_P(CmsgTest, stream_fd_association) {
127 if (Seqpacket()) {
128 return;
129 }
130
131 // fds are associated with the first byte of the write.
132 ASSERT_EQ(1, TEMP_FAILURE_RETRY(write(send.get(), "a", 1)));
133 ASSERT_EQ(2, SendFileDescriptors(send.get(), "bc", 2, fd1.get()));
134 ASSERT_EQ(1, SendFileDescriptors(send.get(), "d", 1, fd2.get()));
135 char buf[2];
136 ASSERT_EQ(2, TEMP_FAILURE_RETRY(read(recv.get(), buf, 2)));
137 ASSERT_EQ(0, memcmp(buf, "ab", 2));
138
139 std::vector<unique_fd> received1;
140 ssize_t rc = ReceiveFileDescriptorVector(recv.get(), buf, 1, 1, &received1);
141 ASSERT_EQ(1, rc);
142 ASSERT_EQ('c', buf[0]);
143 ASSERT_TRUE(received1.empty());
144
145 unique_fd received2;
146 rc = ReceiveFileDescriptors(recv.get(), buf, 1, &received2);
147 ASSERT_EQ(1, rc);
148 ASSERT_EQ('d', buf[0]);
149 ASSERT_EQ(ino2, GetInode(received2.get()));
150 }
151
TEST_P(CmsgTest,multiple_fd_ordering)152 TEST_P(CmsgTest, multiple_fd_ordering) {
153 ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get(), fd2.get()));
154
155 char buf[2];
156 unique_fd received1, received2;
157 ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received1, &received2));
158
159 ASSERT_NE(-1, received1.get());
160 ASSERT_NE(-1, received2.get());
161
162 ASSERT_EQ(ino1, GetInode(received1.get()));
163 ASSERT_EQ(ino2, GetInode(received2.get()));
164 }
165
TEST_P(CmsgTest,separate_fd_ordering)166 TEST_P(CmsgTest, separate_fd_ordering) {
167 ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get()));
168 ASSERT_EQ(1, SendFileDescriptors(send.get(), "b", 1, fd2.get()));
169
170 char buf[2];
171 unique_fd received1, received2;
172 ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received1));
173 ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received2));
174
175 ASSERT_NE(-1, received1.get());
176 ASSERT_NE(-1, received2.get());
177
178 ASSERT_EQ(ino1, GetInode(received1.get()));
179 ASSERT_EQ(ino2, GetInode(received2.get()));
180 }
181
TEST_P(CmsgTest,separate_fds_no_coalescing)182 TEST_P(CmsgTest, separate_fds_no_coalescing) {
183 unique_fd sent1(dup(tmp1.fd));
184 unique_fd sent2(dup(tmp2.fd));
185
186 ASSERT_EQ(1, SendFileDescriptors(send.get(), "", 1, fd1.get()));
187 ASSERT_EQ(1, SendFileDescriptors(send.get(), "", 1, fd2.get()));
188
189 char buf[2];
190 std::vector<unique_fd> received;
191 ASSERT_EQ(1, ReceiveFileDescriptorVector(recv.get(), buf, 2, 2, &received));
192 ASSERT_EQ(1U, received.size());
193 ASSERT_EQ(ino1, GetInode(received[0].get()));
194
195 ASSERT_EQ(1, ReceiveFileDescriptorVector(recv.get(), buf, 2, 2, &received));
196 ASSERT_EQ(1U, received.size());
197 ASSERT_EQ(ino2, GetInode(received[0].get()));
198 }
199
200 INSTANTIATE_TEST_CASE_P(CmsgTest, CmsgTest, testing::Bool());
201
202 #endif
203