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 <cstdint>
20 : : #include <string>
21 : :
22 : : #include "wirestead/base/constants.hpp"
23 : : #include "wirestead/util/input_validator.hpp"
24 : :
25 : : namespace wirestead {
26 : : namespace config {
27 : :
28 : : struct TcpClientConfig {
29 : : std::string host = "127.0.0.1";
30 : : uint16_t port = 9000;
31 : : unsigned retry_interval_ms = base::constants::DEFAULT_RETRY_INTERVAL_MS;
32 : : unsigned connection_timeout_ms = base::constants::DEFAULT_CONNECTION_TIMEOUT_MS;
33 : : unsigned idle_timeout_ms = base::constants::DEFAULT_IDLE_TIMEOUT_MS; // 0 = disabled
34 : : IdleTimeoutAction idle_timeout_action = IdleTimeoutAction::Reconnect;
35 : : int max_retries = base::constants::DEFAULT_MAX_RETRIES;
36 : : size_t backpressure_threshold = base::constants::DEFAULT_BACKPRESSURE_THRESHOLD;
37 : : base::constants::BackpressureStrategy backpressure_strategy = base::constants::BackpressureStrategy::Reliable;
38 : : bool enable_memory_pool = true;
39 : : bool tcp_no_delay = base::constants::DEFAULT_TCP_NO_DELAY;
40 : : bool keep_alive = base::constants::DEFAULT_KEEP_ALIVE;
41 : : size_t send_buffer_size = 0;
42 : : size_t receive_buffer_size = 0;
43 : : // Size of the per-connection userspace read buffer that each
44 : : // async_read_some() fills. Distinct from receive_buffer_size, which is the
45 : : // kernel's SO_RCVBUF. Raising this reduces read completions and callback
46 : : // dispatches on bulk transfers, at the cost of that much memory per
47 : : // connection.
48 : : size_t read_buffer_size = base::constants::DEFAULT_READ_BUFFER_SIZE;
49 : :
50 : : // TLS. Off unless tls_enabled is set, which is the default.
51 : : //
52 : : // The server side of TLS proves who it is; the client side is what checks.
53 : : // Verification is therefore on and not optional: an unverified TLS connection
54 : : // encrypts traffic to whoever answered, which is exactly what an attacker in
55 : : // the middle wants. Leave tls_ca_file empty to use the system trust store,
56 : : // or point it at a PEM to trust a private CA or a self-signed certificate.
57 : : bool tls_enabled = false;
58 : : std::string tls_ca_file;
59 : :
60 : 756 : TcpClientConfig() = default;
61 : 229 : TcpClientConfig(const TcpClientConfig&) = default;
62 : 99 : TcpClientConfig& operator=(const TcpClientConfig&) = default;
63 : : TcpClientConfig(TcpClientConfig&&) noexcept = default;
64 : : TcpClientConfig& operator=(TcpClientConfig&&) noexcept = default;
65 : :
66 : : // Validation methods
67 : 21 : bool is_valid() const {
68 : 41 : return read_buffer_size >= base::constants::MIN_READ_BUFFER_SIZE &&
69 [ + + + + ]: 20 : read_buffer_size <= base::constants::MAX_READ_BUFFER_SIZE && util::InputValidator::is_valid_host(host) &&
70 [ + - + - ]: 16 : port > 0 && retry_interval_ms >= base::constants::MIN_RETRY_INTERVAL_MS &&
71 [ + - ]: 16 : retry_interval_ms <= base::constants::MAX_RETRY_INTERVAL_MS &&
72 [ + + ]: 16 : connection_timeout_ms >= base::constants::MIN_CONNECTION_TIMEOUT_MS &&
73 [ + + ]: 15 : connection_timeout_ms <= base::constants::MAX_CONNECTION_TIMEOUT_MS &&
74 [ + + + - ]: 14 : (idle_timeout_ms == 0 || (idle_timeout_ms >= base::constants::MIN_IDLE_TIMEOUT_MS &&
75 [ - + ]: 1 : idle_timeout_ms <= base::constants::MAX_IDLE_TIMEOUT_MS)) &&
76 [ + - ]: 13 : backpressure_threshold >= base::constants::MIN_BACKPRESSURE_THRESHOLD &&
77 [ + - ]: 13 : backpressure_threshold <= base::constants::MAX_BACKPRESSURE_THRESHOLD &&
78 [ + + + + ]: 13 : (send_buffer_size == 0 || (send_buffer_size >= base::constants::MIN_SOCKET_BUFFER_SIZE &&
79 [ + - ]: 1 : send_buffer_size <= base::constants::MAX_SOCKET_BUFFER_SIZE)) &&
80 [ + + + - ]: 12 : (receive_buffer_size == 0 || (receive_buffer_size >= base::constants::MIN_SOCKET_BUFFER_SIZE &&
81 [ + + + - ]: 42 : receive_buffer_size <= base::constants::MAX_SOCKET_BUFFER_SIZE)) &&
82 [ - + - - : 33 : (max_retries == -1 || (max_retries >= 0 && max_retries <= base::constants::MAX_RETRIES_LIMIT));
- - ]
83 : : }
84 : :
85 : : // Apply validation and clamp values to valid ranges
86 : 153 : void validate_and_clamp() {
87 [ + + ]: 153 : if (read_buffer_size < base::constants::MIN_READ_BUFFER_SIZE) {
88 : 1 : read_buffer_size = base::constants::MIN_READ_BUFFER_SIZE;
89 [ + + ]: 152 : } else if (read_buffer_size > base::constants::MAX_READ_BUFFER_SIZE) {
90 : 1 : read_buffer_size = base::constants::MAX_READ_BUFFER_SIZE;
91 : : }
92 [ + + ]: 153 : if (retry_interval_ms < base::constants::MIN_RETRY_INTERVAL_MS) {
93 : 14 : retry_interval_ms = base::constants::MIN_RETRY_INTERVAL_MS;
94 [ - + ]: 139 : } else if (retry_interval_ms > base::constants::MAX_RETRY_INTERVAL_MS) {
95 : 0 : retry_interval_ms = base::constants::MAX_RETRY_INTERVAL_MS;
96 : : }
97 : :
98 [ + + ]: 153 : if (connection_timeout_ms < base::constants::MIN_CONNECTION_TIMEOUT_MS) {
99 : 8 : connection_timeout_ms = base::constants::MIN_CONNECTION_TIMEOUT_MS;
100 [ + + ]: 145 : } else if (connection_timeout_ms > base::constants::MAX_CONNECTION_TIMEOUT_MS) {
101 : 1 : connection_timeout_ms = base::constants::MAX_CONNECTION_TIMEOUT_MS;
102 : : }
103 : :
104 [ + + ]: 153 : if (idle_timeout_ms != 0) {
105 [ - + ]: 5 : if (idle_timeout_ms < base::constants::MIN_IDLE_TIMEOUT_MS) {
106 : 0 : idle_timeout_ms = base::constants::MIN_IDLE_TIMEOUT_MS;
107 [ + + ]: 5 : } else if (idle_timeout_ms > base::constants::MAX_IDLE_TIMEOUT_MS) {
108 : 1 : idle_timeout_ms = base::constants::MAX_IDLE_TIMEOUT_MS;
109 : : }
110 : : }
111 : :
112 [ + + ]: 153 : if (backpressure_threshold < base::constants::MIN_BACKPRESSURE_THRESHOLD) {
113 : 1 : backpressure_threshold = base::constants::MIN_BACKPRESSURE_THRESHOLD;
114 [ - + ]: 152 : } else if (backpressure_threshold > base::constants::MAX_BACKPRESSURE_THRESHOLD) {
115 : 0 : backpressure_threshold = base::constants::MAX_BACKPRESSURE_THRESHOLD;
116 : : }
117 : :
118 [ + + - + ]: 153 : if (max_retries != -1 && max_retries > base::constants::MAX_RETRIES_LIMIT) {
119 : 0 : max_retries = base::constants::MAX_RETRIES_LIMIT;
120 : : }
121 : :
122 [ + + + - ]: 153 : if (send_buffer_size != 0 && send_buffer_size < base::constants::MIN_SOCKET_BUFFER_SIZE) {
123 : 1 : send_buffer_size = base::constants::MIN_SOCKET_BUFFER_SIZE;
124 [ - + ]: 152 : } else if (send_buffer_size > base::constants::MAX_SOCKET_BUFFER_SIZE) {
125 : 0 : send_buffer_size = base::constants::MAX_SOCKET_BUFFER_SIZE;
126 : : }
127 : :
128 [ + + - + ]: 153 : if (receive_buffer_size != 0 && receive_buffer_size < base::constants::MIN_SOCKET_BUFFER_SIZE) {
129 : 0 : receive_buffer_size = base::constants::MIN_SOCKET_BUFFER_SIZE;
130 [ + + ]: 153 : } else if (receive_buffer_size > base::constants::MAX_SOCKET_BUFFER_SIZE) {
131 : 1 : receive_buffer_size = base::constants::MAX_SOCKET_BUFFER_SIZE;
132 : : }
133 : 153 : }
134 : : };
135 : :
136 : : } // namespace config
137 : : } // namespace wirestead
|