Branch data Line data Source code
1 : : /*
2 : : * Copyright 2025 Jinwoo Sung
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at
7 : : *
8 : : * http://www.apache.org/licenses/LICENSE-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : #pragma once
18 : :
19 : : #include <functional>
20 : : #include <future>
21 : : #include <memory>
22 : : #include <optional>
23 : : #include <string>
24 : : #include <string_view>
25 : : #include <vector>
26 : :
27 : : #include "wirestead/base/constants.hpp"
28 : : #include "wirestead/base/visibility.hpp"
29 : : #include "wirestead/wrapper/iserver.hpp"
30 : : #include "wirestead/wrapper/receive_limits.hpp"
31 : :
32 : : namespace boost {
33 : : namespace asio {
34 : : class io_context;
35 : : }
36 : : } // namespace boost
37 : :
38 : : namespace wirestead {
39 : :
40 : : namespace interface {
41 : : class Channel;
42 : : }
43 : :
44 : : namespace wrapper {
45 : :
46 : : /**
47 : : * @brief Modernized TCP Server Wrapper
48 : : */
49 : : class WIRESTEAD_API TcpServer : public ServerInterface {
50 : : public:
51 : : explicit TcpServer(uint16_t port);
52 : : TcpServer(uint16_t port, std::shared_ptr<boost::asio::io_context> external_ioc);
53 : : explicit TcpServer(std::shared_ptr<interface::Channel> channel);
54 : : ~TcpServer() override;
55 : :
56 : : // Move semantics
57 : : TcpServer(TcpServer&&) noexcept;
58 : : TcpServer& operator=(TcpServer&&) noexcept;
59 : :
60 : : // Disable copy
61 : : TcpServer(const TcpServer&) = delete;
62 : : TcpServer& operator=(const TcpServer&) = delete;
63 : :
64 : : // ServerInterface implementation
65 : : [[nodiscard]] std::future<bool> start() override;
66 : : void stop() override;
67 : : bool listening() const override;
68 : : RuntimeStats stats() const override;
69 : : /// Configure library receive storage while stopped. Custom framer internals are excluded.
70 : : TcpServer& receive_limits(ReceiveLimits limits);
71 : : ReceiveMemoryStats receive_stats() const;
72 : : void reset_stats() override;
73 : :
74 : : // Transmission
75 : : [[nodiscard]] FanoutResult broadcast(std::string_view data) override;
76 : : [[nodiscard]] SendResult send_to(ClientId client_id, std::string_view data) override;
77 : : [[nodiscard]] SendResult send_to_blocking(ClientId client_id, std::string_view data) override;
78 : : [[nodiscard]] SendResult try_send_to(ClientId client_id, std::string_view data) override;
79 : : [[nodiscard]] FanoutResult try_broadcast(std::string_view data) override;
80 : : [[nodiscard]] FanoutResult broadcast_line(std::string_view line) override;
81 : : [[nodiscard]] SendResult send_to_line(ClientId client_id, std::string_view line) override;
82 : : [[nodiscard]] FanoutResult try_broadcast_line(std::string_view line) override;
83 : : [[nodiscard]] SendResult try_send_to_line(ClientId client_id, std::string_view line) override;
84 : :
85 : : // Event handlers
86 : : TcpServer& on_connect(ConnectionHandler handler) override;
87 : : TcpServer& on_disconnect(ConnectionHandler handler) override;
88 : : TcpServer& on_data(MessageHandler handler) override;
89 : : TcpServer& on_data_batch(BatchMessageHandler handler) override;
90 : : TcpServer& on_error(ErrorHandler handler) override;
91 : : TcpServer& on_backpressure(std::function<void(size_t)> handler) override;
92 : :
93 : : TcpServer& framer(FramerFactory factory) override;
94 : : TcpServer& on_message(MessageHandler handler) override;
95 : : TcpServer& on_message_batch(BatchMessageHandler handler) override;
96 : :
97 : : // Client count and management
98 : : size_t client_count() const override;
99 : : std::vector<ClientId> connected_clients() const override;
100 : : std::optional<RuntimeStats> client_stats(ClientId client_id) const override;
101 : :
102 : : // Configuration (Fluent API)
103 : : TcpServer& auto_start(bool manage = true) override;
104 : : TcpServer& bind_address(const std::string& address);
105 : : // Opt into the shared IoContextManager singleton instead of the default
106 : : // dedicated io_context + thread (#440). Must be set before the first
107 : : // start() call to take effect. Only meaningful for deliberately trading
108 : : // per-instance parallelism for reduced thread/memory overhead across many
109 : : // servers in one process; most callers should not need this.
110 : : TcpServer& shared_context(bool use_shared = true);
111 : : TcpServer& port_retry(bool enable = true, int max_retries = 3, int retry_interval_ms = 1000);
112 : : /**
113 : : * @brief Configure application-level idle timeout for accepted sessions.
114 : : *
115 : : * A value of 0ms disables idle timeout. When enabled, only the idle client
116 : : * session is closed; the server keeps listening for new connections.
117 : : */
118 : : TcpServer& idle_timeout(std::chrono::milliseconds timeout);
119 : : TcpServer& max_clients(size_t max);
120 : : TcpServer& backpressure_threshold(size_t threshold);
121 : : TcpServer& backpressure_strategy(base::constants::BackpressureStrategy strategy);
122 : :
123 : : /// Returns the configured backpressure threshold in bytes.
124 : : size_t backpressure_threshold() const;
125 : : /// Returns the configured backpressure strategy.
126 : : base::constants::BackpressureStrategy backpressure_strategy() const;
127 : : TcpServer& tcp_no_delay(bool enable = true);
128 : : TcpServer& keep_alive(bool enable = true);
129 : : /**
130 : : * @brief Serve TLS using this certificate chain and private key (PEM).
131 : : *
132 : : * Must be set before start(). Requires a build with WIRESTEAD_ENABLE_TLS;
133 : : * without it start() fails rather than quietly serving plaintext.
134 : : */
135 : : TcpServer& tls(const std::string& certificate_file, const std::string& private_key_file);
136 : :
137 : : TcpServer& send_buffer_size(size_t bytes);
138 : : TcpServer& receive_buffer_size(size_t bytes);
139 : :
140 : : /**
141 : : * @brief Size of the userspace buffer each read fills, in bytes.
142 : : *
143 : : * Distinct from receive_buffer_size(), which sets the kernel's SO_RCVBUF.
144 : : * Raising this reduces read completions and callback dispatches on bulk
145 : : * transfers, at the cost of that much memory per connection - a server
146 : : * multiplies it by the number of accepted connections. Clamped to
147 : : * [MIN_READ_BUFFER_SIZE, MAX_READ_BUFFER_SIZE]; takes effect on the next
148 : : * start().
149 : : */
150 : : TcpServer& read_buffer_size(size_t bytes);
151 : : TcpServer& manage_external_context(bool manage);
152 : : TcpServer& batch_size(size_t size);
153 : : TcpServer& batch_latency(std::chrono::milliseconds latency);
154 : :
155 : : private:
156 : : struct Impl;
157 : 2334 : const Impl* get_impl() const { return impl_.get(); }
158 : : Impl* get_impl() { return impl_.get(); }
159 : : // #450: shared_ptr (not unique_ptr) so in-flight callbacks on an
160 : : // externally-owned io_context can extend Impl's lifetime for the
161 : : // duration of their invocation via weak_from_this(), rather than only
162 : : // checking a staleness flag that says nothing about whether Impl itself
163 : : // still exists.
164 : : std::shared_ptr<Impl> impl_;
165 : : };
166 : :
167 : : } // namespace wrapper
168 : : } // namespace wirestead
|