GCC Code Coverage Report


Directory: src/gate/
File: src/gate/net/cxx_sockets.cpp
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 151 255 59.2%
Functions: 29 55 52.7%
Branches: 42 138 30.4%

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 Socket::FamilyEnum Socket::Endpoint::getFamily() const
89 {
90 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
298 Socket::Endpoint Socket::getLocalEndpoint()
299 {
300 CHECK_SOCKET(this->impl);
301 Socket::Endpoint ret;
302 result_t result = gate_socket_get_local_endpoint(this->impl, &ret);
303 GATEXX_CHECK_EXCEPTION(result);
304 return ret;
305 }
306 2 String Socket::getLocalAddress()
307 {
308
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 CHECK_SOCKET(this->impl);
309 gate_string_t address;
310
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 result_t result = gate_socket_get_local_address(this->impl, &address);
311
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 GATEXX_CHECK_EXCEPTION(result);
312 4 return String::createFrom(address);
313 }
314 Socket::Endpoint Socket::getRemoteEndpoint()
315 {
316 CHECK_SOCKET(this->impl);
317 Socket::Endpoint ret;
318 result_t result = gate_socket_get_remote_endpoint(this->impl, &ret);
319 GATEXX_CHECK_EXCEPTION(result);
320 return ret;
321 }
322 2 String Socket::getRemoteAddress()
323 {
324
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 CHECK_SOCKET(this->impl);
325 gate_string_t address;
326
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 result_t result = gate_socket_get_remote_address(this->impl, &address);
327
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 GATEXX_CHECK_EXCEPTION(result);
328 4 return String::createFrom(address);
329 }
330
331 gate_socket_t* Socket::c_impl()
332 {
333 return &this->impl;
334 }
335 gate_socket_t const* Socket::c_impl() const
336 {
337 return &this->impl;
338 }
339 void Socket::swap(Socket& that) noexcept
340 {
341 gate::swapRefsNoExcept(this->impl, that.impl);
342 }
343 bool Socket::valid() const noexcept
344 {
345 return this->impl != GATE_SOCKET_INVALID;
346 }
347
348
349
350
351 void Socket::select(Socket const* sockets, size_t socket_count, uint8_t* statusFlags, uint32_t timeout)
352 {
353 gate_socket_t socks[1024];
354 gate_uint8_t flags[1024];
355 gate_size_t current_ndx = 0;
356 gate_size_t ndx;
357 gate_socket_t sockimpl;
358
359 if (socket_count > sizeof(socks) / sizeof(socks[0]))
360 {
361 socket_count = sizeof(socks) / sizeof(socks[0]);
362 }
363
364 current_ndx = 0;
365 for (ndx = 0; ndx != socket_count; ++ndx)
366 {
367 sockimpl = *sockets[ndx].c_impl();
368 if (sockimpl != GATE_SOCKET_INVALID)
369 {
370 socks[current_ndx] = sockimpl;
371 flags[current_ndx] = statusFlags[ndx];
372 ++current_ndx;
373 }
374 }
375 result_t result = gate_socket_select(socks, current_ndx, flags, timeout);
376 GATEXX_CHECK_EXCEPTION(result);
377
378 current_ndx = 0;
379 for (ndx = 0; ndx != socket_count; ++ndx)
380 {
381 sockimpl = *sockets[ndx].c_impl();
382 if (sockimpl != GATE_SOCKET_INVALID)
383 {
384 statusFlags[ndx] = flags[current_ndx];
385 ++current_ndx;
386 }
387 }
388 }
389 4 static gate_result_t socket_select_one(gate_socket_t sock, bool* canRead, bool* canWrite, bool* hasError, uint32_t timeout_ms)
390 {
391 4 uint8_t flags = 0;
392
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (canRead) flags |= GATE_SOCKET_SELECT_FLAG_RECEIVE;
393
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (canWrite) flags |= GATE_SOCKET_SELECT_FLAG_SEND;
394
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (hasError) flags |= GATE_SOCKET_SELECT_FLAG_ERROR;
395
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 result_t result = gate_socket_select(&sock, 1, &flags, timeout_ms);
396
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (GATE_SUCCEEDED(result))
397 {
398
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (canRead) *canRead = GATE_FLAG_ENABLED(flags, GATE_SOCKET_SELECT_FLAG_RECEIVE);
399
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (canWrite) *canWrite = GATE_FLAG_ENABLED(flags, GATE_SOCKET_SELECT_FLAG_SEND);
400
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (hasError) *hasError = GATE_FLAG_ENABLED(flags, GATE_SOCKET_SELECT_FLAG_ERROR);
401 }
402 4 return result;
403 }
404
405 4 void Socket::select(bool* canRead, bool* canWrite, bool* hasError, uint32_t timeout_ms)
406 {
407 4 CHECK_SOCKET(this->impl);
408 4 result_t result = socket_select_one(this->impl, canRead, canWrite, hasError, timeout_ms);
409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATEXX_CHECK_EXCEPTION(result);
410 4 }
411
412 Result<Void> Socket::trySelect(bool* canRead, bool* canWrite, bool* hasError, uint32_t timeout_ms)
413 {
414 return makeResult(socket_select_one(this->impl, canRead, canWrite, hasError, timeout_ms));
415 }
416
417 Socket::Ip4Address Socket::parseIp4(String const& ip4text)
418 {
419 Ip4Address ret;
420 result_t result = gate_socket_parse_ip4(ip4text.c_impl(), &ret);
421 GATEXX_CHECK_EXCEPTION(result);
422 return ret;
423 }
424 Socket::Ip6Address Socket::parseIp6(String const& ip6text)
425 {
426 Ip6Address ret;
427 result_t result = gate_socket_parse_ip6(ip6text.c_impl(), &ret);
428 GATEXX_CHECK_EXCEPTION(result);
429 return ret;
430 }
431 4 Socket::Endpoint Socket::parseAddress(String const& address)
432 {
433 4 Endpoint ret;
434 4 result_t result = gate_socket_parse_endpoint(address.c_impl(), &ret);
435
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATEXX_CHECK_EXCEPTION(result);
436 4 return ret;
437 }
438 2 String Socket::printAddress(Endpoint const& endpoint)
439 {
440 2 gate_string_t text = GATE_STRING_INIT_EMPTY;
441
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 result_t result = gate_socket_print_endpoint(&endpoint, &text);
442
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 GATEXX_CHECK_EXCEPTION(result);
443 4 return String::createFrom(text);
444 }
445
446 } // end of namespace net
447 } // end of namespace gate
448