blob: a767d2314e4de7eaf3c6f1f84ca761391a0aa8c3 [file] [log] [blame]
Eric Newberrya98bf932015-09-21 00:58:47 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Eric Newberry0c841642018-01-17 15:01:00 -07002/*
Davide Pesavento4c957712024-01-01 15:40:06 -05003 * Copyright (c) 2014-2024, Regents of the University of California,
Eric Newberrya98bf932015-09-21 00:58:47 -07004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
Junxiao Shicde37ad2015-12-24 01:02:05 -070026#include "face/unix-stream-channel.hpp"
27
Davide Pesavento9a00fab2016-09-27 11:22:46 +020028#include "channel-fixture.hpp"
Eric Newberrya98bf932015-09-21 00:58:47 -070029
Spencer Lee75142a12016-04-13 16:55:10 -070030#include <boost/filesystem.hpp>
31#include <fstream>
32
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040033namespace nfd::tests {
Eric Newberrya98bf932015-09-21 00:58:47 -070034
Spencer Lee75142a12016-04-13 16:55:10 -070035namespace fs = boost::filesystem;
36namespace local = boost::asio::local;
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040037using face::UnixStreamChannel;
Junxiao Shicde37ad2015-12-24 01:02:05 -070038
Davide Pesavento9a00fab2016-09-27 11:22:46 +020039class UnixStreamChannelFixture : public ChannelFixture<UnixStreamChannel, unix_stream::Endpoint>
Spencer Lee75142a12016-04-13 16:55:10 -070040{
41protected:
42 UnixStreamChannelFixture()
Spencer Lee75142a12016-04-13 16:55:10 -070043 {
Davide Pesavento4c957712024-01-01 15:40:06 -050044 listenerEp = unix_stream::Endpoint(socketPath.string());
Davide Pesavento4b1921f2024-01-12 20:25:45 -050045
46 // in case an earlier test run crashed without a chance to run the destructor
47 boost::system::error_code ec;
48 fs::remove_all(testDir, ec);
49 }
50
51 ~UnixStreamChannelFixture() override
52 {
53 // cleanup
54 boost::system::error_code ec;
55 fs::remove_all(testDir, ec);
Spencer Lee75142a12016-04-13 16:55:10 -070056 }
57
Alexander Afanasyev3a2339a2020-05-27 23:05:06 -040058 shared_ptr<UnixStreamChannel>
Davide Pesavento9a00fab2016-09-27 11:22:46 +020059 makeChannel() final
Spencer Lee75142a12016-04-13 16:55:10 -070060 {
Alexander Afanasyev3a2339a2020-05-27 23:05:06 -040061 return std::make_shared<UnixStreamChannel>(listenerEp, false);
Spencer Lee75142a12016-04-13 16:55:10 -070062 }
63
64 void
65 listen()
66 {
67 listenerChannel = makeChannel();
68 listenerChannel->listen(
69 [this] (const shared_ptr<Face>& newFace) {
70 BOOST_REQUIRE(newFace != nullptr);
71 connectFaceClosedSignal(*newFace, [this] { limitedIo.afterOp(); });
72 listenerFaces.push_back(newFace);
73 limitedIo.afterOp();
74 },
Davide Pesavento9a00fab2016-09-27 11:22:46 +020075 ChannelFixture::unexpectedFailure);
Spencer Lee75142a12016-04-13 16:55:10 -070076 }
77
78 void
Davide Pesavento9a00fab2016-09-27 11:22:46 +020079 clientConnect(local::stream_protocol::socket& client)
Spencer Lee75142a12016-04-13 16:55:10 -070080 {
81 client.async_connect(listenerEp,
Davide Pesavento4c957712024-01-01 15:40:06 -050082 [this] (const auto& error) {
Spencer Lee75142a12016-04-13 16:55:10 -070083 BOOST_REQUIRE_EQUAL(error, boost::system::errc::success);
84 limitedIo.afterOp();
85 });
86 }
Davide Pesavento4c957712024-01-01 15:40:06 -050087
88protected:
Davide Pesavento4b1921f2024-01-12 20:25:45 -050089 fs::path testDir = fs::path(UNIT_TESTS_TMPDIR) / "unix-stream-channel";
90 fs::path socketPath = testDir / "test" / "foo.sock";
Spencer Lee75142a12016-04-13 16:55:10 -070091};
92
Davide Pesavento9a00fab2016-09-27 11:22:46 +020093BOOST_AUTO_TEST_SUITE(Face)
Spencer Lee75142a12016-04-13 16:55:10 -070094BOOST_FIXTURE_TEST_SUITE(TestUnixStreamChannel, UnixStreamChannelFixture)
95
Davide Pesavento9a00fab2016-09-27 11:22:46 +020096BOOST_AUTO_TEST_CASE(Uri)
97{
98 auto channel = makeChannel();
99 BOOST_CHECK_EQUAL(channel->getUri(), FaceUri(listenerEp));
100}
101
Spencer Lee75142a12016-04-13 16:55:10 -0700102BOOST_AUTO_TEST_CASE(Listen)
103{
104 auto channel = makeChannel();
105 BOOST_CHECK_EQUAL(channel->isListening(), false);
106
107 channel->listen(nullptr, nullptr);
108 BOOST_CHECK_EQUAL(channel->isListening(), true);
109
110 // listen() is idempotent
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500111 channel->listen(nullptr, nullptr);
Spencer Lee75142a12016-04-13 16:55:10 -0700112 BOOST_CHECK_EQUAL(channel->isListening(), true);
113}
114
115BOOST_AUTO_TEST_CASE(MultipleAccepts)
116{
117 this->listen();
118
119 BOOST_CHECK_EQUAL(listenerChannel->isListening(), true);
Davide Pesaventoc19408d2017-04-08 00:42:55 -0400120 BOOST_CHECK_EQUAL(listenerChannel->size(), 0);
Spencer Lee75142a12016-04-13 16:55:10 -0700121
122 local::stream_protocol::socket client1(g_io);
Davide Pesavento9a00fab2016-09-27 11:22:46 +0200123 this->clientConnect(client1);
Spencer Lee75142a12016-04-13 16:55:10 -0700124
Davide Pesavento14e71f02019-03-28 17:35:25 -0400125 BOOST_CHECK_EQUAL(limitedIo.run(2, 1_s), LimitedIo::EXCEED_OPS);
Davide Pesaventoc19408d2017-04-08 00:42:55 -0400126 BOOST_CHECK_EQUAL(listenerChannel->size(), 1);
Spencer Lee75142a12016-04-13 16:55:10 -0700127
128 local::stream_protocol::socket client2(g_io);
129 local::stream_protocol::socket client3(g_io);
Davide Pesavento9a00fab2016-09-27 11:22:46 +0200130 this->clientConnect(client2);
131 this->clientConnect(client3);
Spencer Lee75142a12016-04-13 16:55:10 -0700132
Davide Pesavento14e71f02019-03-28 17:35:25 -0400133 BOOST_CHECK_EQUAL(limitedIo.run(4, 1_s), LimitedIo::EXCEED_OPS);
Davide Pesaventoc19408d2017-04-08 00:42:55 -0400134 BOOST_CHECK_EQUAL(listenerChannel->size(), 3);
Spencer Lee75142a12016-04-13 16:55:10 -0700135 BOOST_CHECK_EQUAL(listenerFaces.size(), 3);
136
Alexander Afanasyev3a2339a2020-05-27 23:05:06 -0400137 // check face persistency and channel association
Spencer Lee75142a12016-04-13 16:55:10 -0700138 for (const auto& face : listenerFaces) {
139 BOOST_CHECK_EQUAL(face->getPersistency(), ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
Alexander Afanasyev3a2339a2020-05-27 23:05:06 -0400140 BOOST_CHECK_EQUAL(face->getChannel().lock(), listenerChannel);
Spencer Lee75142a12016-04-13 16:55:10 -0700141 }
142}
143
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500144BOOST_AUTO_TEST_SUITE(SocketFile)
145
146BOOST_AUTO_TEST_CASE(CreateAndRemove)
Spencer Lee75142a12016-04-13 16:55:10 -0700147{
Spencer Lee75142a12016-04-13 16:55:10 -0700148 auto channel = makeChannel();
149 BOOST_CHECK_EQUAL(fs::symlink_status(socketPath).type(), fs::file_not_found);
150
151 channel->listen(nullptr, nullptr);
152 auto status = fs::symlink_status(socketPath);
153 BOOST_CHECK_EQUAL(status.type(), fs::socket_file);
154 BOOST_CHECK_EQUAL(status.permissions(), fs::owner_read | fs::group_read | fs::others_read |
155 fs::owner_write | fs::group_write | fs::others_write);
156
157 channel.reset();
158 BOOST_CHECK_EQUAL(fs::symlink_status(socketPath).type(), fs::file_not_found);
159}
160
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500161BOOST_AUTO_TEST_CASE(InUse)
Spencer Lee75142a12016-04-13 16:55:10 -0700162{
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500163 auto channel = makeChannel();
Davide Pesavento4c957712024-01-01 15:40:06 -0500164 fs::create_directories(socketPath.parent_path());
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500165
Spencer Lee75142a12016-04-13 16:55:10 -0700166 local::stream_protocol::acceptor acceptor(g_io, listenerEp);
Spencer Lee75142a12016-04-13 16:55:10 -0700167 BOOST_CHECK_EQUAL(fs::symlink_status(socketPath).type(), fs::socket_file);
168
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500169 BOOST_CHECK_EXCEPTION(channel->listen(nullptr, nullptr), fs::filesystem_error, [&] (const auto& e) {
170 return e.code() == boost::system::errc::address_in_use &&
171 e.path1() == socketPath &&
172 std::string_view(e.what()).find("UnixStreamChannel::listen") != std::string_view::npos;
173 });
174}
Davide Pesavento4c957712024-01-01 15:40:06 -0500175
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500176BOOST_AUTO_TEST_CASE(Stale)
177{
178 auto channel = makeChannel();
179 fs::create_directories(socketPath.parent_path());
180
181 local::stream_protocol::acceptor acceptor(g_io, listenerEp);
Davide Pesavento4c957712024-01-01 15:40:06 -0500182 acceptor.close();
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500183 // the socket file is not removed when the acceptor is closed
Davide Pesavento4c957712024-01-01 15:40:06 -0500184 BOOST_CHECK_EQUAL(fs::symlink_status(socketPath).type(), fs::socket_file);
185
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500186 // drop write permission from the parent directory
187 fs::permissions(socketPath.parent_path(), fs::owner_all & ~fs::owner_write);
188 // removal of the "stale" socket fails due to insufficient permissions
189 BOOST_CHECK_EXCEPTION(channel->listen(nullptr, nullptr), fs::filesystem_error, [&] (const auto& e) {
190 return e.code() == boost::system::errc::permission_denied &&
191 e.path1() == socketPath &&
192 std::string_view(e.what()).find("remove") != std::string_view::npos;
193 });
194 BOOST_CHECK_EQUAL(fs::symlink_status(socketPath).type(), fs::socket_file);
195
196 // restore all permissions
197 fs::permissions(socketPath.parent_path(), fs::owner_all);
198 // the socket file should be considered "stale" and overwritten
199 channel->listen(nullptr, nullptr);
Spencer Lee75142a12016-04-13 16:55:10 -0700200 BOOST_CHECK_EQUAL(fs::symlink_status(socketPath).type(), fs::socket_file);
201}
202
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500203BOOST_AUTO_TEST_CASE(NotASocket)
Spencer Lee75142a12016-04-13 16:55:10 -0700204{
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500205 auto channel = makeChannel();
Spencer Lee75142a12016-04-13 16:55:10 -0700206
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500207 fs::create_directories(socketPath);
208 BOOST_CHECK_EQUAL(fs::symlink_status(socketPath).type(), fs::directory_file);
209 BOOST_CHECK_EXCEPTION(channel->listen(nullptr, nullptr), fs::filesystem_error, [&] (const auto& e) {
210 return e.code() == boost::system::errc::not_a_socket &&
211 e.path1() == socketPath &&
212 std::string_view(e.what()).find("UnixStreamChannel::listen") != std::string_view::npos;
213 });
214
215 fs::remove(socketPath);
Davide Pesavento4c957712024-01-01 15:40:06 -0500216 std::ofstream f(socketPath.string());
Spencer Lee75142a12016-04-13 16:55:10 -0700217 f.close();
Davide Pesavento4c957712024-01-01 15:40:06 -0500218 BOOST_CHECK_EQUAL(fs::symlink_status(socketPath).type(), fs::regular_file);
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500219 BOOST_CHECK_EXCEPTION(channel->listen(nullptr, nullptr), fs::filesystem_error, [&] (const auto& e) {
220 return e.code() == boost::system::errc::not_a_socket &&
221 e.path1() == socketPath &&
222 std::string_view(e.what()).find("UnixStreamChannel::listen") != std::string_view::npos;
223 });
Spencer Lee75142a12016-04-13 16:55:10 -0700224}
Junxiao Shicde37ad2015-12-24 01:02:05 -0700225
Davide Pesavento4b1921f2024-01-12 20:25:45 -0500226BOOST_AUTO_TEST_CASE(ParentConflict)
227{
228 auto channel = makeChannel();
229 fs::create_directories(testDir);
230
231 auto parent = socketPath.parent_path();
232 std::ofstream f(parent.string());
233 f.close();
234 BOOST_CHECK_EQUAL(fs::symlink_status(parent).type(), fs::regular_file);
235 BOOST_CHECK_EXCEPTION(channel->listen(nullptr, nullptr), fs::filesystem_error, [&] (const auto& e) {
236 return e.code() == boost::system::errc::file_exists &&
237 e.path1() == parent &&
238 std::string_view(e.what()).find("create_dir") != std::string_view::npos;
239 });
240}
241
242BOOST_AUTO_TEST_CASE(PermissionDenied)
243{
244 auto channel = makeChannel();
245 fs::create_directories(testDir);
246
247 fs::permissions(testDir, fs::no_perms);
248 BOOST_CHECK_EXCEPTION(channel->listen(nullptr, nullptr), fs::filesystem_error, [&] (const auto& e) {
249 return e.code() == boost::system::errc::permission_denied &&
250 e.path1() == socketPath.parent_path() &&
251 std::string_view(e.what()).find("create_dir") != std::string_view::npos;
252 });
253
254 fs::permissions(testDir, fs::owner_read | fs::owner_exe);
255 BOOST_CHECK_EXCEPTION(channel->listen(nullptr, nullptr), fs::filesystem_error, [&] (const auto& e) {
256 return e.code() == boost::system::errc::permission_denied &&
257 e.path1() == socketPath.parent_path() &&
258 std::string_view(e.what()).find("create_dir") != std::string_view::npos;
259 });
260
261 fs::permissions(testDir, fs::owner_all);
262 fs::create_directories(socketPath.parent_path());
263
264 fs::permissions(socketPath.parent_path(), fs::no_perms);
265 BOOST_CHECK_EXCEPTION(channel->listen(nullptr, nullptr), fs::filesystem_error, [&] (const auto& e) {
266 return e.code() == boost::system::errc::permission_denied &&
267 e.path1() == socketPath &&
268 std::string_view(e.what()).find("status") != std::string_view::npos;
269 });
270
271 fs::permissions(socketPath.parent_path(), fs::owner_read | fs::owner_exe);
272 BOOST_CHECK_EXCEPTION(channel->listen(nullptr, nullptr), fs::filesystem_error, [&] (const auto& e) {
273 return e.code() == boost::system::errc::permission_denied &&
274 e.path1() == socketPath &&
275 std::string_view(e.what()).find("bind") != std::string_view::npos;
276 });
277
278 fs::permissions(socketPath.parent_path(), fs::owner_all);
279}
280
281BOOST_AUTO_TEST_SUITE_END() // SocketFile
282
Junxiao Shicde37ad2015-12-24 01:02:05 -0700283BOOST_AUTO_TEST_SUITE_END() // TestUnixStreamChannel
284BOOST_AUTO_TEST_SUITE_END() // Face
285
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400286} // namespace nfd::tests