Nexus HTTP/3
A QUIC and HTTP/3 library
socket_impl.hpp
1 #pragma once
2 
3 #include <boost/intrusive/list.hpp>
4 #include <boost/circular_buffer.hpp>
5 #include <nexus/ssl.hpp>
6 #include <nexus/quic/detail/connection_impl.hpp>
7 
8 struct lsquic_conn;
9 struct lsquic_out_spec;
10 
11 namespace nexus::quic::detail {
12 
13 struct engine_impl;
14 struct connection_impl;
15 
16 union sockaddr_union {
17  sockaddr_storage storage;
18  sockaddr addr;
19  sockaddr_in addr4;
20  sockaddr_in6 addr6;
21 };
22 
23 using connection_list = boost::intrusive::list<connection_impl>;
24 
25 inline void list_erase(connection_impl& s, connection_list& from)
26 {
27  from.erase(from.iterator_to(s));
28 }
29 
30 inline void list_transfer(connection_impl& s, connection_list& from,
31  connection_list& to)
32 {
33  from.erase(from.iterator_to(s));
34  to.push_back(s);
35 }
36 
37 struct socket_impl : boost::intrusive::list_base_hook<> {
38  engine_impl& engine;
39  udp::socket socket;
40  ssl::context& ssl;
41  udp::endpoint local_addr; // socket's bound address
42  boost::circular_buffer<incoming_connection> incoming_connections;
43  connection_list accepting_connections;
44  connection_list open_connections;
45  bool receiving = false;
46 
47  socket_impl(engine_impl& engine, udp::socket&& socket,
48  ssl::context& ssl);
49  socket_impl(engine_impl& engine, const udp::endpoint& endpoint,
50  bool is_server, ssl::context& ssl);
51  ~socket_impl() {
52  close();
53  }
54 
55  using executor_type = boost::asio::any_io_executor;
56  executor_type get_executor() const;
57 
58  udp::endpoint local_endpoint() const { return local_addr; }
59 
60  void listen(int backlog);
61 
62  void connect(connection_impl& c,
63  const udp::endpoint& endpoint,
64  const char* hostname);
65  void on_connect(connection_impl& c, lsquic_conn* conn);
66 
67  void accept(connection_impl& c, accept_operation& op);
68  connection_context* on_accept(lsquic_conn* conn);
69 
70  template <typename Connection, typename CompletionToken>
71  decltype(auto) async_accept(Connection& conn,
72  CompletionToken&& token) {
73  auto& c = conn.impl;
74  return boost::asio::async_initiate<CompletionToken, void(error_code)>(
75  [this, &c] (auto h) {
76  using Handler = std::decay_t<decltype(h)>;
77  using op_type = accept_async<Handler, executor_type>;
78  auto p = handler_allocate<op_type>(h, std::move(h), get_executor());
79  auto op = handler_ptr<op_type, Handler>{p, &p->handler};
80  accept(c, *op);
81  op.release(); // release ownership
82  }, token);
83  }
84 
85  void close();
86 
87  void abort_connections(error_code ec);
88 
89  void start_recv();
90  void on_readable();
91  void on_writeable();
92 
93  const lsquic_out_spec* send_packets(const lsquic_out_spec* begin,
94  const lsquic_out_spec* end,
95  error_code& ec);
96 
97  size_t recv_packet(iovec iov, udp::endpoint& peer, sockaddr_union& self,
98  int& ecn, error_code& ec);
99 };
100 
101 } // namespace nexus::quic::detail