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) 2014 Cloudius Systems, Ltd.
24 #include <seastar/net/stack.hh>
26 #include <seastar/net/inet_address.hh>
32 using namespace seastar;
34 template <typename Protocol>
35 class native_server_socket_impl;
37 template <typename Protocol>
38 class native_connected_socket_impl;
40 class native_network_stack;
42 // native_server_socket_impl
43 template <typename Protocol>
44 class native_server_socket_impl : public server_socket_impl {
45 typename Protocol::listener _listener;
47 native_server_socket_impl(Protocol& proto, uint16_t port, listen_options opt);
48 virtual future<accept_result> accept() override;
49 virtual void abort_accept() override;
50 virtual socket_address local_address() const override;
53 template <typename Protocol>
54 native_server_socket_impl<Protocol>::native_server_socket_impl(Protocol& proto, uint16_t port, listen_options opt)
55 : _listener(proto.listen(port)) {
58 template <typename Protocol>
60 native_server_socket_impl<Protocol>::accept() {
61 return _listener.accept().then([] (typename Protocol::connection conn) {
62 // Save "conn" contents before call below function
63 // "conn" is moved in 1st argument, and used in 2nd argument
64 // It causes trouble on Arm which passes arguments from left to right
65 auto ip = conn.foreign_ip().ip;
66 auto port = conn.foreign_port();
67 return make_ready_future<accept_result>(accept_result{
68 connected_socket(std::make_unique<native_connected_socket_impl<Protocol>>(make_lw_shared(std::move(conn)))),
69 make_ipv4_address(ip, port)});
73 template <typename Protocol>
75 native_server_socket_impl<Protocol>::abort_accept() {
76 _listener.abort_accept();
79 template <typename Protocol>
80 socket_address native_server_socket_impl<Protocol>::local_address() const {
81 return socket_address(_listener.get_tcp().inet().inet().host_address(), _listener.port());
84 // native_connected_socket_impl
85 template <typename Protocol>
86 class native_connected_socket_impl : public connected_socket_impl {
87 lw_shared_ptr<typename Protocol::connection> _conn;
88 class native_data_source_impl;
89 class native_data_sink_impl;
91 explicit native_connected_socket_impl(lw_shared_ptr<typename Protocol::connection> conn)
92 : _conn(std::move(conn)) {}
93 using connected_socket_impl::source;
94 virtual data_source source() override;
95 virtual data_sink sink() override;
96 virtual void shutdown_input() override;
97 virtual void shutdown_output() override;
98 virtual void set_nodelay(bool nodelay) override;
99 virtual bool get_nodelay() const override;
100 void set_keepalive(bool keepalive) override;
101 bool get_keepalive() const override;
102 void set_keepalive_parameters(const keepalive_params&) override;
103 keepalive_params get_keepalive_parameters() const override;
104 int get_sockopt(int level, int optname, void* data, size_t len) const override;
105 void set_sockopt(int level, int optname, const void* data, size_t len) override;
106 socket_address local_address() const noexcept override;
107 virtual future<> wait_input_shutdown() override;
110 template <typename Protocol>
111 class native_socket_impl final : public socket_impl {
113 lw_shared_ptr<typename Protocol::connection> _conn;
115 explicit native_socket_impl(Protocol& proto)
116 : _proto(proto), _conn(nullptr) { }
118 virtual future<connected_socket> connect(socket_address sa, socket_address local, transport proto = transport::TCP) override {
119 //TODO: implement SCTP
120 assert(proto == transport::TCP);
122 // FIXME: local is ignored since native stack does not support multiple IPs yet
123 assert(sa.as_posix_sockaddr().sa_family == AF_INET);
125 _conn = make_lw_shared<typename Protocol::connection>(_proto.connect(sa));
126 return _conn->connected().then([conn = _conn]() mutable {
127 auto csi = std::make_unique<native_connected_socket_impl<Protocol>>(std::move(conn));
128 return make_ready_future<connected_socket>(connected_socket(std::move(csi)));
132 virtual void set_reuseaddr(bool reuseaddr) override {
134 std::cerr << "Reuseaddr is not supported by native stack" << std::endl;
137 virtual bool get_reuseaddr() const override {
142 virtual void shutdown() override {
144 _conn->shutdown_connect();
149 template <typename Protocol>
150 class native_connected_socket_impl<Protocol>::native_data_source_impl final
151 : public data_source_impl {
152 typedef typename Protocol::connection connection_type;
153 lw_shared_ptr<connection_type> _conn;
154 size_t _cur_frag = 0;
158 explicit native_data_source_impl(lw_shared_ptr<connection_type> conn)
159 : _conn(std::move(conn)) {}
160 virtual future<temporary_buffer<char>> get() override {
162 return make_ready_future<temporary_buffer<char>>(temporary_buffer<char>(0));
164 if (_cur_frag != _buf.nr_frags()) {
165 auto& f = _buf.fragments()[_cur_frag++];
166 return make_ready_future<temporary_buffer<char>>(
167 temporary_buffer<char>(f.base, f.size,
168 make_deleter(deleter(), [p = _buf.share()] () mutable {})));
170 return _conn->wait_for_data().then([this] {
171 _buf = _conn->read();
177 future<> close() override {
178 _conn->close_write();
179 return make_ready_future<>();
183 template <typename Protocol>
184 class native_connected_socket_impl<Protocol>::native_data_sink_impl final
185 : public data_sink_impl {
186 typedef typename Protocol::connection connection_type;
187 lw_shared_ptr<connection_type> _conn;
189 explicit native_data_sink_impl(lw_shared_ptr<connection_type> conn)
190 : _conn(std::move(conn)) {}
191 using data_sink_impl::put;
192 virtual future<> put(packet p) override {
193 return _conn->send(std::move(p));
195 virtual future<> close() override {
196 _conn->close_write();
197 return make_ready_future<>();
201 template <typename Protocol>
202 data_source native_connected_socket_impl<Protocol>::source() {
203 return data_source(std::make_unique<native_data_source_impl>(_conn));
206 template <typename Protocol>
207 data_sink native_connected_socket_impl<Protocol>::sink() {
208 return data_sink(std::make_unique<native_data_sink_impl>(_conn));
211 template <typename Protocol>
213 native_connected_socket_impl<Protocol>::shutdown_input() {
217 template <typename Protocol>
219 native_connected_socket_impl<Protocol>::shutdown_output() {
220 _conn->close_write();
223 template <typename Protocol>
225 native_connected_socket_impl<Protocol>::set_nodelay(bool nodelay) {
229 template <typename Protocol>
231 native_connected_socket_impl<Protocol>::get_nodelay() const {
236 template <typename Protocol>
237 void native_connected_socket_impl<Protocol>::set_keepalive(bool keepalive) {
239 std::cerr << "Keepalive is not supported by native stack" << std::endl;
241 template <typename Protocol>
242 bool native_connected_socket_impl<Protocol>::get_keepalive() const {
247 template <typename Protocol>
248 void native_connected_socket_impl<Protocol>::set_keepalive_parameters(const keepalive_params&) {
250 std::cerr << "Keepalive parameters are not supported by native stack" << std::endl;
253 template <typename Protocol>
254 keepalive_params native_connected_socket_impl<Protocol>::get_keepalive_parameters() const {
256 return tcp_keepalive_params {std::chrono::seconds(0), std::chrono::seconds(0), 0};
259 template<typename Protocol>
260 void native_connected_socket_impl<Protocol>::set_sockopt(int level, int optname, const void* data, size_t len) {
261 throw std::runtime_error("Setting custom socket options is not supported for native stack");
264 template<typename Protocol>
265 int native_connected_socket_impl<Protocol>::get_sockopt(int level, int optname, void* data, size_t len) const {
266 throw std::runtime_error("Getting custom socket options is not supported for native stack");
269 template<typename Protocol>
270 socket_address native_connected_socket_impl<Protocol>::local_address() const noexcept {
271 return {_conn->local_ip(), _conn->local_port()};
274 template <typename Protocol>
275 future<> native_connected_socket_impl<Protocol>::wait_input_shutdown() {
276 return _conn->wait_input_shutdown();