2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2019 The FreeBSD Foundation
6 * This software was developed by BFF Storage Systems, LLC under sponsorship
7 * from the FreeBSD Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/types.h>
33 #include <sys/socket.h>
41 using namespace testing;
43 const char FULLPATH[] = "mountpoint/some_fifo";
44 const char RELPATH[] = "some_fifo";
45 const char MESSAGE[] = "Hello, World!\n";
46 const int msgsize = sizeof(MESSAGE);
48 class Fifo: public FuseTest {
52 Fifo(): m_child(NULL) {};
55 if (m_child != NULL) {
56 pthread_join(m_child, NULL);
62 class Socket: public Fifo {};
65 static void* writer(void* arg) {
70 while (sent < msgsize) {
73 r = write(fd, MESSAGE + sent, msgsize - sent);
75 return (void*)(intptr_t)errno;
84 * Reading and writing FIFOs works. None of the I/O actually goes through FUSE
86 TEST_F(Fifo, read_write)
88 mode_t mode = S_IFIFO | 0755;
89 const int bufsize = 80;
90 char message[bufsize];
95 expect_lookup(RELPATH, ino, mode, 0, 1);
97 fd = open(FULLPATH, O_RDWR);
98 ASSERT_LE(0, fd) << strerror(errno);
99 ASSERT_EQ(0, pthread_create(&m_child, NULL, writer, &fd))
101 while (recvd < msgsize) {
102 r = read(fd, message + recvd, bufsize - recvd);
103 ASSERT_LE(0, r) << strerror(errno);
104 ASSERT_LT(0, r) << "unexpected EOF";
107 ASSERT_STREQ(message, MESSAGE);
109 /* Deliberately leak fd */
113 static void* socket_writer(void* arg __unused) {
116 struct sockaddr_un sa;
118 fd = socket(AF_UNIX, SOCK_STREAM, 0);
121 return (void*)(intptr_t)errno;
123 sa.sun_family = AF_UNIX;
124 strlcpy(sa.sun_path, FULLPATH, sizeof(sa.sun_path));
125 err = connect(fd, (struct sockaddr*)&sa, sizeof(sa));
128 return (void*)(intptr_t)errno;
131 while (sent < msgsize) {
134 r = write(fd, MESSAGE + sent, msgsize - sent);
136 return (void*)(intptr_t)errno;
145 * Reading and writing unix-domain sockets works. None of the I/O actually
148 TEST_F(Socket, read_write)
150 mode_t mode = S_IFSOCK | 0755;
151 const int bufsize = 80;
152 char message[bufsize];
153 struct sockaddr_un sa;
154 ssize_t recvd = 0, r;
159 EXPECT_LOOKUP(1, RELPATH).WillOnce(Invoke(ReturnErrno(ENOENT)));
160 EXPECT_CALL(*m_mock, process(
161 ResultOf([=](auto in) {
162 return (in->header.opcode == FUSE_CREATE);
166 .WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
167 SET_OUT_HEADER_LEN(out, create);
168 out->body.create.entry.attr.mode = mode;
169 out->body.create.entry.nodeid = ino;
170 out->body.create.entry.entry_valid = UINT64_MAX;
171 out->body.create.entry.attr_valid = UINT64_MAX;
173 EXPECT_LOOKUP(1, RELPATH)
175 .WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto out) {
176 SET_OUT_HEADER_LEN(out, entry);
177 out->body.entry.attr.mode = mode;
178 out->body.entry.nodeid = ino;
179 out->body.entry.attr.nlink = 1;
180 out->body.entry.attr_valid = UINT64_MAX;
181 out->body.entry.entry_valid = UINT64_MAX;
184 fd = socket(AF_UNIX, SOCK_STREAM, 0);
185 ASSERT_LE(0, fd) << strerror(errno);
186 sa.sun_family = AF_UNIX;
187 strlcpy(sa.sun_path, FULLPATH, sizeof(sa.sun_path));
188 ASSERT_EQ(0, bind(fd, (struct sockaddr*)&sa, sizeof(sa)))
191 ASSERT_EQ(0, pthread_create(&m_child, NULL, socket_writer, NULL))
193 connected = accept(fd, 0, 0);
194 ASSERT_LE(0, connected) << strerror(errno);
196 while (recvd < msgsize) {
197 r = read(connected, message + recvd, bufsize - recvd);
198 ASSERT_LE(0, r) << strerror(errno);
199 ASSERT_LT(0, r) << "unexpected EOF";
202 ASSERT_STREQ(message, MESSAGE);
204 /* Deliberately leak fd */