2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
19 * Copyright (C) 2019 Red Hat, Inc.
22 #include <seastar/testing/test_case.hh>
23 #include <seastar/core/seastar.hh>
24 #include <seastar/net/api.hh>
25 #include <seastar/net/inet_address.hh>
26 #include <seastar/core/print.hh>
27 #include <seastar/core/reactor.hh>
28 #include <seastar/core/thread.hh>
29 #include <seastar/util/log.hh>
30 #include <seastar/util/std-compat.hh>
32 using namespace seastar
;
34 using namespace std::string_literals
;
35 using namespace std::chrono_literals
;
37 static logger
iplog("unix_domain");
39 class ud_server_client
{
41 ud_server_client(string server_path
, std::optional
<string
> client_path
, int rounds
) :
42 ud_server_client(server_path
, client_path
, rounds
, 0) {};
44 ud_server_client(string server_path
, std::optional
<string
> client_path
, int rounds
,
46 server_addr
{unix_domain_addr
{server_path
}}, client_path
{client_path
},
48 rounds_left
{rounds
}, abort_after
{abort_run
} {}
51 ud_server_client(ud_server_client
&&) = default;
52 ud_server_client(const ud_server_client
&) = delete;
55 const string test_message
{"are you still the same?"s
};
56 future
<> init_server();
57 future
<> client_round();
58 const socket_address server_addr
;
60 const std::optional
<string
> client_path
;
64 server_socket
* lstn_sock
;
66 int abort_after
; // if set - force the listening socket down after that number of rounds
67 bool planned_abort
{false}; // set when abort_accept() is called
70 future
<> ud_server_client::init_server() {
71 return do_with(seastar::listen(server_addr
), [this](server_socket
& lstn
) mutable {
73 lstn_sock
= &lstn
; // required when aborting (on some tests)
75 // start the clients here, where we know the server is listening
77 th
= seastar::thread([this]{
78 for (int i
=0; i
<rounds
; ++i
) {
80 if (--abort_after
== 0) {
82 lstn_sock
->abort_accept();
86 (void)client_round().get0();
90 return do_until([this](){return rounds_left
<=0;}, [&lstn
,this]() {
91 return lstn
.accept().then([this](accept_result from_accept
) {
92 connected_socket cn
= std::move(from_accept
.connection
);
93 socket_address cn_addr
= std::move(from_accept
.remote_address
);
95 // verify the client address
97 socket_address tmmp
{unix_domain_addr
{*client_path
}};
98 BOOST_REQUIRE_EQUAL(cn_addr
, socket_address
{unix_domain_addr
{*client_path
}});
101 return do_with(cn
.input(), cn
.output(), [](auto& inp
, auto& out
) {
103 return inp
.read().then([&out
](auto bb
) {
105 if (bb
&& bb
.size()) {
106 ans
= "+"s
+ string
{bb
.get(), bb
.size()};
108 return out
.write(ans
).then([&out
](){return out
.flush();}).
109 then([&out
](){return out
.close();});
110 }).then([&inp
]() { return inp
.close(); }).
111 then([]() { return make_ready_future
<>(); });
113 }).then([]{ return make_ready_future
<>();});
115 }).handle_exception([this](auto e
) {
116 // OK to get here only if the test was a "planned abort" one
117 if (!planned_abort
) {
118 std::rethrow_exception(e
);
126 /// Send a message to the server, and expect (almost) the same string back.
127 /// If 'client_path' is set, the client binds to the named path.
128 future
<> ud_server_client::client_round() {
129 auto cc
= client_path
?
130 engine().net().connect(server_addr
, socket_address
{unix_domain_addr
{*client_path
}}).get0() :
131 engine().net().connect(server_addr
).get0();
133 return do_with(cc
.input(), cc
.output(), [this](auto& inp
, auto& out
) {
135 return out
.write(test_message
).then(
136 [&out
](){ return out
.flush(); }).then(
137 [&inp
](){ return inp
.read(); }).then(
138 [this,&inp
](auto bb
){
139 BOOST_REQUIRE_EQUAL(std::string_view(bb
.begin(), bb
.size()), "+"s
+test_message
);
141 }).then([&out
](){return out
.close();}).then(
142 []{ return make_ready_future
<>(); });
147 future
<> ud_server_client::run() {
148 return async([this] {
149 auto serverfut
= init_server();
150 (void)serverfut
.get();
155 // testing the various address types, both on the server and on the
158 SEASTAR_TEST_CASE(unixdomain_server
) {
159 system("rm -f /tmp/ry");
160 ud_server_client
uds("/tmp/ry", std::nullopt
, 3);
161 return do_with(std::move(uds
), [](auto& uds
){
164 return make_ready_future
<>();
167 SEASTAR_TEST_CASE(unixdomain_abs
) {
168 char sv_name
[]{'\0', '1', '1', '1'};
169 //ud_server_client uds(string{"\0111",4}, string{"\0112",4}, 1);
170 ud_server_client
uds(string
{sv_name
,4}, std::nullopt
, 4);
171 return do_with(std::move(uds
), [](auto& uds
){
174 //return make_ready_future<>();
177 SEASTAR_TEST_CASE(unixdomain_abs_bind
) {
178 char sv_name
[]{'\0', '1', '1', '1'};
179 char cl_name
[]{'\0', '1', '1', '2'};
180 ud_server_client
uds(string
{sv_name
,4}, string
{cl_name
,4}, 1);
181 return do_with(std::move(uds
), [](auto& uds
){
186 SEASTAR_TEST_CASE(unixdomain_abs_bind_2
) {
187 char sv_name
[]{'\0', '1', '\0', '\12', '1'};
188 char cl_name
[]{'\0', '1', '\0', '\12', '2'};
189 ud_server_client
uds(string
{sv_name
,5}, string
{cl_name
,5}, 2);
190 return do_with(std::move(uds
), [](auto& uds
){
195 SEASTAR_TEST_CASE(unixdomain_text
) {
196 socket_address addr1
{unix_domain_addr
{"abc"}};
197 BOOST_REQUIRE_EQUAL(format("{}", addr1
), "abc");
198 socket_address addr2
{unix_domain_addr
{""}};
199 BOOST_REQUIRE_EQUAL(format("{}", addr2
), "{unnamed}");
200 socket_address addr3
{unix_domain_addr
{std::string("\0abc", 5)}};
201 BOOST_REQUIRE_EQUAL(format("{}", addr3
), "@abc_");
202 return make_ready_future
<>();
205 SEASTAR_TEST_CASE(unixdomain_bind
) {
206 system("rm -f 111 112");
207 ud_server_client
uds("111"s
, "112"s
, 1);
208 return do_with(std::move(uds
), [](auto& uds
){
213 SEASTAR_TEST_CASE(unixdomain_short
) {
215 ud_server_client
uds("3"s
, std::nullopt
, 10);
216 return do_with(std::move(uds
), [](auto& uds
){
221 // test our ability to abort the accept()'ing on a socket.
222 // The test covers a specific bug in the handling of abort_accept()
223 SEASTAR_TEST_CASE(unixdomain_abort
) {
224 std::string sockname
{"7"s
}; // note: no portable & warnings-free option
225 std::ignore
= ::unlink(sockname
.c_str());
226 ud_server_client
uds(sockname
, std::nullopt
, 10, 4);
227 return do_with(std::move(uds
), [sockname
](auto& uds
){
228 return uds
.run().finally([sockname
](){
229 std::ignore
= ::unlink(sockname
.c_str());
230 return seastar::make_ready_future
<>();