]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/tests/unit/unix_domain_test.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / seastar / tests / unit / unix_domain_test.cc
1 /*
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.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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
16 * under the License.
17 */
18 /*
19 * Copyright (C) 2019 Red Hat, Inc.
20 */
21
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>
31
32 using namespace seastar;
33 using std::string;
34 using namespace std::string_literals;
35 using namespace std::chrono_literals;
36
37 static logger iplog("unix_domain");
38
39 class ud_server_client {
40 public:
41 ud_server_client(string server_path, std::optional<string> client_path, int rounds) :
42 ud_server_client(server_path, client_path, rounds, 0) {};
43
44 ud_server_client(string server_path, std::optional<string> client_path, int rounds,
45 int abort_run) :
46 server_addr{unix_domain_addr{server_path}}, client_path{client_path},
47 rounds{rounds},
48 rounds_left{rounds}, abort_after{abort_run} {}
49
50 future<> run();
51 ud_server_client(ud_server_client&&) = default;
52 ud_server_client(const ud_server_client&) = delete;
53
54 private:
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;
59
60 const std::optional<string> client_path;
61 server_socket server;
62 const int rounds;
63 int rounds_left;
64 server_socket* lstn_sock;
65 seastar::thread th;
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
68 };
69
70 future<> ud_server_client::init_server() {
71 return do_with(seastar::listen(server_addr), [this](server_socket& lstn) mutable {
72
73 lstn_sock = &lstn; // required when aborting (on some tests)
74
75 // start the clients here, where we know the server is listening
76
77 th = seastar::thread([this]{
78 for (int i=0; i<rounds; ++i) {
79 if (abort_after) {
80 if (--abort_after == 0) {
81 planned_abort = true;
82 lstn_sock->abort_accept();
83 break;
84 }
85 }
86 (void)client_round().get0();
87 }
88 });
89
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);
94 --rounds_left;
95 // verify the client address
96 if (client_path) {
97 socket_address tmmp{unix_domain_addr{*client_path}};
98 BOOST_REQUIRE_EQUAL(cn_addr, socket_address{unix_domain_addr{*client_path}});
99 }
100
101 return do_with(cn.input(), cn.output(), [](auto& inp, auto& out) {
102
103 return inp.read().then([&out](auto bb) {
104 string ans = "-"s;
105 if (bb && bb.size()) {
106 ans = "+"s + string{bb.get(), bb.size()};
107 }
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<>(); });
112
113 }).then([]{ return make_ready_future<>();});
114 });
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);
119 }
120 }).finally([this]{
121 return th.join();
122 });
123 });
124 }
125
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();
132
133 return do_with(cc.input(), cc.output(), [this](auto& inp, auto& out) {
134
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);
140 return inp.close();
141 }).then([&out](){return out.close();}).then(
142 []{ return make_ready_future<>(); });
143 });
144
145 }
146
147 future<> ud_server_client::run() {
148 return async([this] {
149 auto serverfut = init_server();
150 (void)serverfut.get();
151 });
152
153 }
154
155 // testing the various address types, both on the server and on the
156 // client side
157
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){
162 return uds.run();
163 });
164 return make_ready_future<>();
165 }
166
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){
172 return uds.run();
173 });
174 //return make_ready_future<>();
175 }
176
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){
182 return uds.run();
183 });
184 }
185
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){
191 return uds.run();
192 });
193 }
194
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<>();
203 }
204
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){
209 return uds.run();
210 });
211 }
212
213 SEASTAR_TEST_CASE(unixdomain_short) {
214 system("rm -f 3");
215 ud_server_client uds("3"s, std::nullopt, 10);
216 return do_with(std::move(uds), [](auto& uds){
217 return uds.run();
218 });
219 }
220
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<>();
231 });
232 });
233 }
234