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