Files
scylladb/net/stack.cc
Avi Kivity 3def4bc7d7 tcp: queue connections being accepted
With the current listen() -> future<connection> interface, if a new connection
is established before the connection handler is able to re-register for the
port, we have to drop the connection.

Fix by adding a queue for accepted connections, and switching to the more
standard listen() -> accept() -> future<connection> model.
2014-09-14 16:05:48 +03:00

150 lines
4.9 KiB
C++

/*
* Copyright (C) 2014 Cloudius Systems, Ltd.
*/
#include "stack.hh"
#include "net.hh"
#include "ip.hh"
#include "tcp.hh"
#include "virtio.hh"
#include <memory>
#include <queue>
namespace net {
class native_network_stack;
template <typename Protocol>
class native_server_socket_impl;
template <typename Protocol>
class native_connected_socket_impl;
template <typename Protocol>
class native_connected_socket_impl : public connected_socket_impl {
typename Protocol::connection _conn;
class native_data_source_impl;
class native_data_sink_impl;
public:
explicit native_connected_socket_impl(typename Protocol::connection conn)
: _conn(std::move(conn)) {}
virtual input_stream<char> input() override;
virtual output_stream<char> output() override;
};
template <typename Protocol>
class native_server_socket_impl : public server_socket_impl {
typename Protocol::listener _listener;
public:
native_server_socket_impl(Protocol& proto, uint16_t port, listen_options opt);
virtual future<connected_socket, socket_address> accept() override;
};
class native_network_stack : public network_stack {
static std::unique_ptr<native_network_stack> _s;
interface _netif;
ipv4 _inet;
using tcp4 = tcp<ipv4_traits>;
public:
explicit native_network_stack(std::unique_ptr<device> dev);
explicit native_network_stack() : native_network_stack(create_virtio_net_device("tap0")) {}
virtual server_socket listen(socket_address sa, listen_options opt) override;
friend class native_server_socket_impl<tcp4>;
};
native_network_stack::native_network_stack(std::unique_ptr<device> dev)
: _netif(std::move(dev))
, _inet(&_netif) {
_netif.run();
_inet.set_host_address(ipv4_address("192.168.122.2"));
}
template <typename Protocol>
native_server_socket_impl<Protocol>::native_server_socket_impl(Protocol& proto, uint16_t port, listen_options opt)
: _listener(proto.listen(port)) {
}
template <typename Protocol>
future<connected_socket, socket_address>
native_server_socket_impl<Protocol>::accept() {
return _listener.accept().then([this] (typename Protocol::connection conn) {
return make_ready_future<connected_socket, socket_address>(
connected_socket(std::make_unique<native_connected_socket_impl<Protocol>>(std::move(conn))),
socket_address()); // FIXME: don't fake it
});
}
server_socket
native_network_stack::listen(socket_address sa, listen_options opts) {
assert(sa.as_posix_sockaddr().sa_family == AF_INET);
return server_socket(std::make_unique<native_server_socket_impl<tcp4>>(
_inet.get_tcp(), ntohs(sa.as_posix_sockaddr_in().sin_port), opts));
}
template <typename Protocol>
class native_connected_socket_impl<Protocol>::native_data_source_impl final
: public data_source_impl {
typename Protocol::connection& _conn;
size_t _cur_frag = 0;
bool _eof = false;
packet _buf;
public:
explicit native_data_source_impl(typename Protocol::connection& conn)
: _conn(conn) {}
virtual future<temporary_buffer<char>> get() override {
if (_eof) {
return make_ready_future<temporary_buffer<char>>(temporary_buffer<char>(0));
}
if (_cur_frag != _buf.fragments.size()) {
auto& f = _buf.fragments[_cur_frag++];
return make_ready_future<temporary_buffer<char>>(
temporary_buffer<char>(f.base, f.size,
make_deleter(nullptr, [p = _buf.share()] () mutable {})));
}
return _conn.wait_for_data().then([this] {
_buf = _conn.read();
_cur_frag = 0;
_eof = !_buf.len;
return get();
});
}
};
template <typename Protocol>
class native_connected_socket_impl<Protocol>::native_data_sink_impl final
: public data_sink_impl {
typename Protocol::connection& _conn;
public:
explicit native_data_sink_impl(typename Protocol::connection& conn)
: _conn(conn) {}
virtual future<> put(std::vector<temporary_buffer<char>> data) override {
std::vector<fragment> frags;
frags.reserve(data.size());
for (auto& e : data) {
frags.push_back(fragment{e.get_write(), e.size()});
}
return _conn.send(packet(std::move(frags), [tmp = std::move(data)] () mutable {}));
}
};
template <typename Protocol>
input_stream<char>
native_connected_socket_impl<Protocol>::input() {
data_source ds(std::make_unique<native_data_source_impl>(_conn));
return input_stream<char>(std::move(ds));
}
template <typename Protocol>
output_stream<char>
native_connected_socket_impl<Protocol>::output() {
data_sink ds(std::make_unique<native_data_sink_impl>(_conn));
return output_stream<char>(std::move(ds), 8192);
}
std::unique_ptr<native_network_stack> native_network_stack::_s;
network_stack_registrator<native_network_stack> nns_registrator{"native"};
}