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 : : #include "wirestead/builder/udp_builder.hpp"
18 : :
19 : : #include <boost/asio/io_context.hpp>
20 : : #include <boost/asio/ip/address.hpp>
21 : :
22 : : #include "wirestead/builder/auto_initializer.hpp"
23 : : #include "wirestead/diagnostics/exceptions.hpp"
24 : :
25 : : namespace wirestead {
26 : : namespace builder {
27 : :
28 : : // UdpClientBuilder implementation
29 : :
30 : 1 : UdpClientBuilder::UdpClientBuilder() : UdpClientBuilder(0) {}
31 : :
32 : 9 : UdpClientBuilder::UdpClientBuilder(uint16_t local_port)
33 : 9 : : local_port_(local_port),
34 : 9 : bind_address_("0.0.0.0"),
35 : 18 : remote_host_(""),
36 : 9 : remote_port_(0),
37 : 9 : auto_start_(false),
38 : 9 : independent_context_(false),
39 : 9 : enable_broadcast_(false),
40 : 9 : reuse_address_(false),
41 : 9 : send_buffer_size_(0),
42 : 18 : receive_buffer_size_(0) {
43 : : // Ensure background IO service is running
44 : 9 : AutoInitializer::ensure_io_context_running();
45 : 9 : }
46 : :
47 : 7 : std::unique_ptr<wrapper::UdpClient> UdpClientBuilder::build() {
48 : 7 : std::unique_ptr<wrapper::UdpClient> client;
49 : 7 : config::UdpConfig cfg;
50 : 7 : cfg.bind_address = bind_address_;
51 : 7 : cfg.local_port = local_port_;
52 : 7 : cfg.remote_address = remote_host_;
53 : 7 : cfg.remote_port = remote_port_;
54 : 7 : cfg.enable_broadcast = enable_broadcast_;
55 : 7 : cfg.reuse_address = reuse_address_;
56 : 7 : cfg.multicast_group = multicast_group_;
57 : 7 : cfg.multicast_interface = multicast_interface_;
58 : 7 : cfg.send_buffer_size = send_buffer_size_;
59 : 7 : cfg.receive_buffer_size = receive_buffer_size_;
60 : :
61 [ + + ]: 7 : if (independent_context_) {
62 : 2 : client = std::make_unique<wrapper::UdpClient>(cfg, std::make_shared<boost::asio::io_context>());
63 : 2 : client->manage_external_context(true);
64 : : } else {
65 : 5 : client = std::make_unique<wrapper::UdpClient>(cfg);
66 : : }
67 : :
68 [ + + + - : 7 : if (this->on_data_) client->on_data(this->on_data_);
+ - ]
69 [ + + + - : 7 : if (this->on_data_batch_) client->on_data_batch(this->on_data_batch_);
+ - ]
70 [ + + + - : 7 : if (this->on_connect_) client->on_connect(this->on_connect_);
+ - ]
71 [ + + + - : 7 : if (this->on_disconnect_) client->on_disconnect(this->on_disconnect_);
+ - ]
72 [ + + + - : 7 : if (this->on_error_) client->on_error(this->on_error_);
+ - ]
73 [ + + + - : 7 : if (this->on_backpressure_) client->on_backpressure(this->on_backpressure_);
+ - ]
74 : :
75 [ + + + - ]: 7 : if (this->bp_strategy_set_) client->backpressure_strategy(this->bp_strategy_);
76 : 7 : client->backpressure_threshold(this->get_effective_backpressure_threshold());
77 : :
78 [ + + ]: 7 : if (this->framer_factory_) {
79 : 3 : client->framer(this->framer_factory_());
80 : : }
81 [ + + ]: 7 : if (this->on_message_) {
82 : 2 : client->on_message(this->on_message_);
83 : : }
84 [ + + ]: 7 : if (this->on_message_batch_) {
85 : 1 : client->on_message_batch(this->on_message_batch_);
86 : : }
87 : :
88 [ - + ]: 7 : if (auto_start_) {
89 : 0 : client->auto_start(true);
90 : : }
91 : :
92 : 14 : return client;
93 : 7 : }
94 : :
95 : 4 : UdpClientBuilder& UdpClientBuilder::auto_start(bool auto_start) {
96 : 4 : auto_start_ = auto_start;
97 : 4 : return *this;
98 : : }
99 : :
100 : 3 : UdpClientBuilder& UdpClientBuilder::local_port(uint16_t port) {
101 : 3 : local_port_ = port;
102 : 3 : return *this;
103 : : }
104 : :
105 : 2 : UdpClientBuilder& UdpClientBuilder::bind_address(const std::string& address) {
106 : 2 : bind_address_ = address;
107 : 2 : return *this;
108 : : }
109 : :
110 : 5 : UdpClientBuilder& UdpClientBuilder::remote_endpoint(const std::string& host, uint16_t port) {
111 : 5 : boost::system::error_code ec;
112 : 5 : boost::asio::ip::make_address(host, ec);
113 [ + + ]: 5 : if (ec) {
114 : 5 : throw diagnostics::BuilderException("Invalid remote address: " + host, "udp");
115 : : }
116 : 4 : remote_host_ = host;
117 : 4 : remote_port_ = port;
118 : 4 : return *this;
119 : : }
120 : :
121 : 4 : UdpClientBuilder& UdpClientBuilder::broadcast(bool enable) {
122 : 4 : enable_broadcast_ = enable;
123 : 4 : return *this;
124 : : }
125 : :
126 : 0 : UdpClientBuilder& UdpClientBuilder::multicast_group(const std::string& group, const std::string& interface_address) {
127 : 0 : multicast_group_ = group;
128 [ # # ]: 0 : if (interface_address.empty()) {
129 : 0 : multicast_interface_.reset();
130 : : } else {
131 : 0 : multicast_interface_ = interface_address;
132 : : }
133 : 0 : return *this;
134 : : }
135 : :
136 : 4 : UdpClientBuilder& UdpClientBuilder::reuse_address(bool enable) {
137 : 4 : reuse_address_ = enable;
138 : 4 : return *this;
139 : : }
140 : :
141 : 3 : UdpClientBuilder& UdpClientBuilder::independent_context(bool use_independent) {
142 : 3 : independent_context_ = use_independent;
143 : 3 : return *this;
144 : : }
145 : :
146 : 1 : UdpClientBuilder& UdpClientBuilder::send_buffer_size(size_t bytes) {
147 : 1 : send_buffer_size_ = bytes;
148 : 1 : return *this;
149 : : }
150 : :
151 : 1 : UdpClientBuilder& UdpClientBuilder::receive_buffer_size(size_t bytes) {
152 : 1 : receive_buffer_size_ = bytes;
153 : 1 : return *this;
154 : : }
155 : :
156 : : // UdpServerBuilder implementation
157 : :
158 : 1 : UdpServerBuilder::UdpServerBuilder() : UdpServerBuilder(0) {}
159 : :
160 : 5 : UdpServerBuilder::UdpServerBuilder(uint16_t local_port)
161 : 5 : : local_port_(local_port),
162 : 5 : bind_address_("0.0.0.0"),
163 : 5 : auto_start_(false),
164 : 5 : independent_context_(false),
165 : 5 : enable_broadcast_(false),
166 : 5 : reuse_address_(false),
167 : 5 : send_buffer_size_(0),
168 : 10 : receive_buffer_size_(0) {
169 : : // Ensure background IO service is running
170 : 5 : AutoInitializer::ensure_io_context_running();
171 : 5 : }
172 : :
173 : 4 : std::unique_ptr<wrapper::UdpServer> UdpServerBuilder::build() {
174 : 4 : std::unique_ptr<wrapper::UdpServer> server;
175 : 4 : config::UdpConfig cfg;
176 : 4 : cfg.bind_address = bind_address_;
177 : 4 : cfg.local_port = local_port_;
178 : 4 : cfg.enable_broadcast = enable_broadcast_;
179 : 4 : cfg.reuse_address = reuse_address_;
180 : 4 : cfg.multicast_group = multicast_group_;
181 : 4 : cfg.multicast_interface = multicast_interface_;
182 : 4 : cfg.send_buffer_size = send_buffer_size_;
183 : 4 : cfg.receive_buffer_size = receive_buffer_size_;
184 : :
185 [ + + ]: 4 : if (independent_context_) {
186 : 2 : server = std::make_unique<wrapper::UdpServer>(cfg, std::make_shared<boost::asio::io_context>());
187 : 2 : server->manage_external_context(true);
188 : : } else {
189 : 2 : server = std::make_unique<wrapper::UdpServer>(cfg);
190 : : }
191 : :
192 [ + + + - : 4 : if (this->on_data_) server->on_data(this->on_data_);
+ - ]
193 [ + + + - : 4 : if (this->on_data_batch_) server->on_data_batch(this->on_data_batch_);
+ - ]
194 [ + + + - : 4 : if (this->on_connect_) server->on_connect(this->on_connect_);
+ - ]
195 [ + + + - : 4 : if (this->on_disconnect_) server->on_disconnect(this->on_disconnect_);
+ - ]
196 [ + + + - : 4 : if (this->on_error_) server->on_error(this->on_error_);
+ - ]
197 [ + + + - : 4 : if (this->on_backpressure_) server->on_backpressure(this->on_backpressure_);
+ - ]
198 : :
199 [ + + + - ]: 4 : if (this->bp_strategy_set_) server->backpressure_strategy(this->bp_strategy_);
200 : 4 : server->backpressure_threshold(this->get_effective_backpressure_threshold());
201 : :
202 [ + + ]: 4 : if (this->framer_factory_) {
203 : 3 : server->framer(this->framer_factory_);
204 : : }
205 [ + + ]: 4 : if (this->on_message_) {
206 : 2 : server->on_message(this->on_message_);
207 : : }
208 [ + + ]: 4 : if (this->on_message_batch_) {
209 : 1 : server->on_message_batch(this->on_message_batch_);
210 : : }
211 : :
212 [ + + ]: 4 : if (client_limit_enabled_) {
213 : 2 : server->max_clients(max_clients_);
214 : : }
215 [ + + ]: 4 : if (idle_timeout_set_) {
216 : 2 : server->idle_timeout(idle_timeout_);
217 : : }
218 : :
219 [ - + ]: 4 : if (auto_start_) {
220 : 0 : server->auto_start(true);
221 : : }
222 : :
223 : 8 : return server;
224 : 4 : }
225 : :
226 : 4 : UdpServerBuilder& UdpServerBuilder::auto_start(bool auto_start) {
227 : 4 : auto_start_ = auto_start;
228 : 4 : return *this;
229 : : }
230 : :
231 : 3 : UdpServerBuilder& UdpServerBuilder::local_port(uint16_t port) {
232 : 3 : local_port_ = port;
233 : 3 : return *this;
234 : : }
235 : :
236 : 2 : UdpServerBuilder& UdpServerBuilder::bind_address(const std::string& address) {
237 : 2 : bind_address_ = address;
238 : 2 : return *this;
239 : : }
240 : :
241 : 2 : UdpServerBuilder& UdpServerBuilder::max_clients(uint32_t max) {
242 : 2 : max_clients_ = max;
243 : 2 : client_limit_enabled_ = true;
244 : 2 : return *this;
245 : : }
246 : :
247 : 4 : UdpServerBuilder& UdpServerBuilder::broadcast(bool enable) {
248 : 4 : enable_broadcast_ = enable;
249 : 4 : return *this;
250 : : }
251 : :
252 : 0 : UdpServerBuilder& UdpServerBuilder::multicast_group(const std::string& group, const std::string& interface_address) {
253 : 0 : multicast_group_ = group;
254 [ # # ]: 0 : if (interface_address.empty()) {
255 : 0 : multicast_interface_.reset();
256 : : } else {
257 : 0 : multicast_interface_ = interface_address;
258 : : }
259 : 0 : return *this;
260 : : }
261 : :
262 : 4 : UdpServerBuilder& UdpServerBuilder::reuse_address(bool enable) {
263 : 4 : reuse_address_ = enable;
264 : 4 : return *this;
265 : : }
266 : :
267 : 3 : UdpServerBuilder& UdpServerBuilder::independent_context(bool use_independent) {
268 : 3 : independent_context_ = use_independent;
269 : 3 : return *this;
270 : : }
271 : :
272 : 2 : UdpServerBuilder& UdpServerBuilder::idle_timeout(std::chrono::milliseconds timeout) {
273 : 2 : idle_timeout_ = timeout;
274 : 2 : idle_timeout_set_ = true;
275 : 2 : return *this;
276 : : }
277 : :
278 : 1 : UdpServerBuilder& UdpServerBuilder::send_buffer_size(size_t bytes) {
279 : 1 : send_buffer_size_ = bytes;
280 : 1 : return *this;
281 : : }
282 : :
283 : 1 : UdpServerBuilder& UdpServerBuilder::receive_buffer_size(size_t bytes) {
284 : 1 : receive_buffer_size_ = bytes;
285 : 1 : return *this;
286 : : }
287 : :
288 : : // Explicit template instantiations
289 : :
290 : : } // namespace builder
291 : : } // namespace wirestead
|