xref: /freebsd-src/tests/sys/fs/fusefs/fifo.cc (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1f9b0e30bSAlan Somers /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3f9b0e30bSAlan Somers  *
4f9b0e30bSAlan Somers  * Copyright (c) 2019 The FreeBSD Foundation
5f9b0e30bSAlan Somers  *
6f9b0e30bSAlan Somers  * This software was developed by BFF Storage Systems, LLC under sponsorship
7f9b0e30bSAlan Somers  * from the FreeBSD Foundation.
8f9b0e30bSAlan Somers  *
9f9b0e30bSAlan Somers  * Redistribution and use in source and binary forms, with or without
10f9b0e30bSAlan Somers  * modification, are permitted provided that the following conditions
11f9b0e30bSAlan Somers  * are met:
12f9b0e30bSAlan Somers  * 1. Redistributions of source code must retain the above copyright
13f9b0e30bSAlan Somers  *    notice, this list of conditions and the following disclaimer.
14f9b0e30bSAlan Somers  * 2. Redistributions in binary form must reproduce the above copyright
15f9b0e30bSAlan Somers  *    notice, this list of conditions and the following disclaimer in the
16f9b0e30bSAlan Somers  *    documentation and/or other materials provided with the distribution.
17f9b0e30bSAlan Somers  *
18f9b0e30bSAlan Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19f9b0e30bSAlan Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20f9b0e30bSAlan Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21f9b0e30bSAlan Somers  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22f9b0e30bSAlan Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23f9b0e30bSAlan Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24f9b0e30bSAlan Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25f9b0e30bSAlan Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26f9b0e30bSAlan Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27f9b0e30bSAlan Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28f9b0e30bSAlan Somers  * SUCH DAMAGE.
29f9b0e30bSAlan Somers  */
30f9b0e30bSAlan Somers 
31f9b0e30bSAlan Somers extern "C" {
32f9b0e30bSAlan Somers #include <sys/types.h>
33ede571e4SAlan Somers #include <sys/socket.h>
34ede571e4SAlan Somers #include <sys/un.h>
35f9b0e30bSAlan Somers #include <fcntl.h>
36f9b0e30bSAlan Somers }
37f9b0e30bSAlan Somers 
38f9b0e30bSAlan Somers #include "mockfs.hh"
39f9b0e30bSAlan Somers #include "utils.hh"
40f9b0e30bSAlan Somers 
41f9b0e30bSAlan Somers using namespace testing;
42f9b0e30bSAlan Somers 
43f9b0e30bSAlan Somers const char FULLPATH[] = "mountpoint/some_fifo";
44f9b0e30bSAlan Somers const char RELPATH[] = "some_fifo";
45f9b0e30bSAlan Somers const char MESSAGE[] = "Hello, World!\n";
46f9b0e30bSAlan Somers const int msgsize = sizeof(MESSAGE);
47f9b0e30bSAlan Somers 
48f9b0e30bSAlan Somers class Fifo: public FuseTest {
49ede571e4SAlan Somers public:
50ede571e4SAlan Somers pthread_t m_child;
51ede571e4SAlan Somers 
Fifo()52ede571e4SAlan Somers Fifo(): m_child(NULL) {};
53ede571e4SAlan Somers 
TearDown()54ede571e4SAlan Somers void TearDown() {
55ede571e4SAlan Somers 	if (m_child != NULL) {
56ede571e4SAlan Somers 		pthread_join(m_child, NULL);
57ede571e4SAlan Somers 	}
58ede571e4SAlan Somers 	FuseTest::TearDown();
59ede571e4SAlan Somers }
60f9b0e30bSAlan Somers };
61f9b0e30bSAlan Somers 
62ede571e4SAlan Somers class Socket: public Fifo {};
63ede571e4SAlan Somers 
64f9b0e30bSAlan Somers /* Writer thread */
writer(void * arg)65f9b0e30bSAlan Somers static void* writer(void* arg) {
66f9b0e30bSAlan Somers 	ssize_t sent = 0;
67f9b0e30bSAlan Somers 	int fd;
68f9b0e30bSAlan Somers 
69f9b0e30bSAlan Somers 	fd = *(int*)arg;
70f9b0e30bSAlan Somers 	while (sent < msgsize) {
71f9b0e30bSAlan Somers 		ssize_t r;
72f9b0e30bSAlan Somers 
73f9b0e30bSAlan Somers 		r = write(fd, MESSAGE + sent, msgsize - sent);
74f9b0e30bSAlan Somers 		if (r < 0)
75f9b0e30bSAlan Somers 			return (void*)(intptr_t)errno;
76f9b0e30bSAlan Somers 		else
77f9b0e30bSAlan Somers 			sent += r;
78f9b0e30bSAlan Somers 
79f9b0e30bSAlan Somers 	}
80f9b0e30bSAlan Somers 	return 0;
81f9b0e30bSAlan Somers }
82f9b0e30bSAlan Somers 
83f9b0e30bSAlan Somers /*
84f9b0e30bSAlan Somers  * Reading and writing FIFOs works.  None of the I/O actually goes through FUSE
85f9b0e30bSAlan Somers  */
TEST_F(Fifo,read_write)86f9b0e30bSAlan Somers TEST_F(Fifo, read_write)
87f9b0e30bSAlan Somers {
88f9b0e30bSAlan Somers 	mode_t mode = S_IFIFO | 0755;
89f9b0e30bSAlan Somers 	const int bufsize = 80;
90f9b0e30bSAlan Somers 	char message[bufsize];
91f9b0e30bSAlan Somers 	ssize_t recvd = 0, r;
92f9b0e30bSAlan Somers 	uint64_t ino = 42;
93f9b0e30bSAlan Somers 	int fd;
94f9b0e30bSAlan Somers 
95f9b0e30bSAlan Somers 	expect_lookup(RELPATH, ino, mode, 0, 1);
96f9b0e30bSAlan Somers 
97f9b0e30bSAlan Somers 	fd = open(FULLPATH, O_RDWR);
98f9b0e30bSAlan Somers 	ASSERT_LE(0, fd) << strerror(errno);
99ede571e4SAlan Somers 	ASSERT_EQ(0, pthread_create(&m_child, NULL, writer, &fd))
100f9b0e30bSAlan Somers 		<< strerror(errno);
101f9b0e30bSAlan Somers 	while (recvd < msgsize) {
102f9b0e30bSAlan Somers 		r = read(fd, message + recvd, bufsize - recvd);
103f9b0e30bSAlan Somers 		ASSERT_LE(0, r) << strerror(errno);
104f9b0e30bSAlan Somers 		ASSERT_LT(0, r) << "unexpected EOF";
105f9b0e30bSAlan Somers 		recvd += r;
106f9b0e30bSAlan Somers 	}
107f9b0e30bSAlan Somers 	ASSERT_STREQ(message, MESSAGE);
108f9b0e30bSAlan Somers 
1097fc0921dSAlan Somers 	leak(fd);
110f9b0e30bSAlan Somers }
111ede571e4SAlan Somers 
112ede571e4SAlan Somers /* Writer thread */
socket_writer(void * arg __unused)113ede571e4SAlan Somers static void* socket_writer(void* arg __unused) {
114ede571e4SAlan Somers 	ssize_t sent = 0;
115ede571e4SAlan Somers 	int fd, err;
116ede571e4SAlan Somers 	struct sockaddr_un sa;
117ede571e4SAlan Somers 
118ede571e4SAlan Somers 	fd = socket(AF_UNIX, SOCK_STREAM, 0);
119ede571e4SAlan Somers 	if (fd < 0) {
120ede571e4SAlan Somers 		perror("socket");
121ede571e4SAlan Somers 		return (void*)(intptr_t)errno;
122ede571e4SAlan Somers 	}
123ede571e4SAlan Somers 	sa.sun_family = AF_UNIX;
124ede571e4SAlan Somers 	strlcpy(sa.sun_path, FULLPATH, sizeof(sa.sun_path));
1258e765737SAlan Somers 	sa.sun_len = sizeof(FULLPATH);
126ede571e4SAlan Somers 	err = connect(fd, (struct sockaddr*)&sa, sizeof(sa));
127ede571e4SAlan Somers 	if (err < 0) {
128ede571e4SAlan Somers 		perror("connect");
129ede571e4SAlan Somers 		return (void*)(intptr_t)errno;
130ede571e4SAlan Somers 	}
131ede571e4SAlan Somers 
132ede571e4SAlan Somers 	while (sent < msgsize) {
133ede571e4SAlan Somers 		ssize_t r;
134ede571e4SAlan Somers 
135ede571e4SAlan Somers 		r = write(fd, MESSAGE + sent, msgsize - sent);
136ede571e4SAlan Somers 		if (r < 0)
137ede571e4SAlan Somers 			return (void*)(intptr_t)errno;
138ede571e4SAlan Somers 		else
139ede571e4SAlan Somers 			sent += r;
140ede571e4SAlan Somers 
141ede571e4SAlan Somers 	}
1428e765737SAlan Somers 
1438e765737SAlan Somers 	FuseTest::leak(fd);
144ede571e4SAlan Somers 	return 0;
145ede571e4SAlan Somers }
146ede571e4SAlan Somers 
147ede571e4SAlan Somers /*
148ede571e4SAlan Somers  * Reading and writing unix-domain sockets works.  None of the I/O actually
149ede571e4SAlan Somers  * goes through FUSE.
150ede571e4SAlan Somers  */
TEST_F(Socket,read_write)151ede571e4SAlan Somers TEST_F(Socket, read_write)
152ede571e4SAlan Somers {
153ede571e4SAlan Somers 	mode_t mode = S_IFSOCK | 0755;
154ede571e4SAlan Somers 	const int bufsize = 80;
155ede571e4SAlan Somers 	char message[bufsize];
156ede571e4SAlan Somers 	struct sockaddr_un sa;
157ede571e4SAlan Somers 	ssize_t recvd = 0, r;
158ede571e4SAlan Somers 	uint64_t ino = 42;
159ede571e4SAlan Somers 	int fd, connected;
160ede571e4SAlan Somers 	Sequence seq;
161ede571e4SAlan Somers 
162a34cdd26SAlan Somers 	EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
163a34cdd26SAlan Somers 		.WillOnce(Invoke(ReturnErrno(ENOENT)));
164ede571e4SAlan Somers 	EXPECT_CALL(*m_mock, process(
165ede571e4SAlan Somers 		ResultOf([=](auto in) {
16629edc611SAlan Somers 			return (in.header.opcode == FUSE_MKNOD);
167ede571e4SAlan Somers 		}, Eq(true)),
168ede571e4SAlan Somers 		_)
169ede571e4SAlan Somers 	).InSequence(seq)
17029edc611SAlan Somers 	.WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
171d5ff2688SAlan Somers 		SET_OUT_HEADER_LEN(out, entry);
17229edc611SAlan Somers 		out.body.entry.attr.mode = mode;
17329edc611SAlan Somers 		out.body.entry.nodeid = ino;
17429edc611SAlan Somers 		out.body.entry.entry_valid = UINT64_MAX;
17529edc611SAlan Somers 		out.body.entry.attr_valid = UINT64_MAX;
176ede571e4SAlan Somers 	})));
177d5ff2688SAlan Somers 
178a34cdd26SAlan Somers 	EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
179ede571e4SAlan Somers 	.InSequence(seq)
18029edc611SAlan Somers 	.WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
181ede571e4SAlan Somers 		SET_OUT_HEADER_LEN(out, entry);
18229edc611SAlan Somers 		out.body.entry.attr.mode = mode;
18329edc611SAlan Somers 		out.body.entry.nodeid = ino;
18429edc611SAlan Somers 		out.body.entry.attr.nlink = 1;
18529edc611SAlan Somers 		out.body.entry.attr_valid = UINT64_MAX;
18629edc611SAlan Somers 		out.body.entry.entry_valid = UINT64_MAX;
187ede571e4SAlan Somers 	})));
188ede571e4SAlan Somers 
189ede571e4SAlan Somers 	fd = socket(AF_UNIX, SOCK_STREAM, 0);
190ede571e4SAlan Somers 	ASSERT_LE(0, fd) << strerror(errno);
191ede571e4SAlan Somers 	sa.sun_family = AF_UNIX;
192ede571e4SAlan Somers 	strlcpy(sa.sun_path, FULLPATH, sizeof(sa.sun_path));
1938e765737SAlan Somers 	sa.sun_len = sizeof(FULLPATH);
194ede571e4SAlan Somers 	ASSERT_EQ(0, bind(fd, (struct sockaddr*)&sa, sizeof(sa)))
195ede571e4SAlan Somers 		<< strerror(errno);
196ede571e4SAlan Somers 	listen(fd, 5);
197ede571e4SAlan Somers 	ASSERT_EQ(0, pthread_create(&m_child, NULL, socket_writer, NULL))
198ede571e4SAlan Somers 		<< strerror(errno);
199ede571e4SAlan Somers 	connected = accept(fd, 0, 0);
200ede571e4SAlan Somers 	ASSERT_LE(0, connected) << strerror(errno);
201ede571e4SAlan Somers 
202ede571e4SAlan Somers 	while (recvd < msgsize) {
203ede571e4SAlan Somers 		r = read(connected, message + recvd, bufsize - recvd);
204ede571e4SAlan Somers 		ASSERT_LE(0, r) << strerror(errno);
205ede571e4SAlan Somers 		ASSERT_LT(0, r) << "unexpected EOF";
206ede571e4SAlan Somers 		recvd += r;
207ede571e4SAlan Somers 	}
208ede571e4SAlan Somers 	ASSERT_STREQ(message, MESSAGE);
209ede571e4SAlan Somers 
2107fc0921dSAlan Somers 	leak(fd);
211ede571e4SAlan Somers }
212