GCC Code Coverage Report


Directory: src/gate/
File: src/gate/net/cxx_sockets.cpp
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 153 262 58.4%
Functions: 30 56 53.6%
Branches: 42 144 29.2%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28 #include "gate/net/sockets.hpp"
29 #include "gate/exceptions.hpp"
30 #include "gate/results.hpp"
31 #include "gate/memalloc.hpp"
32
33 namespace gate
34 {
35 namespace net
36 {
37
38 1 Socket::Ip4Address::Ip4Address(uint8_t n1, uint8_t n2, uint8_t n3, uint8_t n4)
39 {
40 1 this->item[0] = n1;
41 1 this->item[1] = n2;
42 1 this->item[2] = n3;
43 1 this->item[3] = n4;
44 1 }
45
46 Socket::Ip4Address::Ip4Address(uint32_t quad)
47 {
48 this->item[0] = static_cast<uint8_t>((quad & 0xff000000) >> 24);
49 this->item[1] = static_cast<uint8_t>((quad & 0x00ff0000) >> 16);
50 this->item[2] = static_cast<uint8_t>((quad & 0x0000ff00) >> 8);
51 this->item[3] = static_cast<uint8_t>((quad & 0x000000ff));
52 }
53
54 1 Socket::Ip6Address::Ip6Address(gate_uint16_t n1, gate_uint16_t n2, gate_uint16_t n3, gate_uint16_t n4,
55 1 gate_uint16_t n5, gate_uint16_t n6, gate_uint16_t n7, gate_uint16_t n8)
56 {
57 1 this->item[0] = n1;
58 1 this->item[1] = n2;
59 1 this->item[2] = n3;
60 1 this->item[3] = n4;
61 1 this->item[4] = n5;
62 1 this->item[5] = n6;
63 1 this->item[6] = n7;
64 1 this->item[7] = n8;
65 1 }
66
67 70 Socket::Endpoint::Endpoint()
68 {
69 70 gate_socket_endpoint_t* ptr = this;
70 70 gate_mem_clear(ptr, sizeof(gate_socket_endpoint_t));
71 70 }
72
73 1 Socket::Endpoint::Endpoint(Ip4Address const& addressIp4, uint16_t port)
74 {
75 1 this->ip4.family = GATE_SOCKET_FAMILY_INET4;
76 1 this->ip4.port = port;
77 1 gate_mem_copy(&this->ip4.address.item[0], &addressIp4.item[0], sizeof(addressIp4.item));
78 1 }
79
80 1 Socket::Endpoint::Endpoint(Ip6Address const& addressIp6, uint16_t port, int32_t scope)
81 {
82 1 this->ip6.family = GATE_SOCKET_FAMILY_INET6;
83 1 this->ip6.port = port;
84 1 this->ip6.scope = scope;
85 1 gate_mem_copy(&this->ip6.address.item[0], &addressIp6.item[0], sizeof(addressIp6.item));
86 1 }
87
88 4 Socket::FamilyEnum Socket::Endpoint::getFamily() const
89 {
90 4 return static_cast<Socket::FamilyEnum>(this->family);
91 }
92
93
94 44 static void check_socket_valid(gate_socket_t const& s, char const* const sourceFunc = NULL)
95 {
96
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
44 if (s == GATE_SOCKET_INVALID)
97 {
98 gate::raiseError(results::InvalidState, sourceFunc);
99 }
100 44 }
101
102 #define CHECK_SOCKET(sock_fd) check_socket_valid((sock_fd), GATE_CURRENT_FUNCTION_NAME)
103
104 2 bool_t Socket::hasSupportFor(FamilyEnum family)
105 {
106 2 return gate_socket_support((int16_t)family);
107 }
108
109 2 Socket::Socket()
110 {
111 2 this->impl = GATE_SOCKET_INVALID;
112 2 }
113
114 4 Socket::Socket(SocketTypeEnum socktype)
115 {
116 4 result_t result = gate_socket_create((int16_t)socktype, &this->impl);
117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATEXX_CHECK_ERROR(result);
118 4 }
119 4 Socket::Socket(FamilyEnum family, MsgTypeEnum msgtype, ProtocolEnum protocol)
120 {
121 4 result_t result = gate_socket_create_ex((int16_t)family, (int16_t)msgtype, (int16_t)protocol, &this->impl);
122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATEXX_CHECK_ERROR(result);
123 4 }
124 20 Socket::~Socket()
125 {
126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (this->impl != GATE_SOCKET_INVALID)
127 {
128 gate_socket_close(this->impl);
129 }
130 10 }
131
132 void Socket::connect(Endpoint const& endpoint)
133 {
134 CHECK_SOCKET(this->impl);
135 result_t result = gate_socket_connect(this->impl, &endpoint);
136 GATEXX_CHECK_EXCEPTION(result);
137 }
138 2 void Socket::connect(String const& address)
139 {
140 2 CHECK_SOCKET(this->impl);
141 2 result_t result = gate_socket_connect_address(this->impl, address.c_impl());
142
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATEXX_CHECK_EXCEPTION(result);
143 2 }
144 Result<Void> Socket::tryConnect(Endpoint const& endpoint) noexcept
145 {
146 return makeResult(gate_socket_connect(this->impl, &endpoint));
147 }
148 Result<Void> Socket::tryConnect(String const& address) noexcept
149 {
150 return makeResult(gate_socket_connect_address(this->impl, address.c_impl()));
151 }
152
153 2 void Socket::bind(Endpoint const& endpoint)
154 {
155 2 CHECK_SOCKET(this->impl);
156 2 result_t result = gate_socket_bind(this->impl, &endpoint);
157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATEXX_CHECK_EXCEPTION(result);
158 2 }
159 4 void Socket::bind(String const& address)
160 {
161 4 CHECK_SOCKET(this->impl);
162 4 result_t result = gate_socket_bind_address(this->impl, address.c_impl());
163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATEXX_CHECK_EXCEPTION(result);
164 4 }
165 Result<Void> Socket::tryBind(Endpoint const& endpoint) noexcept
166 {
167 return makeResult(gate_socket_bind(this->impl, &endpoint));
168 }
169 Result<Void> Socket::tryBind(String const& address) noexcept
170 {
171 return makeResult(gate_socket_bind_address(this->impl, address.c_impl()));
172 }
173
174
175 2 void Socket::listen(int32_t backlog)
176 {
177 2 CHECK_SOCKET(this->impl);
178 2 result_t result = gate_socket_listen(this->impl, backlog);
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATEXX_CHECK_EXCEPTION(result);
180 2 }
181 Result<Void> Socket::tryListen(int32_t backlog) noexcept
182 {
183 return makeResult(gate_socket_listen(this->impl, backlog));
184 }
185
186
187 2 void Socket::accept(Socket& socket)
188 {
189 2 CHECK_SOCKET(this->impl);
190 2 result_t result = gate_socket_accept(this->impl, &socket.impl);
191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATEXX_CHECK_EXCEPTION(result);
192 2 }
193 Result<Void> Socket::tryAccept(Socket& socket) noexcept
194 {
195 return makeResult(gate_socket_accept(this->impl, &socket.impl));
196 }
197
198
199 4 size_t Socket::receive(char* buffer, size_t bufferlen)
200 {
201
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 CHECK_SOCKET(this->impl);
202 4 size_t received = 0;
203
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 result_t result = gate_socket_receive(this->impl, buffer, bufferlen, &received);
204
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
4 GATEXX_CHECK_EXCEPTION(result);
205 4 return received;
206 }
207 Result<size_t> Socket::tryReceive(char* buffer, size_t bufferlen) noexcept
208 {
209 size_t received = 0;
210 return makeResult(gate_socket_receive(this->impl, buffer, bufferlen, &received), received);
211 }
212
213
214 2 size_t Socket::receiveFrom(Endpoint& endpoint, char* buffer, size_t bufferlen, uint16_t flags)
215 {
216
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 CHECK_SOCKET(this->impl);
217 2 size_t received = 0;
218
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 result_t result = gate_socket_receive_from(this->impl, &endpoint, buffer, bufferlen, &received, flags);
219
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 GATEXX_CHECK_EXCEPTION(result);
220 2 return received;
221 }
222 Result<size_t> Socket::tryReceiveFrom(Endpoint& endpoint, char* buffer, size_t bufferlen, uint16_t flags) noexcept
223 {
224 size_t received = 0;
225 return makeResult(gate_socket_receive_from(this->impl, &endpoint, buffer, bufferlen, &received, flags), received);
226 }
227
228 2 size_t Socket::send(char const* buffer, size_t bufferlen)
229 {
230
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 CHECK_SOCKET(this->impl);
231 2 size_t sent = 0;
232
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 result_t result = gate_socket_send(this->impl, buffer, bufferlen, &sent);
233
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 GATEXX_CHECK_EXCEPTION(result);
234 2 return sent;
235 }
236 Result<size_t> Socket::trySend(char const* buffer, size_t bufferlen) noexcept
237 {
238 size_t sent = 0;
239 return makeResult(gate_socket_send(this->impl, buffer, bufferlen, &sent), sent);
240 }
241
242 2 size_t Socket::sendTo(Endpoint const& endpoint, char const* buffer, size_t bufferlen, uint16_t flags)
243 {
244
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 CHECK_SOCKET(this->impl);
245 2 size_t sent = 0;
246
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 result_t result = gate_socket_send_to(this->impl, &endpoint, buffer, bufferlen, &sent, flags);
247
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 GATEXX_CHECK_EXCEPTION(result);
248 2 return sent;
249 }
250 Result<size_t> Socket::trySendTo(Endpoint const& endpoint, char const* buffer, size_t bufferlen, uint16_t flags) noexcept
251 {
252 size_t sent = 0;
253 return makeResult(gate_socket_send_to(this->impl, &endpoint, buffer, bufferlen, &sent, flags), sent);
254 }
255
256
257 4 void Socket::shutdown(bool shutdownReceive, bool shutdownSend)
258 {
259 4 CHECK_SOCKET(this->impl);
260 4 result_t result = gate_socket_shutdown(this->impl, shutdownReceive, shutdownSend);
261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATEXX_CHECK_EXCEPTION(result);
262 4 }
263 Result<Void> Socket::tryShutdown(bool shutdownReceive, bool shutdownSend) noexcept
264 {
265 return makeResult(gate_socket_shutdown(this->impl, shutdownReceive, shutdownSend));
266 }
267
268
269 10 void Socket::close() noexcept
270 {
271
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (this->impl != GATE_SOCKET_INVALID)
272 {
273 10 gate_socket_close(this->impl);
274 }
275 10 this->impl = GATE_SOCKET_INVALID;
276 10 }
277
278 size_t Socket::getOption(int32_t level, int32_t option, void* buffer, size_t bufferlen)
279 {
280 CHECK_SOCKET(this->impl);
281 result_t result = gate_socket_get_option(this->impl, level, option, buffer, &bufferlen);
282 GATEXX_CHECK_EXCEPTION(result);
283 return bufferlen;
284 }
285 void Socket::setOption(int32_t level, int32_t option, void const* buffer, size_t bufferlen)
286 {
287 CHECK_SOCKET(this->impl);
288 result_t result = gate_socket_set_option(this->impl, level, option, buffer, bufferlen);
289 GATEXX_CHECK_EXCEPTION(result);
290 }
291 10 void Socket::setOption(OptionEnum option, int32_t value)
292 {
293 10 CHECK_SOCKET(this->impl);
294 10 result_t result = gate_socket_set(this->impl, (GATE_SOCKET_OPTION)option, value);
295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 GATEXX_CHECK_EXCEPTION(result);
296 10 }
297 bool_t Socket::hasError()
298 {
299 CHECK_SOCKET(this->impl);
300 gate_bool_t error_flag = false;
301 result_t result = gate_socket_has_error(this->impl, &error_flag);
302 if (GATE_FAILED(result))
303 {
304 error_flag = true;
305 }
306 return error_flag;
307 }
308 Socket::Endpoint Socket::getLocalEndpoint()
309 {
310 CHECK_SOCKET(this->impl);
311 Socket::Endpoint ret;
312 result_t result = gate_socket_get_local_endpoint(this->impl, &ret);
313 GATEXX_CHECK_EXCEPTION(result);
314 return ret;
315 }
316 2 String Socket::getLocalAddress()
317 {
318
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 CHECK_SOCKET(this->impl);
319 gate_string_t address;
320
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 result_t result = gate_socket_get_local_address(this->impl, &address);
321
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 GATEXX_CHECK_EXCEPTION(result);
322 4 return String::createFrom(address);
323 }
324 Socket::Endpoint Socket::getRemoteEndpoint()
325 {
326 CHECK_SOCKET(this->impl);
327 Socket::Endpoint ret;
328 result_t result = gate_socket_get_remote_endpoint(this->impl, &ret);
329 GATEXX_CHECK_EXCEPTION(result);
330 return ret;
331 }
332 2 String Socket::getRemoteAddress()
333 {
334
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 CHECK_SOCKET(this->impl);
335 gate_string_t address;
336
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 result_t result = gate_socket_get_remote_address(this->impl, &address);
337
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 GATEXX_CHECK_EXCEPTION(result);
338 4 return String::createFrom(address);
339 }
340
341 gate_socket_t* Socket::c_impl()
342 {
343 return &this->impl;
344 }
345 gate_socket_t const* Socket::c_impl() const
346 {
347 return &this->impl;
348 }
349 void Socket::swap(Socket& that) noexcept
350 {
351 gate::swapRefsNoExcept(this->impl, that.impl);
352 }
353 bool Socket::valid() const noexcept
354 {
355 return this->impl != GATE_SOCKET_INVALID;
356 }
357
358
359
360
361 void Socket::select(Socket const* sockets, size_t socket_count, uint8_t* statusFlags, uint32_t timeout)
362 {
363 gate_socket_t socks[1024];
364 gate_uint8_t flags[1024];
365 gate_size_t current_ndx = 0;
366 gate_size_t ndx;
367 gate_socket_t sockimpl;
368
369 if (socket_count > sizeof(socks) / sizeof(socks[0]))
370 {
371 socket_count = sizeof(socks) / sizeof(socks[0]);
372 }
373
374 current_ndx = 0;
375 for (ndx = 0; ndx != socket_count; ++ndx)
376 {
377 sockimpl = *sockets[ndx].c_impl();
378 if (sockimpl != GATE_SOCKET_INVALID)
379 {
380 socks[current_ndx] = sockimpl;
381 flags[current_ndx] = statusFlags[ndx];
382 ++current_ndx;
383 }
384 }
385 result_t result = gate_socket_select(socks, current_ndx, flags, timeout);
386 GATEXX_CHECK_EXCEPTION(result);
387
388 current_ndx = 0;
389 for (ndx = 0; ndx != socket_count; ++ndx)
390 {
391 sockimpl = *sockets[ndx].c_impl();
392 if (sockimpl != GATE_SOCKET_INVALID)
393 {
394 statusFlags[ndx] = flags[current_ndx];
395 ++current_ndx;
396 }
397 }
398 }
399 4 static gate_result_t socket_select_one(gate_socket_t sock, bool* canRead, bool* canWrite, bool* hasError, uint32_t timeout_ms)
400 {
401 4 uint8_t flags = 0;
402
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (canRead) flags |= GATE_SOCKET_SELECT_FLAG_RECEIVE;
403
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (canWrite) flags |= GATE_SOCKET_SELECT_FLAG_SEND;
404
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (hasError) flags |= GATE_SOCKET_SELECT_FLAG_ERROR;
405
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 result_t result = gate_socket_select(&sock, 1, &flags, timeout_ms);
406
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (GATE_SUCCEEDED(result))
407 {
408
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (canRead) *canRead = GATE_FLAG_ENABLED(flags, GATE_SOCKET_SELECT_FLAG_RECEIVE);
409
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (canWrite) *canWrite = GATE_FLAG_ENABLED(flags, GATE_SOCKET_SELECT_FLAG_SEND);
410
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (hasError) *hasError = GATE_FLAG_ENABLED(flags, GATE_SOCKET_SELECT_FLAG_ERROR);
411 }
412 4 return result;
413 }
414
415 4 void Socket::select(bool* canRead, bool* canWrite, bool* hasError, uint32_t timeout_ms)
416 {
417 4 CHECK_SOCKET(this->impl);
418 4 result_t result = socket_select_one(this->impl, canRead, canWrite, hasError, timeout_ms);
419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATEXX_CHECK_EXCEPTION(result);
420 4 }
421
422 Result<Void> Socket::trySelect(bool* canRead, bool* canWrite, bool* hasError, uint32_t timeout_ms)
423 {
424 return makeResult(socket_select_one(this->impl, canRead, canWrite, hasError, timeout_ms));
425 }
426
427 Socket::Ip4Address Socket::parseIp4(String const& ip4text)
428 {
429 Ip4Address ret;
430 result_t result = gate_socket_parse_ip4(ip4text.c_impl(), &ret);
431 GATEXX_CHECK_EXCEPTION(result);
432 return ret;
433 }
434 Socket::Ip6Address Socket::parseIp6(String const& ip6text)
435 {
436 Ip6Address ret;
437 result_t result = gate_socket_parse_ip6(ip6text.c_impl(), &ret);
438 GATEXX_CHECK_EXCEPTION(result);
439 return ret;
440 }
441 4 Socket::Endpoint Socket::parseAddress(String const& address)
442 {
443 4 Endpoint ret;
444 4 result_t result = gate_socket_parse_endpoint(address.c_impl(), &ret);
445
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATEXX_CHECK_EXCEPTION(result);
446 4 return ret;
447 }
448 2 String Socket::printAddress(Endpoint const& endpoint)
449 {
450 2 gate_string_t text = GATE_STRING_INIT_EMPTY;
451
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 result_t result = gate_socket_print_endpoint(&endpoint, &text);
452
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 GATEXX_CHECK_EXCEPTION(result);
453 4 return String::createFrom(text);
454 }
455
456 } // end of namespace net
457 } // end of namespace gate
458