GCC Code Coverage Report


Directory: src/gate/
File: src/gate/net/sockettools.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 705 987 71.4%
Functions: 63 85 74.1%
Branches: 232 475 48.8%

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/sockettools.h"
29 #include "gate/net/nameresolvers.h"
30 #include "gate/threading.h"
31 #include "gate/synchronization.h"
32 #include "gate/arrays.h"
33 #include "gate/debugging.h"
34 #include "gate/maps.h"
35 #include "gate/platforms.h"
36
37 #define GATE_SOCKETGROUP_LIMIT 512
38
39
40 #if !defined(GATE_SYS_POSIX)
41
42 gate_result_t gate_socketselector_create(gate_socketselector_t* selector)
43 {
44 gate_result_t ret;
45 gate_socket_t sock;
46 do
47 {
48 gate_mem_clear(selector, sizeof(gate_socketselector_t));
49 ret = gate_socket_create_ex(GATE_SOCKET_FAMILY_INET4, GATE_SOCKET_MSGTYPE_STREAM, GATE_SOCKET_PROTOCOL_TCP, &sock);
50 } while (0);
51 selector->handles[0] = (void*)sock;
52 return ret;
53 }
54 gate_result_t gate_socketselector_destroy(gate_socketselector_t* selector)
55 {
56 gate_result_t ret = GATE_RESULT_OK;
57 gate_socket_t sock = (gate_socket_t)(gate_intptr_t)selector->handles[0];
58 gate_socket_close(sock);
59 return ret;
60 }
61 gate_result_t gate_socketselector_interrupt(gate_socketselector_t* selector)
62 {
63 gate_result_t ret;
64 gate_socket_t oldsock = (gate_socket_t)(gate_intptr_t)selector->handles[0];
65 gate_socket_t newsock;
66 do
67 {
68 ret = gate_socket_create_ex(GATE_SOCKET_FAMILY_INET4, GATE_SOCKET_MSGTYPE_STREAM, GATE_SOCKET_PROTOCOL_TCP, &newsock);
69 GATE_BREAK_IF_FAILED(ret);
70
71 selector->handles[0] = (void*)newsock;
72 gate_socket_close(oldsock);
73 } while (0);
74 return ret;
75 }
76 gate_result_t gate_socketselector_select(gate_socketselector_t* selector, gate_socket_t const* socks, gate_size_t sockcount, gate_uint8_t* statusflags, gate_uint32_t timeout)
77 {
78 gate_result_t ret;
79 gate_socket_t local_sockets[GATE_SOCKETGROUP_LIMIT];
80 gate_uint8_t local_flags[GATE_SOCKETGROUP_LIMIT];
81 gate_size_t index;
82 gate_size_t local_sockcount = sockcount;
83 gate_socket_t interruptor = (gate_socket_t)(gate_intptr_t)selector->handles[0];
84
85 if (local_sockcount >= GATE_SOCKETGROUP_LIMIT)
86 {
87 local_sockcount = GATE_SOCKETGROUP_LIMIT - 1;
88 }
89
90 for (index = 0; index != local_sockcount; ++index)
91 {
92 local_sockets[index] = socks[index];
93 local_flags[index] = statusflags[index];
94 }
95 local_sockets[local_sockcount] = interruptor;
96 local_flags[local_sockcount] = GATE_SOCKET_SELECT_FLAG_ERROR;
97
98 ret = gate_socket_select(local_sockets, local_sockcount + 1, local_flags, timeout);
99
100 index = 0;
101 if (GATE_SUCCEEDED(ret))
102 {
103 for (; index != local_sockcount; ++index)
104 {
105 statusflags[index] = local_flags[index];
106 }
107 }
108
109 /* notify NO-ACTION on all non-processed sockets */
110 for (; index < sockcount; ++index)
111 {
112 statusflags[index] = 0;
113 }
114
115 return ret;
116 }
117
118 #else
119
120 #include <unistd.h>
121
122 4 gate_result_t gate_socketselector_create(gate_socketselector_t* selector)
123 {
124 int pipe_fd[2];
125 4 int result = pipe(pipe_fd);
126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (result == -1)
127 {
128 return GATE_RESULT_FAILED;
129 }
130 else
131 {
132 4 selector->handles[0] = (void*)(gate_intptr_t)pipe_fd[0];
133 4 selector->handles[1] = (void*)(gate_intptr_t)pipe_fd[1];
134 4 return GATE_RESULT_OK;
135 }
136 }
137 4 gate_result_t gate_socketselector_destroy(gate_socketselector_t* selector)
138 {
139 4 int read_pipe = (int)(gate_intptr_t)selector->handles[0];
140 4 int write_pipe = (int)(gate_intptr_t)selector->handles[1];
141 4 gate_posix_close(read_pipe);
142 4 gate_posix_close(write_pipe);
143 4 return GATE_RESULT_OK;
144 }
145 27 gate_result_t gate_socketselector_interrupt(gate_socketselector_t* selector)
146 {
147 27 int write_pipe = (int)(gate_intptr_t)selector->handles[1];
148 static char const ch = 'I';
149 27 gate_posix_write(write_pipe, &ch, 1);
150 27 return GATE_RESULT_OK;
151 }
152 34 gate_result_t gate_socketselector_select(gate_socketselector_t* selector, gate_socket_t const* socks, gate_size_t sockcount, gate_uint8_t* statusflags, gate_uint32_t timeout)
153 {
154 gate_result_t ret;
155 gate_socket_t local_sockets[GATE_SOCKETGROUP_LIMIT];
156 gate_uint8_t local_flags[GATE_SOCKETGROUP_LIMIT];
157 gate_size_t index;
158 34 gate_size_t local_sockcount = sockcount;
159 34 gate_socket_t interruptor = (gate_socket_t)(gate_intptr_t)selector->handles[0];
160
161
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (local_sockcount >= GATE_SOCKETGROUP_LIMIT)
162 {
163 local_sockcount = GATE_SOCKETGROUP_LIMIT - 1;
164 }
165
166
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 34 times.
92 for (index = 0; index != local_sockcount; ++index)
167 {
168 58 local_sockets[index] = socks[index];
169 58 local_flags[index] = statusflags[index];
170 }
171 34 local_sockets[local_sockcount] = interruptor;
172 34 local_flags[local_sockcount] = GATE_SOCKET_SELECT_FLAG_RECEIVE | GATE_SOCKET_SELECT_FLAG_ERROR;
173
174 34 ret = gate_socket_select(local_sockets, local_sockcount + 1, local_flags, timeout);
175
176 34 index = 0;
177
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 if (GATE_SUCCEEDED(ret))
178 {
179
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 7 times.
34 if (GATE_FLAG_ENABLED(local_flags[local_sockcount], GATE_SOCKET_SELECT_FLAG_RECEIVE))
180 {
181 char buf[1];
182 27 gate_posix_read((int)interruptor, buf, 1);
183 }
184
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 34 times.
92 for (; index != local_sockcount; ++index)
185 {
186 58 statusflags[index] = local_flags[index];
187 }
188 }
189
190 /* notify NO-ACTION on all non-processed sockets */
191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 for (; index < sockcount; ++index)
192 {
193 statusflags[index] = 0;
194 }
195
196 34 return ret;
197 }
198
199
200 #endif
201
202
203
204 typedef struct gate_socketgroup_task
205 {
206 gate_socket_t sock;
207 int command;
208 gate_size_t length;
209 gate_size_t offset;
210 void* param;
211 gate_intptr_t info;
212 gate_bool_t completed;
213 char data[1];
214
215 } gate_socketgroup_task_t;
216
217 27 static gate_socketgroup_task_t* gate_socketgroup_task_create(int command, gate_size_t datalength, gate_size_t allocatelength, void* param)
218 {
219 27 gate_socketgroup_task_t* ret = (gate_socketgroup_task_t*)gate_mem_alloc(sizeof(gate_socketgroup_task_t) + allocatelength);
220
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 if (ret)
221 {
222 27 gate_mem_clear(ret, sizeof(gate_socketgroup_task_t) + allocatelength);
223 27 ret->command = command;
224 27 ret->offset = 0;
225 27 ret->length = datalength;
226 27 ret->param = param;
227 27 ret->completed = false;
228 }
229 27 return ret;
230 }
231
232 27 static void gate_socketgroup_task_destroy(gate_socketgroup_task_t* task)
233 {
234 27 gate_mem_dealloc(task);
235 27 }
236
237
238 4 gate_result_t gate_socketgroup_create(gate_socketgroup_t* group, void* user_tag)
239 {
240 4 gate_result_t ret = GATE_RESULT_OK;
241 do
242 {
243 4 gate_mem_clear(group, sizeof(gate_socketgroup_t));
244 4 gate_atomic_int_set(&group->running, 0);
245
246 4 ret = gate_socketselector_create(&group->selector);
247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATE_BREAK_IF_FAILED(ret);
248
249 4 group->tasks = gate_arraylist_create(sizeof(gate_socketgroup_task_t*), NULL, 0, NULL, NULL);
250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!group->tasks)
251 {
252 gate_socketselector_destroy(&group->selector);
253 ret = GATE_RESULT_OUTOFMEMORY;
254 break;
255 }
256 4 ret = gate_mutex_create(&group->mutex);
257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (GATE_FAILED(ret))
258 {
259 gate_arraylist_release(group->tasks);
260 gate_socketselector_destroy(&group->selector);
261 break;
262 }
263 4 group->interval_ms = 500;
264 4 group->user_tag = user_tag;
265 } while (0);
266 4 return ret;
267 }
268
269 4 gate_result_t gate_socketgroup_destroy(gate_socketgroup_t* group)
270 {
271 4 gate_result_t ret = GATE_RESULT_OK;
272 gate_result_t result;
273 4 gate_socketgroup_quit(group);
274
275 4 result = gate_socketgroup_clear(group);
276
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (GATE_FAILED(result)) ret = result;
277
278 4 gate_arraylist_release(group->tasks);
279 4 gate_socketselector_destroy(&group->selector);
280
281 4 result = gate_mutex_destroy(&group->mutex);
282
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (GATE_FAILED(result)) ret = result;
283
284 4 return ret;
285 }
286 7 gate_result_t gate_socketgroup_clear(gate_socketgroup_t* group)
287 {
288 7 gate_result_t ret = GATE_RESULT_FAILED;
289 gate_size_t index;
290 gate_size_t sockcount;
291 gate_socketgroup_task_t** ptr_task;
292 do
293 {
294 7 ret = gate_mutex_acquire(&group->mutex);
295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 GATE_BREAK_IF_FAILED(ret);
296
297 do
298 {
299 7 sockcount = gate_arraylist_length(group->tasks);
300
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 for (index = 0; index != sockcount; ++index)
301 {
302 1 ptr_task = (gate_socketgroup_task_t**)gate_arraylist_get(group->tasks, index);
303
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (ptr_task && *ptr_task)
304 {
305 1 gate_socketgroup_task_destroy(*ptr_task);
306 }
307 }
308 7 gate_arraylist_clear(group->tasks);
309
310 } while (0);
311 7 gate_mutex_release(&group->mutex);
312
313 } while (0);
314 7 return ret;
315 }
316
317 10 static gate_bool_t gate_socketgroup_remove_condition(void const* item, void* param)
318 {
319 10 gate_socketgroup_task_t* const* task = (gate_socketgroup_task_t* const*)item;
320 10 gate_socket_t* sock = (gate_socket_t*)param;
321
5/6
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 4 times.
10 if (task && (*task) && ((*task)->sock == *sock))
322 {
323 /* delete task pointer and return true to remove it from arraylist */
324 2 gate_socketgroup_task_destroy(*task);
325 2 return true;
326 }
327 8 return false;
328 }
329
330 27 static gate_bool_t gate_socketgroup_integrate_task(gate_socketgroup_t* group, gate_socketgroup_task_t* task)
331 {
332 27 gate_size_t len = gate_arraylist_length(group->tasks);
333
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 3 times.
27 if (len != 0)
334 {
335 /* find empty slot to overwrite: */
336 24 gate_socketgroup_task_t** tasks = (gate_socketgroup_task_t**)gate_arraylist_get(group->tasks, 0);
337
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 8 times.
42 for (; len != 0; --len, ++tasks)
338 {
339
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 18 times.
34 if (*tasks == NULL)
340 {
341 16 *tasks = task;
342 16 return true;
343 }
344 }
345 }
346 /* add new entry */
347 11 return NULL != gate_arraylist_add(group->tasks, &task);
348 }
349
350 6 gate_result_t gate_socketgroup_remove(gate_socketgroup_t* group, gate_socket_t sock)
351 {
352 6 gate_result_t ret = GATE_RESULT_FAILED;
353 do
354 {
355 6 ret = gate_mutex_acquire(&group->mutex);
356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 GATE_BREAK_IF_FAILED(ret);
357
358 do
359 {
360 6 ret = gate_arraylist_remove_if(group->tasks, &gate_socketgroup_remove_condition, &sock);
361 } while (0);
362 6 gate_mutex_release(&group->mutex);
363
364 } while (0);
365 6 return ret;
366 }
367
368 3 gate_result_t gate_socketgroup_connect(gate_socketgroup_t* group, gate_socket_t sock, gate_socket_endpoint_t const* endpoint, void* param)
369 {
370 3 gate_result_t ret = GATE_RESULT_OK;
371 do
372 {
373 3 gate_socketgroup_task_t* task = gate_socketgroup_task_create(GATE_SOCKETGROUP_OPERATION_CONNECT, 0, 0, param);
374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!task)
375 {
376 ret = GATE_RESULT_OUTOFMEMORY;
377 break;
378 }
379 3 ret = gate_socket_connect(sock, endpoint);
380
381
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(ret))
382 {
383 gate_socketgroup_task_destroy(task);
384 }
385 else
386 {
387 3 task->sock = sock;
388 3 ret = gate_mutex_acquire(&group->mutex);
389
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (GATE_SUCCEEDED(ret))
390 {
391
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (!gate_socketgroup_integrate_task(group, task))
392 {
393 gate_socketgroup_task_destroy(task);
394 ret = GATE_RESULT_OUTOFMEMORY;
395 }
396 3 gate_mutex_release(&group->mutex);
397 }
398 3 gate_socketselector_interrupt(&group->selector);
399 }
400 } while (0);
401 3 return ret;
402 }
403 7 gate_result_t gate_socketgroup_accept(gate_socketgroup_t* group, gate_socket_t sock, void* param)
404 {
405 7 gate_result_t ret = GATE_RESULT_OK;
406 do
407 {
408 7 gate_socketgroup_task_t* task = gate_socketgroup_task_create(GATE_SOCKETGROUP_OPERATION_ACCEPT, 0, 0, param);
409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (!task)
410 {
411 ret = GATE_RESULT_OUTOFMEMORY;
412 break;
413 }
414 7 task->sock = sock;
415 {
416 7 ret = gate_mutex_acquire(&group->mutex);
417
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (GATE_SUCCEEDED(ret))
418 {
419
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 if (!gate_socketgroup_integrate_task(group, task))
420 {
421 gate_socketgroup_task_destroy(task);
422 ret = GATE_RESULT_OUTOFMEMORY;
423 }
424 7 gate_mutex_release(&group->mutex);
425 }
426 7 gate_socketselector_interrupt(&group->selector);
427 }
428 } while (0);
429 7 return ret;
430 }
431 8 gate_result_t gate_socketgroup_read(gate_socketgroup_t* group, gate_socket_t sock, gate_size_t length, void* param)
432 {
433 8 gate_result_t ret = GATE_RESULT_OK;
434 do
435 {
436 8 gate_socketgroup_task_t* task = gate_socketgroup_task_create(GATE_SOCKETGROUP_OPERATION_READ, 0, 0, param);
437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!task)
438 {
439 ret = GATE_RESULT_OUTOFMEMORY;
440 break;
441 }
442 8 task->length = length;
443 8 task->sock = sock;
444 {
445 8 ret = gate_mutex_acquire(&group->mutex);
446
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (GATE_SUCCEEDED(ret))
447 {
448
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if (!gate_socketgroup_integrate_task(group, task))
449 {
450 gate_socketgroup_task_destroy(task);
451 ret = GATE_RESULT_OUTOFMEMORY;
452 }
453 8 gate_mutex_release(&group->mutex);
454 }
455 8 gate_socketselector_interrupt(&group->selector);
456 }
457 } while (0);
458 8 return ret;
459 }
460 7 gate_result_t gate_socketgroup_write(gate_socketgroup_t* group, gate_socket_t sock, char const* data, gate_size_t length, void* param)
461 {
462 7 gate_result_t ret = GATE_RESULT_OK;
463 do
464 {
465 7 gate_socketgroup_task_t* task = gate_socketgroup_task_create(GATE_SOCKETGROUP_OPERATION_WRITE, length, length, param);
466
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (!task)
467 {
468 ret = GATE_RESULT_OUTOFMEMORY;
469 break;
470 }
471
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (length != 0)
472 {
473 7 gate_mem_copy(task->data, data, length);
474 }
475 7 task->sock = sock;
476 {
477 7 ret = gate_mutex_acquire(&group->mutex);
478
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (GATE_SUCCEEDED(ret))
479 {
480
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 if (!gate_socketgroup_integrate_task(group, task))
481 {
482 gate_socketgroup_task_destroy(task);
483 ret = GATE_RESULT_OUTOFMEMORY;
484 }
485 7 gate_mutex_release(&group->mutex);
486 }
487 7 gate_socketselector_interrupt(&group->selector);
488 }
489 } while (0);
490 7 return ret;
491 }
492 2 gate_result_t gate_socketgroup_shutdown_write(gate_socketgroup_t* group, gate_socket_t sock, void* param)
493 {
494 2 gate_result_t ret = GATE_RESULT_OK;
495 do
496 {
497 2 gate_socketgroup_task_t* task = gate_socketgroup_task_create(GATE_SOCKETGROUP_OPERATION_SHUTDOWN_WRITE, 0, 0, param);
498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!task)
499 {
500 ret = GATE_RESULT_OUTOFMEMORY;
501 break;
502 }
503 2 task->sock = sock;
504 {
505 2 ret = gate_mutex_acquire(&group->mutex);
506
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (GATE_SUCCEEDED(ret))
507 {
508
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (!gate_socketgroup_integrate_task(group, task))
509 {
510 gate_socketgroup_task_destroy(task);
511 ret = GATE_RESULT_OUTOFMEMORY;
512 }
513 2 gate_mutex_release(&group->mutex);
514 }
515 2 gate_socketselector_interrupt(&group->selector);
516 }
517 } while (0);
518 2 return ret;
519 }
520
521
522 62 static gate_size_t gate_socketgroup_find_socket(gate_socket_t* sockets, gate_size_t socketcount, gate_socket_t target)
523 {
524 62 gate_size_t sockindex = 0;
525
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 58 times.
91 while (socketcount-- != 0)
526 {
527
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 29 times.
33 if (*sockets == target)
528 {
529 4 return sockindex;
530 }
531 29 ++sockets;
532 29 ++sockindex;
533 }
534 58 return GATE_INVALID_SIZE;
535 }
536
537 33 static gate_size_t gate_socketgroup_load_sockets(gate_socketgroup_task_t* const* tasks, gate_size_t taskcount,
538 gate_socket_t* sockets, gate_uint8_t* flags, gate_size_t maxsockets)
539 {
540 33 gate_size_t sockets_used = 0;
541 gate_size_t sockindex;
542 gate_socketgroup_task_t* current_task;
543
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (taskcount > maxsockets)
544 {
545 taskcount = maxsockets;
546 }
547
548
1/2
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
95 while ((taskcount-- != 0) && (sockets_used < maxsockets))
549 {
550 62 current_task = *tasks;
551 62 ++tasks;
552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 if (current_task == NULL)
553 {
554 /* skip empty tasks */
555 continue;
556 }
557 62 sockindex = gate_socketgroup_find_socket(sockets, sockets_used, current_task->sock);
558
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 4 times.
62 if (sockindex == GATE_INVALID_SIZE)
559 {
560 58 sockindex = sockets_used++;
561 58 sockets[sockindex] = current_task->sock;
562 58 flags[sockindex] = GATE_SOCKET_SELECT_FLAG_ERROR;
563 }
564
565
3/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
62 switch (current_task->command)
566 {
567 48 case GATE_SOCKETGROUP_OPERATION_ACCEPT:
568 case GATE_SOCKETGROUP_OPERATION_READ:
569 {
570 48 flags[sockindex] |= GATE_SOCKET_SELECT_FLAG_RECEIVE;
571 48 break;
572 }
573 11 case GATE_SOCKETGROUP_OPERATION_WRITE:
574 case GATE_SOCKETGROUP_OPERATION_SHUTDOWN_WRITE:
575 {
576 11 flags[sockindex] |= GATE_SOCKET_SELECT_FLAG_SEND;
577 11 break;
578 }
579 3 case GATE_SOCKETGROUP_OPERATION_CONNECT:
580 {
581 3 flags[sockindex] |= GATE_SOCKET_SELECT_FLAG_SEND;
582 3 break;
583 }
584 }
585
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 33 times.
95 }
586 33 return sockets_used;
587 }
588
589 24 static gate_size_t gate_socketgroup_find_task(gate_socketgroup_task_t* const* tasks, gate_size_t taskcount,
590 gate_socket_t target, gate_uint8_t flag)
591 {
592 24 gate_size_t task_index = 0;
593
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 while (taskcount-- != 0)
594 {
595
4/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 8 times.
35 if ((*tasks) && (*tasks)->sock == target)
596 {
597
2/3
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 switch ((*tasks)->command)
598 {
599 12 case GATE_SOCKETGROUP_OPERATION_CONNECT:
600 case GATE_SOCKETGROUP_OPERATION_WRITE:
601 case GATE_SOCKETGROUP_OPERATION_SHUTDOWN_WRITE:
602 {
603
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (GATE_FLAG_ENABLED(flag, GATE_SOCKET_SELECT_FLAG_SEND))
604 {
605 12 return task_index;
606 }
607 break;
608 }
609 12 case GATE_SOCKETGROUP_OPERATION_ACCEPT:
610 case GATE_SOCKETGROUP_OPERATION_READ:
611 {
612
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (GATE_FLAG_ENABLED(flag, GATE_SOCKET_SELECT_FLAG_RECEIVE))
613 {
614 12 return task_index;
615 }
616 break;
617 }
618 }
619
620 if (GATE_FLAG_ENABLED(flag, GATE_SOCKET_SELECT_FLAG_ERROR))
621 {
622 /* errors are always communicated */
623 return task_index;
624 }
625 }
626 11 ++task_index;
627 11 ++tasks;
628 }
629 return GATE_INVALID_SIZE;
630 }
631
632 32 static gate_size_t gate_socketgroup_load_tasks(gate_socket_t const* sockets, gate_uint8_t* flags, gate_size_t socketcount,
633 gate_socketgroup_task_t** tasks, gate_size_t taskcount,
634 gate_socketgroup_task_t** localtasks, gate_size_t max_localtasks)
635 {
636 32 gate_size_t localtasks_used = 0;
637 gate_size_t taskindex;
638 gate_size_t sockindex;
639
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if (taskcount > max_localtasks)
640 {
641 taskcount = max_localtasks;
642 }
643
644
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 32 times.
89 for (sockindex = 0; sockindex != socketcount; ++sockindex)
645 {
646
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 24 times.
57 if (flags[sockindex] == 0)
647 {
648 /* skip socket with no activity */
649 33 continue;
650 }
651
652 24 taskindex = gate_socketgroup_find_task(tasks, taskcount, sockets[sockindex], flags[sockindex]);
653
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (taskindex == GATE_INVALID_SIZE)
654 {
655 /* skip sockets with no associated task */
656 continue;
657 }
658 /* put task into local-tasks buffer */
659
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (tasks[taskindex])
660 {
661 24 localtasks[localtasks_used] = tasks[taskindex];
662 24 localtasks[localtasks_used]->info = flags[sockindex];
663 24 tasks[taskindex] = NULL; /* remove task pointer from array */
664 24 ++localtasks_used;
665 }
666 }
667
668 32 return localtasks_used;
669 }
670 67 static gate_bool_t gate_socketgroup_remove_completed_task(void const* item, void* param)
671 {
672 67 gate_socketgroup_task_t* const* ptr_task = (gate_socketgroup_task_t* const*)item;
673 (void)param;
674
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 if (ptr_task != NULL)
675 {
676
2/2
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 8 times.
67 if (*ptr_task != NULL)
677 {
678
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59 times.
59 if ((*ptr_task)->completed)
679 {
680 gate_socketgroup_task_destroy(*ptr_task);
681 return true;
682 }
683 else
684 {
685 59 return false;
686 }
687 }
688 8 return true;
689 }
690 GATE_DEBUG_BREAKPOINT;
691 return false;
692 }
693
694 3 gate_result_t gate_socketgroup_run(gate_socketgroup_t* group, gate_socketgroup_callback_t callback)
695 {
696 gate_result_t ret;
697 3 gate_int32_t prev_state = gate_atomic_int_xchg_if(&group->running, 0, 1);
698 gate_socket_t sockets[GATE_SOCKETGROUP_LIMIT];
699 gate_uint8_t flags[GATE_SOCKETGROUP_LIMIT];
700 gate_size_t sockets_used;
701 gate_socketgroup_task_t* localtasks[GATE_SOCKETGROUP_LIMIT];
702 gate_size_t localtasks_used;
703 gate_size_t localtask_index;
704
705 gate_socketgroup_task_t** tasks;
706 gate_size_t task_count;
707 gate_socketgroup_task_t* current_task;
708 gate_bool_t error_detected;
709 char buffer[1024 * 6 + 1];
710 gate_size_t buffer_len;
711 gate_size_t buffer_used;
712 gate_socket_t new_sock;
713
714 do
715 {
716
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (prev_state != 0)
717 {
718 ret = GATE_RESULT_INVALIDSTATE;
719 break;
720 }
721
722 3 ret = GATE_RESULT_OK;
723
724
2/2
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 3 times.
37 while (gate_atomic_int_get(&group->running) == 1)
725 {
726 {
727 /* idle event */
728 34 callback(group, GATE_SOCKETGROUP_OPERATION_PREPARE, GATE_SOCKET_INVALID, GATE_RESULT_OK, NULL, NULL, 0);
729 }
730
731 34 sockets_used = 0;
732 { /* mutex section */
733 34 ret = gate_mutex_acquire(&group->mutex);
734
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 GATE_BREAK_IF_FAILED(ret);
735
736 34 task_count = gate_arraylist_length(group->tasks);
737
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 1 times.
34 if (task_count != 0)
738 {
739 33 tasks = (gate_socketgroup_task_t**)gate_arraylist_get(group->tasks, 0);
740
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (tasks != NULL)
741 {
742 33 sockets_used = gate_socketgroup_load_sockets(tasks, task_count, sockets, flags, GATE_SOCKETGROUP_LIMIT);
743 }
744 }
745 34 gate_mutex_release(&group->mutex);
746 }
747
748 34 ret = gate_socketselector_select(&group->selector, sockets, sockets_used, flags, group->interval_ms);
749
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 GATE_BREAK_IF_FAILED(ret);
750
751 34 localtasks_used = 0;
752 { /* mutex section */
753 34 ret = gate_mutex_acquire(&group->mutex);
754
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 GATE_BREAK_IF_FAILED(ret);
755
756 34 task_count = gate_arraylist_length(group->tasks);
757
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 2 times.
34 if (task_count != 0)
758 {
759 32 tasks = (gate_socketgroup_task_t**)gate_arraylist_get(group->tasks, 0);
760
761 32 localtasks_used = gate_socketgroup_load_tasks(sockets, flags, sockets_used, tasks, task_count, localtasks, GATE_SOCKETGROUP_LIMIT);
762 }
763
764 34 gate_mutex_release(&group->mutex);
765 }
766
767
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 34 times.
58 for (localtask_index = 0; localtask_index != localtasks_used; ++localtask_index)
768 {
769 24 current_task = localtasks[localtask_index];
770 24 error_detected = GATE_FLAG_ENABLED(current_task->info, GATE_SOCKET_SELECT_FLAG_ERROR);
771
772
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (error_detected)
773 {
774 current_task->completed = true;
775 callback(group, current_task->command, current_task->sock, GATE_RESULT_CRITICALERROR, current_task->param, NULL, 0);
776 }
777 else
778 {
779
5/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
24 switch (current_task->command)
780 {
781 3 case GATE_SOCKETGROUP_OPERATION_CONNECT:
782 {
783 3 gate_bool_t error_flag = false;
784 3 gate_socket_has_error(current_task->sock, &error_flag);
785 3 current_task->completed = true;
786
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (error_flag)
787 {
788 1 callback(group, GATE_SOCKETGROUP_OPERATION_CONNECT, current_task->sock,
789 GATE_RESULT_NOTAVAILABLE, current_task->param, NULL, 0);
790 }
791 else
792 {
793 2 callback(group, GATE_SOCKETGROUP_OPERATION_CONNECT, current_task->sock,
794 GATE_RESULT_OK, current_task->param, NULL, 0);
795 }
796 3 break;
797 }
798 4 case GATE_SOCKETGROUP_OPERATION_ACCEPT:
799 {
800 4 current_task->completed = true;
801 4 ret = gate_socket_accept(current_task->sock, &new_sock);
802
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (GATE_FAILED(ret))
803 {
804 callback(group, GATE_SOCKETGROUP_OPERATION_ACCEPT, current_task->sock, ret, current_task->param,
805 NULL, 0);
806 }
807 else
808 {
809 4 callback(group, GATE_SOCKETGROUP_OPERATION_ACCEPT, new_sock, GATE_RESULT_OK, current_task->param,
810 4 (char const*)&current_task->sock, sizeof(current_task->sock));
811 }
812 4 break;
813 }
814 8 case GATE_SOCKETGROUP_OPERATION_READ:
815 {
816 8 current_task->completed = true;
817 8 buffer_len = sizeof(buffer) - 1;
818
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (buffer_len > current_task->length)
819 {
820 8 buffer_len = current_task->length;
821 }
822 8 ret = gate_socket_receive(current_task->sock, buffer, buffer_len, &buffer_used);
823
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (GATE_SUCCEEDED(ret))
824 {
825 8 buffer[buffer_used] = 0;
826 }
827
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 callback(group, GATE_SOCKETGROUP_OPERATION_READ, current_task->sock, ret, current_task->param,
828 GATE_FAILED(ret) ? NULL : buffer, GATE_FAILED(ret) ? 0 : buffer_used);
829 8 break;
830 }
831 7 case GATE_SOCKETGROUP_OPERATION_WRITE:
832 {
833
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (current_task->offset < current_task->length)
834 {
835 7 ret = gate_socket_send(current_task->sock, &current_task->data[current_task->offset],
836 7 current_task->length - current_task->offset, &buffer_used);
837
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (GATE_FAILED(ret))
838 {
839 current_task->completed = true;
840 callback(group, GATE_SOCKETGROUP_OPERATION_WRITE, current_task->sock, ret, current_task->param,
841 current_task->data, current_task->length);
842 break;
843 }
844 7 current_task->offset += buffer_used;
845 }
846
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (current_task->offset >= current_task->length)
847 {
848 7 current_task->completed = true;
849 14 callback(group, GATE_SOCKETGROUP_OPERATION_WRITE, current_task->sock, GATE_RESULT_OK, current_task->param,
850 7 current_task->data, current_task->length);
851 }
852
853 7 break;
854 }
855 2 case GATE_SOCKETGROUP_OPERATION_SHUTDOWN_WRITE:
856 {
857 2 ret = gate_socket_shutdown(current_task->sock, false, true);
858 2 current_task->completed = true;
859 2 callback(group, GATE_SOCKETGROUP_OPERATION_SHUTDOWN_WRITE, current_task->sock, ret, current_task->param,
860 NULL, 0);
861 2 break;
862 }
863 }
864 24 }
865
866 } /* for(all localtask */
867
868 { /* mutex section */
869 34 ret = gate_mutex_acquire(&group->mutex);
870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 GATE_BREAK_IF_FAILED(ret);
871
872
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 34 times.
58 for (localtask_index = 0; localtask_index != localtasks_used; ++localtask_index)
873 {
874 24 current_task = localtasks[localtask_index];
875
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (current_task->completed)
876 {
877 24 gate_socketgroup_task_destroy(current_task);
878 }
879 else
880 {
881 if (!gate_socketgroup_integrate_task(group, current_task))
882 {
883 GATE_DEBUG_BREAKPOINT;
884 }
885 }
886 }
887
888 34 ret = gate_arraylist_remove_if(group->tasks, &gate_socketgroup_remove_completed_task, NULL);
889
890 34 gate_mutex_release(&group->mutex);
891
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 GATE_BREAK_IF_FAILED(ret);
892 }
893
894 } /* while running */
895
896 3 gate_atomic_int_set(&group->running, 0);
897
898 } while (0);
899
900 3 return ret;
901 }
902 7 gate_result_t gate_socketgroup_quit(gate_socketgroup_t* group)
903 {
904 7 gate_atomic_int_set(&group->running, 0);
905 7 return GATE_RESULT_OK;
906 }
907
908
909
910
911
912
913
914
915
916
917
918 /*
919 typedef struct gate_socket_request_class
920 {
921 gate_dataqueue_status_t callback;
922 gate_size_t length;
923 gate_size_t used;
924 char buffer[1];
925 } gate_socket_request_t;
926
927
928 static gate_socket_request_t* gate_socket_request_create(gate_dataqueue_status_t callback, gate_size_t length, char const* data)
929 {
930 gate_socket_request_t* ret = (gate_socket_request_t*)gate_mem_alloc(sizeof(gate_socket_request_t) + length);
931 if(ret != NULL)
932 {
933 ret->callback = callback;
934 ret->used = 0;
935 ret->length = length;
936 if(data != NULL)
937 {
938 gate_mem_copy(&ret->buffer[0], data, length);
939 ret->buffer[length] = 0;
940 }
941 else
942 {
943 ret->buffer[0] = 0;
944 }
945 }
946 return ret;
947 }
948 static void gate_socket_request_release(gate_socket_request_t* request)
949 {
950 gate_mem_dealloc(request);
951 }
952
953 typedef struct gate_socket_channel_class
954 {
955 gate_channel_id_t id;
956 gate_socket_t sock;
957 gate_arraylist_t read_requests;
958 gate_arraylist_t write_requests;
959
960 } gate_socket_channel_t;
961
962 static gate_socket_channel_t* gate_socket_channel_create()
963 {
964 gate_socket_channel_t* channel = gate_mem_alloc(sizeof(gate_socket_channel_t));
965 gate_mem_clear(channel, sizeof(gate_socket_channel_t));
966 channel->sock = GATE_SOCKET_INVALID;
967 return channel;
968 }
969 static void gate_socket_channel_release(gate_socket_channel_t* channel)
970 {
971 if(channel->sock != GATE_SOCKET_INVALID)
972 {
973 gate_socket_close(channel->sock);
974 }
975 gate_mem_dealloc(channel);
976 }
977 */
978
979 #define GATE_SOCKETQUEUE_STATE_OFFLINE 0
980 #define GATE_SOCKETQUEUE_STATE_STARTING 1
981 #define GATE_SOCKETQUEUE_STATE_ONLINE 2
982 #define GATE_SOCKETQUEUE_STATE_STOPPING 3
983
984 typedef struct gate_socketqueue_impl_class
985 {
986 GATE_INTERFACE_VTBL(gate_socketqueue) const* vtbl;
987
988 gate_atomic_int_t ref_counter;
989 gate_atomic_int_t state;
990 gate_atomic_int_t max_channel_id;
991 gate_thread_t thread;
992 gate_mutex_t lock;
993 gate_map_t channel_2_sock;
994 gate_map_t sock_2_channel;
995 gate_socketgroup_t sockets;
996 gate_dataqueue_status_t next_callback;
997 void* next_callback_data;
998 gate_dataqueue_status_t callback;
999 void* callback_data;
1000
1001 } gate_socketqueue_impl_t;
1002
1003 25 static gate_bool_t gate_socketqueue_impl_new_state(gate_socketqueue_impl_t* impl, gate_int32_t from_state, gate_int32_t to_state)
1004 {
1005 25 gate_int32_t old_state = gate_atomic_int_xchg_if(&impl->state, from_state, to_state);
1006 25 return old_state == from_state;
1007 }
1008 3 static gate_int32_t gate_socketqueue_impl_set_state(gate_socketqueue_impl_t* impl, gate_int32_t to_state)
1009 {
1010 3 gate_int32_t old_state = gate_atomic_int_set(&impl->state, to_state);
1011 3 return old_state;
1012 }
1013
1014 17 static gate_result_t gate_socketqueue_impl_resolve_socket(gate_socketqueue_impl_t* impl, gate_channel_id_t id, gate_socket_t* ptr_sock)
1015 {
1016 gate_result_t ret;
1017 gate_map_iterator_t iter;
1018 do
1019 {
1020 17 iter = gate_map_get(&impl->channel_2_sock, &id);
1021
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 if (gate_map_iterator_valid(iter))
1022 {
1023 17 *ptr_sock = GATE_MAP_ITER_VALUE(gate_socket_t, iter);
1024 17 ret = GATE_RESULT_OK;
1025 }
1026 else
1027 {
1028 ret = GATE_RESULT_NOMATCH;
1029 }
1030 } while (0);
1031 17 return ret;
1032 }
1033 24 static gate_result_t gate_socketqueue_impl_resolve_channel(gate_socketqueue_impl_t* impl, gate_socket_t sock, gate_channel_id_t* ptr_id)
1034 {
1035 gate_result_t ret;
1036 gate_map_iterator_t iter;
1037 do
1038 {
1039 24 iter = gate_map_get(&impl->sock_2_channel, &sock);
1040
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 if (gate_map_iterator_valid(iter))
1041 {
1042 24 *ptr_id = GATE_MAP_ITER_VALUE(gate_channel_id_t, iter);
1043 24 ret = GATE_RESULT_OK;
1044 }
1045 else
1046 {
1047 ret = GATE_RESULT_NOMATCH;
1048 }
1049 } while (0);
1050 24 return ret;
1051 }
1052 10 static gate_result_t gate_socketqueue_impl_register(gate_socketqueue_impl_t* impl, gate_socket_t sock, gate_channel_id_t channel_id)
1053 {
1054 gate_result_t ret;
1055 do
1056 {
1057
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (!gate_map_iterator_valid(gate_map_add(&impl->sock_2_channel, &sock, &channel_id)))
1058 {
1059 ret = GATE_RESULT_OUTOFMEMORY;
1060 break;
1061 }
1062
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (!gate_map_iterator_valid(gate_map_add(&impl->channel_2_sock, &channel_id, &sock)))
1063 {
1064 ret = GATE_RESULT_OUTOFMEMORY;
1065 gate_map_remove(&impl->sock_2_channel, &sock);
1066 break;
1067 }
1068 10 ret = GATE_RESULT_OK;
1069 } while (0);
1070 10 return ret;
1071 }
1072
1073 58 static void gate_socketqueue_group_callback(gate_socketgroup_t* group, gate_uint32_t operation, gate_socket_t sock,
1074 gate_result_t result, void* user_param, char const* data, gate_size_t data_len)
1075 {
1076 gate_result_t res;
1077 58 gate_socketqueue_impl_t* impl = (gate_socketqueue_impl_t*)group->user_tag;
1078 58 gate_channel_id_t channel_id = GATE_QUEUE_INVALID_ID;
1079 58 gate_socket_t parent_socket = GATE_SOCKET_INVALID;
1080 gate_channel_id_t parent_channel_id;
1081
1082 {
1083
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
58 if (GATE_FAILED(res = gate_mutex_acquire(&impl->lock)))
1084 {
1085 gate_socket_close(sock);
1086 return;
1087 }
1088
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 54 times.
58 if (operation == GATE_SOCKETGROUP_OPERATION_ACCEPT)
1089 {
1090 4 channel_id = gate_atomic_int_inc(&impl->max_channel_id);
1091 4 res = gate_socketqueue_impl_register(impl, sock, channel_id);
1092
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (GATE_FAILED(res))
1093 {
1094 gate_socket_close(sock);
1095 result = res;
1096 }
1097 else
1098 {
1099 4 parent_channel_id = 0;
1100 4 parent_socket = *(gate_socket_t const*)data;
1101 4 gate_socketqueue_impl_resolve_channel(impl, parent_socket, &parent_channel_id);
1102 }
1103 }
1104
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 34 times.
54 else if (operation != GATE_SOCKETGROUP_OPERATION_PREPARE)
1105 {
1106 20 res = gate_socketqueue_impl_resolve_channel(impl, sock, &channel_id);
1107 }
1108 58 gate_mutex_release(&impl->lock);
1109 }
1110
1111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (GATE_FAILED(res))
1112 {
1113 impl->callback(impl->callback_data, GATE_DATAQUEUE_RESULT_ERROR, 0, res, NULL, 0, user_param);
1114 }
1115 else
1116 {
1117
6/8
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 34 times.
✗ Branch 7 not taken.
58 switch (operation)
1118 {
1119 4 case GATE_SOCKETGROUP_OPERATION_ACCEPT:
1120 {
1121 4 impl->callback(impl->callback_data, GATE_DATAQUEUE_RESULT_OPENNEW, channel_id, result,
1122 (char const*)&parent_channel_id, sizeof(parent_channel_id), user_param);
1123 4 gate_socketgroup_accept(&impl->sockets, parent_socket, user_param);
1124 4 break;
1125 /* accepts are automatically repeated until server socket is closed */
1126 }
1127 3 case GATE_SOCKETGROUP_OPERATION_CONNECT:
1128 {
1129 3 impl->callback(impl->callback_data, GATE_DATAQUEUE_RESULT_OPEN, channel_id, result, NULL, 0, user_param);
1130 3 break;
1131 }
1132 8 case GATE_SOCKETGROUP_OPERATION_READ:
1133 {
1134
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
8 if (data_len == 0)
1135 {
1136 3 impl->callback(impl->callback_data, GATE_DATAQUEUE_RESULT_CLOSE, channel_id, result, NULL, 0, user_param);
1137 }
1138 else
1139 {
1140 5 impl->callback(impl->callback_data, GATE_DATAQUEUE_RESULT_READ, channel_id, result, data, data_len, user_param);
1141 }
1142 8 break;
1143 }
1144 7 case GATE_SOCKETGROUP_OPERATION_WRITE:
1145 {
1146 7 impl->callback(impl->callback_data, GATE_DATAQUEUE_RESULT_WRITE, channel_id, result, data, data_len, user_param);
1147 7 break;
1148 }
1149 2 case GATE_SOCKETGROUP_OPERATION_SHUTDOWN_WRITE:
1150 {
1151 2 impl->callback(impl->callback_data, GATE_DATAQUEUE_RESULT_WRITE, channel_id, result, NULL, 0, user_param);
1152 2 break;
1153 }
1154 case GATE_SOCKETGROUP_OPERATION_ERROR:
1155 {
1156 impl->callback(impl->callback_data, GATE_DATAQUEUE_RESULT_ERROR, channel_id, result, data, data_len, user_param);
1157 break;
1158 }
1159 34 case GATE_SOCKETGROUP_OPERATION_PREPARE:
1160 {
1161 34 impl->callback(impl->callback_data, GATE_DATAQUEUE_RESULT_HEARTBEAT, GATE_QUEUE_INVALID_ID, result, NULL, 0, user_param);
1162 34 break;
1163 }
1164 }
1165 58 }
1166 }
1167
1168 3 static gate_result_t gate_socketqueue_impl_worker(void* data)
1169 {
1170 3 gate_result_t ret = GATE_RESULT_OK;
1171 3 gate_socketqueue_impl_t* impl = (gate_socketqueue_impl_t*)data;
1172
1173
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (!gate_socketqueue_impl_new_state(impl, GATE_SOCKETQUEUE_STATE_STARTING, GATE_SOCKETQUEUE_STATE_ONLINE))
1174 {
1175 return GATE_RESULT_INVALIDSTATE;
1176 }
1177
1178 do
1179 {
1180 3 ret = gate_socketgroup_run(&impl->sockets, &gate_socketqueue_group_callback);
1181 if (GATE_FAILED(ret))
1182 {
1183 /* TODO */
1184 }
1185
1186
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 } while (gate_socketqueue_impl_new_state(impl, GATE_SOCKETQUEUE_STATE_ONLINE, GATE_SOCKETQUEUE_STATE_ONLINE));
1187 3 return ret;
1188 }
1189
1190
1191 4 static int gate_socketqueue_impl_retain(void* obj)
1192 {
1193 4 gate_socketqueue_impl_t* impl = (gate_socketqueue_impl_t*)obj;
1194 4 return gate_atomic_int_inc(&impl->ref_counter);
1195 }
1196 static char const* gate_socketqueue_impl_get_interface_name(void* obj)
1197 {
1198 (void)obj;
1199 return GATE_INTERFACE_NAME_SOCKETQUEUE;
1200 }
1201
1202
1203 3 static gate_result_t gate_socketqueue_impl_start(void* obj)
1204 {
1205 3 gate_result_t ret = GATE_RESULT_FAILED;
1206 3 gate_socketqueue_impl_t* impl = (gate_socketqueue_impl_t*)obj;
1207
1208 do
1209 {
1210
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (!gate_socketqueue_impl_new_state(impl, GATE_SOCKETQUEUE_STATE_OFFLINE, GATE_SOCKETQUEUE_STATE_STARTING))
1211 {
1212 ret = GATE_RESULT_INVALIDSTATE;
1213 break;
1214 }
1215
1216 3 impl->callback = impl->next_callback;
1217 3 impl->callback_data = impl->next_callback_data;
1218
1219 3 ret = gate_thread_start_code(&gate_socketqueue_impl_worker, obj, &impl->thread, NULL);
1220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(ret))
1221 {
1222 gate_socketqueue_impl_new_state(impl, GATE_SOCKETQUEUE_STATE_STARTING, GATE_SOCKETQUEUE_STATE_OFFLINE);
1223 }
1224 } while (0);
1225
1226 3 return ret;
1227 }
1228 8 static gate_result_t gate_socketqueue_impl_stop(void* obj)
1229 {
1230 8 gate_result_t ret = GATE_RESULT_FAILED;
1231 8 gate_socketqueue_impl_t* impl = (gate_socketqueue_impl_t*)obj;
1232 gate_result_t thread_result;
1233 8 gate_bool_t is_current_thread = false;
1234 8 gate_bool_t join_thread = true;
1235
1236 do
1237 {
1238
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (!gate_socketqueue_impl_new_state(impl, GATE_SOCKETQUEUE_STATE_STARTING, GATE_SOCKETQUEUE_STATE_STOPPING))
1239 {
1240
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 3 times.
8 if (!gate_socketqueue_impl_new_state(impl, GATE_SOCKETQUEUE_STATE_ONLINE, GATE_SOCKETQUEUE_STATE_STOPPING))
1241 {
1242 5 ret = GATE_RESULT_INVALIDSTATE;
1243 5 break;
1244 }
1245 }
1246
1247 3 ret = gate_socketgroup_quit(&impl->sockets);
1248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_DEBUG_ASSERT(GATE_SUCCEEDED(ret));
1249
1250 3 ret = gate_thread_is_current(&impl->thread, &is_current_thread);
1251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_DEBUG_ASSERT(GATE_SUCCEEDED(ret));
1252
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (GATE_SUCCEEDED(ret))
1253 {
1254 3 join_thread = !is_current_thread;
1255 }
1256
1257
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (join_thread)
1258 {
1259 3 ret = gate_thread_join(&impl->thread, &thread_result);
1260
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_DEBUG_ASSERT(GATE_SUCCEEDED(ret));
1261 }
1262 else
1263 {
1264 ret = gate_thread_detach(&impl->thread);
1265 GATE_DEBUG_ASSERT(GATE_SUCCEEDED(ret));
1266 }
1267
1268 3 gate_socketqueue_impl_set_state(impl, GATE_SOCKETQUEUE_STATE_OFFLINE);
1269 } while (0);
1270
1271 8 return ret;
1272 }
1273
1274
1275 static gate_enumint_t gate_socketqueue_impl_get_status(void* obj)
1276 {
1277 gate_socketqueue_impl_t* impl = (gate_socketqueue_impl_t*)obj;
1278 return (gate_enumint_t)gate_atomic_int_get(&impl->state);
1279 }
1280
1281 3 gate_result_t gate_socketqueue_impl_set_callback(void* obj, gate_dataqueue_status_t callback_func, void* callback_data)
1282 {
1283 3 gate_socketqueue_impl_t* impl = (gate_socketqueue_impl_t*)obj;
1284 3 impl->next_callback = callback_func;
1285 3 impl->next_callback_data = callback_data;
1286 3 return GATE_RESULT_OK;
1287 }
1288
1289
1290 6 static gate_result_t gate_socketqueue_impl_open(void* obj, gate_string_t const* address, gate_enumint_t flags, void* user_param, gate_channel_id_t* channel_id)
1291 {
1292 6 gate_socketqueue_impl_t* impl = (gate_socketqueue_impl_t*)obj;
1293 6 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1294 gate_socket_endpoint_t endpoint;
1295 6 gate_socket_t new_sock = GATE_SOCKET_INVALID;
1296 6 gate_channel_id_t new_channel = 0;
1297 6 gate_bool_t server_socket = GATE_FLAG_ENABLED(flags, GATE_SOCKETQUEUE_OPEN_SERVER);
1298
1299 do
1300 {
1301 6 ret = gate_socket_parse_endpoint(address, &endpoint);
1302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 GATE_BREAK_IF_FAILED(ret);
1303
1304
1/3
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
6 switch (endpoint.family)
1305 {
1306 6 case GATE_SOCKET_FAMILY_INET4:
1307 {
1308 6 ret = gate_socket_create_ex(endpoint.family, GATE_SOCKET_MSGTYPE_STREAM, GATE_SOCKET_PROTOCOL_IP, &new_sock);
1309 6 break;
1310 }
1311 case GATE_SOCKET_FAMILY_INET6:
1312 {
1313 ret = gate_socket_create_ex(endpoint.family, GATE_SOCKET_MSGTYPE_STREAM, GATE_SOCKET_PROTOCOL_IP6, &new_sock);
1314 break;
1315 }
1316 default:
1317 {
1318 ret = GATE_RESULT_NOTSUPPORTED;
1319 break;
1320 }
1321 }
1322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 GATE_BREAK_IF_FAILED(ret);
1323
1324
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (server_socket)
1325 {
1326 3 ret = gate_socket_bind(new_sock, &endpoint);
1327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED_TRACE(ret, "gate_socket_bind() failed");
1328 3 ret = gate_socket_listen(new_sock, 0);
1329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED_TRACE(ret, "gate_socket_listen() failed");
1330 3 ret = gate_socketgroup_accept(&impl->sockets, new_sock, user_param);
1331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED_TRACE(ret, "gate_socketgroup_accept() failed");
1332 }
1333 else
1334 {
1335 3 ret = gate_socket_set(new_sock, GATE_SOCKET_OPTION_BLOCKING, 0);
1336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED_TRACE(ret, "gate_socket_set() failed");
1337
1338 3 ret = gate_socketgroup_connect(&impl->sockets, new_sock, &endpoint, user_param);
1339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED_TRACE(ret, "gate_socketgroup_connect() failed");
1340
1341 3 ret = gate_socket_set(new_sock, GATE_SOCKET_OPTION_BLOCKING, 1);
1342
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED_TRACE(ret, "gate_socket_set() failed");
1343 }
1344
1345
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (GATE_SUCCEEDED(ret = gate_mutex_acquire(&impl->lock)))
1346 {
1347 6 new_channel = gate_atomic_int_inc(&impl->max_channel_id);
1348 6 ret = gate_socketqueue_impl_register(impl, new_sock, new_channel);
1349 6 gate_mutex_release(&impl->lock);
1350 6 *channel_id = new_channel;
1351 }
1352
1353 } while (0);
1354
1355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (GATE_FAILED(ret))
1356 {
1357 gate_socket_close(new_sock);
1358 }
1359
1360 6 return ret;
1361 }
1362 20 static gate_result_t gate_socketqueue_impl_close(void* obj, gate_channel_id_t channel_id)
1363 {
1364 20 gate_socketqueue_impl_t* impl = (gate_socketqueue_impl_t*)obj;
1365 20 gate_result_t ret = GATE_RESULT_FAILED;
1366 gate_map_iterator_t iter;
1367 20 gate_socket_t sock = GATE_SOCKET_INVALID;
1368
1369
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 if (GATE_SUCCEEDED(ret = gate_mutex_acquire(&impl->lock)))
1370 {
1371 do
1372 {
1373
2/2
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 6 times.
20 if (!gate_map_iterator_valid(iter = gate_map_get(&impl->channel_2_sock, &channel_id)))
1374 {
1375 14 ret = GATE_RESULT_NOMATCH;
1376 14 break;
1377 }
1378 6 sock = GATE_MAP_ITER_VALUE(gate_socket_t, iter);
1379 6 gate_map_remove(&impl->sock_2_channel, &sock);
1380 6 gate_map_remove(&impl->channel_2_sock, &channel_id);
1381
1382 6 gate_socketgroup_remove(&impl->sockets, sock);
1383 6 gate_socket_close(sock);
1384
1385 6 ret = GATE_RESULT_OK;
1386 } while (0);
1387 20 gate_mutex_release(&impl->lock);
1388 }
1389 20 return ret;
1390 }
1391 8 static gate_result_t gate_socketqueue_impl_begin_read(void* obj, gate_channel_id_t channel_id, gate_size_t size, void* user_param)
1392 {
1393 8 gate_socketqueue_impl_t* impl = (gate_socketqueue_impl_t*)obj;
1394 gate_result_t ret;
1395 8 gate_socket_t sock = GATE_SOCKET_INVALID;
1396
1397
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (GATE_SUCCEEDED(ret = gate_mutex_acquire(&impl->lock)))
1398 {
1399 8 ret = gate_socketqueue_impl_resolve_socket(impl, channel_id, &sock);
1400 8 gate_mutex_release(&impl->lock);
1401 }
1402
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (GATE_SUCCEEDED(ret))
1403 {
1404 8 ret = gate_socketgroup_read(&impl->sockets, sock, size, user_param);
1405 }
1406
1407 8 return ret;
1408 }
1409 9 static gate_result_t gate_socketqueue_impl_begin_write(void* obj, gate_channel_id_t channel_id, char const* buffer, gate_size_t buffer_size, void* user_param)
1410 {
1411 9 gate_socketqueue_impl_t* impl = (gate_socketqueue_impl_t*)obj;
1412 gate_result_t ret;
1413 9 gate_socket_t sock = GATE_SOCKET_INVALID;
1414
1415
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 if (GATE_SUCCEEDED(ret = gate_mutex_acquire(&impl->lock)))
1416 {
1417 9 ret = gate_socketqueue_impl_resolve_socket(impl, channel_id, &sock);
1418 9 gate_mutex_release(&impl->lock);
1419 }
1420
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (GATE_SUCCEEDED(ret))
1421 {
1422
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
9 if ((buffer_size == 0) || (buffer == NULL))
1423 {
1424 /* sending empty buffers is interpreted as socket shutdown */
1425 2 ret = gate_socketgroup_shutdown_write(&impl->sockets, sock, user_param);
1426 }
1427 else
1428 {
1429 7 ret = gate_socketgroup_write(&impl->sockets, sock, buffer, buffer_size, user_param);
1430 }
1431 }
1432 9 return ret;
1433 }
1434
1435 3 static gate_result_t gate_socketqueue_impl_close_all(void* obj)
1436 {
1437 gate_result_t ret;
1438 3 gate_socketqueue_impl_t* impl = (gate_socketqueue_impl_t*)obj;
1439
1440
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if (GATE_SUCCEEDED(ret = gate_mutex_acquire(&impl->lock)))
1441 {
1442 3 ret = gate_socketgroup_clear(&impl->sockets);
1443 3 gate_map_clear(&impl->channel_2_sock);
1444 3 gate_map_clear(&impl->sock_2_channel);
1445 3 gate_mutex_release(&impl->lock);
1446 }
1447 3 return ret;
1448 }
1449
1450 8 static void gate_socketqueue_impl_release(void* obj)
1451 {
1452 8 gate_socketqueue_impl_t* impl = (gate_socketqueue_impl_t*)obj;
1453
1454
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
8 if (gate_atomic_int_dec(&impl->ref_counter) == 0)
1455 {
1456 4 gate_socketqueue_impl_stop(impl);
1457
1458 4 gate_socketgroup_destroy(&impl->sockets);
1459 4 gate_map_destroy(&impl->sock_2_channel);
1460 4 gate_map_destroy(&impl->channel_2_sock);
1461 4 gate_mutex_destroy(&impl->lock);
1462 4 gate_mem_dealloc(impl);
1463 }
1464 8 }
1465
1466 static GATE_INTERFACE_VTBL(gate_socketqueue) gate_socketqueue_vtbl;
1467 4 static void gate_init_socketqueue_vtbl()
1468 {
1469
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (!gate_socketqueue_vtbl.get_interface_name)
1470 {
1471 GATE_INTERFACE_VTBL(gate_socketqueue) const local_vtbl =
1472 {
1473 &gate_socketqueue_impl_get_interface_name,
1474 &gate_socketqueue_impl_release,
1475 &gate_socketqueue_impl_retain,
1476
1477 &gate_socketqueue_impl_start,
1478 &gate_socketqueue_impl_stop,
1479 &gate_socketqueue_impl_get_status,
1480
1481 &gate_socketqueue_impl_set_callback,
1482 &gate_socketqueue_impl_open,
1483 &gate_socketqueue_impl_close,
1484 &gate_socketqueue_impl_begin_read,
1485 &gate_socketqueue_impl_begin_write,
1486
1487 &gate_socketqueue_impl_close_all
1488 };
1489 2 gate_socketqueue_vtbl = local_vtbl;
1490 }
1491 4 }
1492
1493 4 gate_result_t gate_socketqueue_create(gate_socketqueue_t** ptr_queue, gate_uint32_t idle_interval_ms)
1494 {
1495 4 gate_result_t ret = GATE_RESULT_FAILED;
1496 gate_socketqueue_impl_t* impl;
1497
1498 do
1499 {
1500
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (idle_interval_ms < 1)
1501 {
1502 idle_interval_ms = 1;
1503 }
1504
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 else if (idle_interval_ms > 60000)
1505 {
1506 idle_interval_ms = 60000;
1507 }
1508
1509 4 impl = gate_mem_alloc(sizeof(gate_socketqueue_impl_t));
1510
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (impl == NULL)
1511 {
1512 ret = GATE_RESULT_OUTOFMEMORY;
1513 break;
1514 }
1515 4 gate_mem_clear(impl, sizeof(gate_socketqueue_impl_t));
1516 4 gate_init_socketqueue_vtbl();
1517 4 impl->vtbl = &gate_socketqueue_vtbl;
1518 4 gate_atomic_int_init(&impl->ref_counter, 1);
1519 4 gate_atomic_int_init(&impl->state, GATE_SOCKETQUEUE_STATE_OFFLINE);
1520 4 gate_atomic_int_init(&impl->max_channel_id, 0);
1521
1522 4 ret = gate_mutex_create(&impl->lock);
1523
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATE_BREAK_IF_FAILED(ret);
1524
1525
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (NULL == gate_map_create(&impl->sock_2_channel, &gate_compare_socket, sizeof(gate_socket_t), NULL, NULL, sizeof(gate_channel_id_t), NULL, NULL))
1526 {
1527 ret = GATE_RESULT_OUTOFMEMORY;
1528 break;
1529 }
1530
1531
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (NULL == gate_map_create(&impl->channel_2_sock, &gate_compare_channel_id, sizeof(gate_channel_id_t), NULL, NULL, sizeof(gate_socket_t), NULL, NULL))
1532 {
1533 ret = GATE_RESULT_OUTOFMEMORY;
1534 break;
1535 }
1536
1537 4 ret = gate_socketgroup_create(&impl->sockets, impl);
1538
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATE_BREAK_IF_FAILED(ret);
1539 4 impl->sockets.interval_ms = idle_interval_ms;
1540
1541 4 ret = GATE_RESULT_OK;
1542 4 *ptr_queue = (gate_socketqueue_t*)impl;
1543 4 impl = NULL;
1544 } while (0);
1545
1546
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (GATE_FAILED(ret))
1547 {
1548 if (impl)
1549 {
1550 gate_map_destroy(&impl->sock_2_channel);
1551 gate_map_destroy(&impl->channel_2_sock);
1552 gate_mutex_destroy(&impl->lock);
1553 gate_mem_dealloc(impl);
1554 }
1555 }
1556
1557 4 return ret;
1558 }
1559
1560
1561
1562 /**********************************
1563 * SOCKET STREAM implementation *
1564 **********************************/
1565
1566 typedef struct gate_socketstream_class
1567 {
1568 GATE_INTERFACE_VTBL(gate_controlstream) const* vtbl;
1569
1570 gate_atomic_int_t ref_counter;
1571 gate_socket_t sock;
1572 gate_bool_t connected;
1573 gate_socket_endpoint_t ep;
1574 gate_uint64_t bytes_received;
1575 gate_uint64_t bytes_sent;
1576 } gate_socketstream_t;
1577
1578 4 static gate_result_t socketstream_create_socket(gate_socket_endpoint_t const* ptr_ep, gate_socket_t* ptr_sock)
1579 {
1580 gate_int16_t socktype;
1581
1/3
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
4 switch (ptr_ep->family)
1582 {
1583 4 case GATE_SOCKET_FAMILY_INET4: socktype = GATE_SOCKET_TYPE_TCP4; break;
1584 case GATE_SOCKET_FAMILY_INET6: socktype = GATE_SOCKET_TYPE_TCP6; break;
1585 default: socktype = 0;
1586 }
1587
1588
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (socktype == 0)
1589 {
1590 return GATE_RESULT_INVALIDARG;
1591 }
1592
1593 4 return gate_socket_create(socktype, ptr_sock);
1594 }
1595
1596 3 static gate_result_t socketstream_connect_socket(gate_socketstream_t* ptr_sockstream)
1597 {
1598 3 gate_result_t ret = gate_socket_connect(ptr_sockstream->sock, &ptr_sockstream->ep);
1599
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (GATE_SUCCEEDED(ret))
1600 {
1601 3 ptr_sockstream->connected = true;
1602 }
1603 3 return ret;
1604 }
1605
1606
1607 static char const* socketstream_get_interface_name(void* obj)
1608 {
1609 GATE_UNUSED_ARG(obj);
1610 return GATE_INTERFACE_NAME_CONTROLSTREAM;
1611 }
1612 7 static void socketstream_release(void* obj)
1613 {
1614 7 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1615
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 4 times.
7 if (0 == gate_atomic_int_dec(&self->ref_counter))
1616 {
1617 3 gate_socket_close(self->sock);
1618 3 gate_mem_dealloc(self);
1619 }
1620 7 }
1621 4 static int socketstream_retain(void* obj)
1622 {
1623 4 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1624 4 return gate_atomic_int_inc(&self->ref_counter);
1625 }
1626
1627 140 static gate_result_t socketstream_read(void* obj, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1628 {
1629 gate_result_t ret;
1630 140 gate_size_t received = 0;
1631 140 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1632
1633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
140 if (!self->connected)
1634 {
1635 ret = socketstream_connect_socket(self);
1636 GATE_RETURN_IF_FAILED(ret);
1637 }
1638
1639 140 ret = gate_socket_receive(self->sock, buffer, bufferlength, &received);
1640
1/2
✓ Branch 0 taken 140 times.
✗ Branch 1 not taken.
140 if (GATE_SUCCEEDED(ret))
1641 {
1642
1/2
✓ Branch 0 taken 140 times.
✗ Branch 1 not taken.
140 if (returned)
1643 {
1644 140 *returned = received;
1645 }
1646 140 self->bytes_received += received;
1647 }
1648 140 return ret;
1649 }
1650 static gate_result_t socketstream_peek(void* obj, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
1651 {
1652 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1653 gate_result_t ret;
1654 gate_uint8_t sel_states = GATE_SOCKET_SELECT_FLAG_RECEIVE;
1655
1656 do
1657 {
1658 if (!self->connected)
1659 {
1660 ret = socketstream_connect_socket(self);
1661 GATE_BREAK_IF_FAILED(ret);
1662 }
1663
1664 ret = gate_socket_select(&self->sock, 1, &sel_states, 0);
1665 GATE_BREAK_IF_FAILED(ret);
1666
1667 if (GATE_FLAG_ENABLED(sel_states, GATE_SOCKET_SELECT_FLAG_RECEIVE))
1668 {
1669 /* there are bytes in receive buffer: */
1670 ret = gate_socket_receive_from(self->sock, NULL, buffer, bufferlength, returned, GATE_SOCKET_FLAG_PEEK);
1671 }
1672 else
1673 {
1674 /* no bytes in receive buffer */
1675 if (returned)
1676 {
1677 *returned = 0;
1678 }
1679 ret = GATE_RESULT_OK;
1680 }
1681 } while (0);
1682
1683 return ret;
1684 }
1685 4 static gate_result_t socketstream_write(void* obj, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1686 {
1687 gate_result_t ret;
1688 4 gate_size_t sent = 0;
1689 4 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1690
1691
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!self->connected)
1692 {
1693 ret = socketstream_connect_socket(self);
1694 GATE_RETURN_IF_FAILED(ret);
1695 }
1696
1697 4 ret = gate_socket_send(self->sock, buffer, bufferlength, &sent);
1698
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (GATE_SUCCEEDED(ret))
1699 {
1700
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (written)
1701 {
1702 4 *written = sent;
1703 }
1704 4 self->bytes_sent += sent;
1705 }
1706 4 return ret;
1707 }
1708 1 static gate_result_t socketstream_flush(void* obj)
1709 {
1710 1 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1711
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!self->connected)
1712 {
1713 return socketstream_connect_socket(self);
1714 }
1715 1 return GATE_RESULT_OK;
1716 }
1717
1718 static gate_result_t socketstream_get_resource(void* obj, gate_enumint_t resource_type, gate_uintptr_t* resource)
1719 {
1720 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1721 switch (resource_type)
1722 {
1723 case GATE_STREAM_RESOURCE_INPUT:
1724 case GATE_STREAM_RESOURCE_OUTPUT:
1725 if (resource)
1726 {
1727 *resource = (gate_uintptr_t)self->sock;
1728 }
1729 return GATE_RESULT_OK;
1730 default:
1731 return GATE_RESULT_NOTSUPPORTED;
1732 }
1733 }
1734
1735 static gate_result_t socketstream_can_read(void* obj, gate_bool_t* return_value)
1736 {
1737 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1738 gate_uint8_t status = GATE_SOCKET_SELECT_FLAG_RECEIVE;
1739 gate_result_t ret;
1740
1741 if (!self->connected)
1742 {
1743 ret = socketstream_connect_socket(self);
1744 GATE_RETURN_IF_FAILED(ret);
1745 }
1746
1747 ret = gate_socket_select(&self->sock, 1, &status, 10);
1748 if (return_value)
1749 {
1750 *return_value = GATE_FLAG_ENABLED(status, GATE_SOCKET_SELECT_FLAG_RECEIVE);
1751 }
1752 return ret;
1753 }
1754
1755 static gate_result_t socketstream_can_write(void* obj, gate_bool_t* return_value)
1756 {
1757 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1758 gate_uint8_t status = GATE_SOCKET_SELECT_FLAG_SEND;
1759 gate_result_t ret;
1760
1761 if (!self->connected)
1762 {
1763 ret = socketstream_connect_socket(self);
1764 GATE_RETURN_IF_FAILED(ret);
1765 }
1766
1767 ret = gate_socket_select(&self->sock, 1, &status, 10);
1768 if (return_value)
1769 {
1770 *return_value = GATE_FLAG_ENABLED(status, GATE_SOCKET_SELECT_FLAG_SEND);
1771 }
1772 return ret;
1773 }
1774
1775 static gate_result_t socketstream_get_size(void* obj, gate_int64_t* return_value)
1776 {
1777 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1778 if (return_value)
1779 {
1780 *return_value = (gate_int64_t)self->bytes_received;
1781 }
1782 return GATE_RESULT_NOTAVAILABLE;
1783 }
1784
1785 static gate_result_t socketstream_get_available(void* obj, gate_int64_t* return_value)
1786 {
1787 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1788 gate_uint8_t status = GATE_SOCKET_SELECT_FLAG_RECEIVE;
1789 gate_result_t ret = gate_socket_select(&self->sock, 1, &status, 0);
1790 if (return_value)
1791 {
1792 *return_value = GATE_FLAG_ENABLED(status, GATE_SOCKET_SELECT_FLAG_RECEIVE) ? 1 : 0;
1793 }
1794 return ret;
1795 }
1796
1797 static gate_result_t socketstream_seek(void* obj, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position)
1798 {
1799 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1800 if (((origin == GATE_STREAM_SEEK_CURRENT) || (origin == GATE_STREAM_SEEK_END)) && (position == 0))
1801 {
1802 /* just return current 'write' position */
1803 if (final_position)
1804 {
1805 *final_position = (gate_int64_t)self->bytes_sent;
1806 }
1807 return GATE_RESULT_OK;
1808 }
1809 return GATE_RESULT_NOTSUPPORTED;
1810 }
1811 static gate_result_t socketstream_reset(void* obj)
1812 {
1813 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1814
1815 if (self->connected)
1816 {
1817 gate_socket_close(self->sock);
1818 self->connected = false;
1819 }
1820
1821 return socketstream_connect_socket(self);
1822 }
1823 3 static gate_result_t socketstream_close(void* obj, gate_enumint_t close_type)
1824 {
1825 3 gate_socketstream_t* self = (gate_socketstream_t*)obj;
1826
1827
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!self->connected)
1828 {
1829 return GATE_RESULT_OK;
1830 }
1831
1832
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 switch (close_type)
1833 {
1834 case GATE_STREAM_CLOSE_INPUT:
1835 return gate_socket_shutdown(self->sock, true, false);
1836 3 case GATE_STREAM_CLOSE_OUTPUT:
1837 3 return gate_socket_shutdown(self->sock, false, true);
1838 }
1839 return GATE_RESULT_NOTSUPPORTED;
1840 }
1841
1842 static GATE_INTERFACE_VTBL(gate_controlstream) sockstream_vtbl;
1843
1844 3 static void gate_init_socketstream_vtbl()
1845 {
1846
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (!sockstream_vtbl.get_interface_name)
1847 {
1848 2 GATE_INTERFACE_VTBL(gate_controlstream) local_vtbl =
1849 {
1850 &socketstream_get_interface_name,
1851 &socketstream_release,
1852 &socketstream_retain,
1853
1854 &socketstream_read,
1855 &socketstream_peek,
1856 &socketstream_write,
1857 &socketstream_flush,
1858
1859 &socketstream_get_resource,
1860
1861 &socketstream_can_read,
1862 &socketstream_can_write,
1863 &socketstream_get_size,
1864 &socketstream_get_available,
1865 &socketstream_seek,
1866 &socketstream_reset,
1867 &socketstream_close
1868 };
1869 2 sockstream_vtbl = local_vtbl;
1870 }
1871 3 }
1872
1873
1874 3 static gate_result_t gate_socketstream_create_internal(
1875 gate_socket_t sock, gate_socket_endpoint_t const* ep, gate_bool_t delay_connect, gate_controlstream_t** ptr_stream)
1876 {
1877 3 gate_result_t ret = GATE_RESULT_FAILED;
1878 3 gate_socketstream_t* ptr_sockstream = NULL;
1879 do
1880 {
1881 3 ptr_sockstream = (gate_socketstream_t*)gate_mem_alloc(sizeof(gate_socketstream_t));
1882
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (NULL == ptr_sockstream)
1883 {
1884 ret = GATE_RESULT_OUTOFMEMORY;
1885 break;
1886 }
1887 3 gate_atomic_int_init(&ptr_sockstream->ref_counter, 1);
1888 3 gate_init_socketstream_vtbl();
1889 3 ptr_sockstream->vtbl = &sockstream_vtbl;
1890 3 ptr_sockstream->bytes_sent = 0;
1891 3 ptr_sockstream->bytes_received = 0;
1892 3 ptr_sockstream->sock = sock;
1893
1894
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (sock == GATE_SOCKET_INVALID)
1895 {
1896 3 ptr_sockstream->sock = GATE_SOCKET_INVALID;
1897 3 ptr_sockstream->connected = false;
1898 3 gate_mem_copy(&ptr_sockstream->ep, ep, sizeof(ptr_sockstream->ep));
1899
1900 3 ret = socketstream_create_socket(&ptr_sockstream->ep, &ptr_sockstream->sock);
1901
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED(ret);
1902
1903
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (!delay_connect)
1904 {
1905 3 ret = socketstream_connect_socket(ptr_sockstream);
1906
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED(ret);
1907 }
1908 }
1909 else
1910 {
1911 ptr_sockstream->connected = true;
1912 gate_mem_clear(&ptr_sockstream->ep, sizeof(ptr_sockstream->ep));
1913 }
1914
1915
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (ptr_stream)
1916 {
1917 3 *ptr_stream = (gate_controlstream_t*)ptr_sockstream;
1918 3 ptr_sockstream = NULL;
1919 }
1920 3 ret = GATE_RESULT_OK;
1921 } while (0);
1922
1923
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (ptr_sockstream)
1924 {
1925 gate_object_release(ptr_sockstream);
1926 }
1927
1928 3 return ret;
1929 }
1930
1931 gate_result_t gate_socketstream_create(gate_socket_t sock, gate_controlstream_t** ptr_stream)
1932 {
1933 return gate_socketstream_create_internal(sock, NULL, false, ptr_stream);
1934 }
1935
1936 2 gate_result_t gate_socketstream_create_endpoint(gate_socket_endpoint_t const* ep, gate_controlstream_t** ptr_stream, gate_bool_t delay_connect)
1937 {
1938 2 return gate_socketstream_create_internal(GATE_SOCKET_INVALID, ep, delay_connect, ptr_stream);
1939 }
1940
1941 1 gate_result_t gate_socketstream_create_address(gate_string_t const* addr, gate_controlstream_t** ptr_stream, gate_bool_t delay_connect)
1942 {
1943 gate_result_t ret;
1944 gate_socket_endpoint_t ep;
1945 do
1946 {
1947 1 ret = gate_socket_parse_endpoint(addr, &ep);
1948
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(ret))
1949 {
1950 gate_string_t host = GATE_STRING_INIT_EMPTY;
1951 gate_uint16_t port = 0;
1952 gate_int16_t family = 0;
1953 gate_size_t ep_count = 1;
1954 do
1955 {
1956 ret = gate_socket_parse_address(addr, &host, &port, &family);
1957 GATE_BREAK_IF_FAILED(ret);
1958
1959 ret = gate_net_resolve_host(&host, family, &ep, &ep_count);
1960 switch (ep.family)
1961 {
1962 case GATE_SOCKET_FAMILY_INET4: ep.ip4.port = port; break;
1963 case GATE_SOCKET_FAMILY_INET6: ep.ip6.port = port; break;
1964 }
1965 } while (0);
1966 gate_string_release(&host);
1967 }
1968
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1969
1970 1 ret = gate_socketstream_create_internal(GATE_SOCKET_INVALID, &ep, delay_connect, ptr_stream);
1971 } while (0);
1972 1 return ret;
1973 }
1974
1975
1976
1977 typedef struct gate_socketserverstream_class
1978 {
1979 GATE_INTERFACE_VTBL(gate_controlstream) const* vtbl;
1980
1981 gate_atomic_int_t ref_counter;
1982 gate_socket_t server_sock;
1983 gate_socket_endpoint_t ep;
1984 gate_socket_t connection_sock;
1985 gate_bool_t connected;
1986 gate_uint64_t bytes_received;
1987 gate_uint64_t bytes_sent;
1988 } gate_socketserverstream_t;
1989
1990
1991 static char const* socketserverstream_get_interface_name(void* obj)
1992 {
1993 GATE_UNUSED_ARG(obj);
1994 return GATE_INTERFACE_NAME_CONTROLSTREAM;
1995 }
1996 1 static void socketserverstream_release(void* obj)
1997 {
1998 1 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
1999
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (0 == gate_atomic_int_dec(&self->ref_counter))
2000 {
2001
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (self->connection_sock != GATE_SOCKET_INVALID)
2002 {
2003 1 gate_socket_close(self->connection_sock);
2004 }
2005
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (self->server_sock != GATE_SOCKET_INVALID)
2006 {
2007 1 gate_socket_close(self->server_sock);
2008 }
2009 1 gate_mem_dealloc(self);
2010 }
2011 1 }
2012 static int socketserverstream_retain(void* obj)
2013 {
2014 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
2015 return gate_atomic_int_inc(&self->ref_counter);
2016 }
2017
2018 4 static gate_result_t socketserverstream_accept(gate_socketserverstream_t* self)
2019 {
2020 4 gate_result_t ret = GATE_RESULT_OK;
2021
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (!self->connected)
2022 {
2023 1 ret = gate_socket_accept(self->server_sock, &self->connection_sock);
2024
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_SUCCEEDED(ret))
2025 {
2026 1 self->connected = true;
2027 }
2028 }
2029 4 return ret;
2030 }
2031
2032 2 static gate_result_t socketserverstream_read(void* obj, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
2033 {
2034 gate_result_t ret;
2035 2 gate_size_t received = 0;
2036 2 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
2037
2038 2 ret = socketserverstream_accept(self);
2039
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_RETURN_IF_FAILED(ret);
2040
2041 2 ret = gate_socket_receive(self->connection_sock, buffer, bufferlength, &received);
2042
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (GATE_SUCCEEDED(ret))
2043 {
2044
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (returned)
2045 {
2046 2 *returned = received;
2047 }
2048 2 self->bytes_received += received;
2049 }
2050 2 return ret;
2051 }
2052
2053 static gate_result_t socketserverstream_peek(void* obj, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
2054 {
2055 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
2056 gate_result_t ret;
2057
2058 ret = socketserverstream_accept(self);
2059 GATE_RETURN_IF_FAILED(ret);
2060
2061 return gate_socket_receive_from(self->connection_sock, NULL, buffer, bufferlength, returned, GATE_SOCKET_FLAG_PEEK);
2062 }
2063
2064 1 static gate_result_t socketserverstream_write(void* obj, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
2065 {
2066 gate_result_t ret;
2067 1 gate_size_t sent = 0;
2068 1 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
2069
2070 1 ret = socketserverstream_accept(self);
2071
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_RETURN_IF_FAILED(ret);
2072
2073 1 ret = gate_socket_send(self->connection_sock, buffer, bufferlength, &sent);
2074
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_SUCCEEDED(ret))
2075 {
2076
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (written)
2077 {
2078 1 *written = sent;
2079 }
2080 1 self->bytes_sent += sent;
2081 }
2082 1 return ret;
2083 }
2084 1 static gate_result_t socketserverstream_flush(void* obj)
2085 {
2086 1 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
2087
2088 1 return socketserverstream_accept(self);
2089 }
2090
2091 static gate_result_t socketserverstream_get_resource(void* obj, gate_enumint_t resource_type, gate_uintptr_t* resource)
2092 {
2093 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
2094 switch (resource_type)
2095 {
2096 case GATE_STREAM_RESOURCE_DEFAULT:
2097 if (resource)
2098 {
2099 *resource = (gate_uintptr_t)self->server_sock;
2100 }
2101 return GATE_RESULT_OK;
2102
2103 case GATE_STREAM_RESOURCE_INPUT:
2104 case GATE_STREAM_RESOURCE_OUTPUT:
2105 if (resource)
2106 {
2107 *resource = (gate_uintptr_t)self->connection_sock;
2108 }
2109 return GATE_RESULT_OK;
2110 default:
2111 return GATE_RESULT_NOTSUPPORTED;
2112 }
2113 }
2114
2115 static gate_result_t socketserverstream_can_read(void* obj, gate_bool_t* return_value)
2116 {
2117 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
2118 gate_uint8_t status = GATE_SOCKET_SELECT_FLAG_RECEIVE;
2119 gate_result_t ret;
2120 gate_bool_t can_read = false;
2121
2122 if (self->connected)
2123 {
2124 ret = gate_socket_select(&self->connection_sock, 1, &status, 10);
2125 can_read = GATE_FLAG_ENABLED(status, GATE_SOCKET_SELECT_FLAG_RECEIVE);
2126 }
2127
2128 if (return_value)
2129 {
2130 *return_value = can_read;
2131 }
2132
2133 return ret;
2134 }
2135
2136 static gate_result_t socketserverstream_can_write(void* obj, gate_bool_t* return_value)
2137 {
2138 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
2139 gate_uint8_t status = GATE_SOCKET_SELECT_FLAG_SEND;
2140 gate_result_t ret;
2141 gate_bool_t can_read = false;
2142
2143 if (self->connected)
2144 {
2145 ret = gate_socket_select(&self->connection_sock, 1, &status, 10);
2146 can_read = GATE_FLAG_ENABLED(status, GATE_SOCKET_SELECT_FLAG_SEND);
2147 }
2148
2149 if (return_value)
2150 {
2151 *return_value = can_read;
2152 }
2153
2154 return ret;
2155 }
2156
2157 static gate_result_t socketserverstream_get_size(void* obj, gate_int64_t* return_value)
2158 {
2159 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
2160 if (return_value)
2161 {
2162 *return_value = (gate_int64_t)self->bytes_received;
2163 }
2164 return GATE_RESULT_NOTAVAILABLE;
2165 }
2166
2167 static gate_result_t socketserverstream_get_available(void* obj, gate_int64_t* return_value)
2168 {
2169 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
2170 gate_uint8_t status = GATE_SOCKET_SELECT_FLAG_RECEIVE;
2171 gate_result_t ret = GATE_RESULT_OK;
2172 unsigned available = 0;
2173
2174 if (self->connected)
2175 {
2176 ret = gate_socket_select(&self->connection_sock, 1, &status, 0);
2177 available = GATE_FLAG_ENABLED(status, GATE_SOCKET_SELECT_FLAG_RECEIVE) ? 1 : 0;
2178 }
2179
2180 if (return_value)
2181 {
2182 *return_value = (gate_int64_t)available;
2183 }
2184 return ret;
2185 }
2186
2187 static gate_result_t socketserverstream_seek(void* obj, gate_int64_t position, gate_enumint_t origin, gate_int64_t* final_position)
2188 {
2189 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
2190 if (((origin == GATE_STREAM_SEEK_CURRENT) || (origin == GATE_STREAM_SEEK_END)) && (position == 0))
2191 {
2192 /* just return current 'write' position */
2193 if (final_position)
2194 {
2195 *final_position = (gate_int64_t)self->bytes_sent;
2196 }
2197 return GATE_RESULT_OK;
2198 }
2199 return GATE_RESULT_NOTSUPPORTED;
2200 }
2201 static gate_result_t socketserverstream_reset(void* obj)
2202 {
2203 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
2204
2205 if (self->connected)
2206 {
2207 gate_socket_close(self->connection_sock);
2208 self->connected = false;
2209 }
2210
2211 return socketserverstream_accept(self);
2212 }
2213
2214 1 static gate_result_t socketserverstream_close(void* obj, gate_enumint_t close_type)
2215 {
2216 1 gate_socketserverstream_t* self = (gate_socketserverstream_t*)obj;
2217
2218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!self->connected)
2219 {
2220 return GATE_RESULT_OK;
2221 }
2222
2223
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 switch (close_type)
2224 {
2225 case GATE_STREAM_CLOSE_INPUT:
2226 return gate_socket_shutdown(self->connected, true, false);
2227 1 case GATE_STREAM_CLOSE_OUTPUT:
2228 1 return gate_socket_shutdown(self->connection_sock, false, true);
2229 }
2230 return GATE_RESULT_NOTSUPPORTED;
2231 }
2232
2233 static GATE_INTERFACE_VTBL(gate_controlstream) socketserverstream_vtbl;
2234
2235 1 static void gate_init_socketserverstream_vtbl()
2236 {
2237
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!sockstream_vtbl.get_interface_name)
2238 {
2239 1 GATE_INTERFACE_VTBL(gate_controlstream) local_vtbl =
2240 {
2241 &socketserverstream_get_interface_name,
2242 &socketserverstream_release,
2243 &socketserverstream_retain,
2244
2245 &socketserverstream_read,
2246 &socketserverstream_peek,
2247 &socketserverstream_write,
2248 &socketserverstream_flush,
2249
2250 &socketserverstream_get_resource,
2251
2252 &socketserverstream_can_read,
2253 &socketserverstream_can_write,
2254 &socketserverstream_get_size,
2255 &socketserverstream_get_available,
2256 &socketserverstream_seek,
2257 &socketserverstream_reset,
2258 &socketserverstream_close
2259 };
2260 1 socketserverstream_vtbl = local_vtbl;
2261 }
2262 1 }
2263
2264
2265 1 gate_result_t gate_socketstream_create_server(gate_socket_endpoint_t const* bind_ep, gate_controlstream_t** ptr_stream)
2266 {
2267 1 gate_result_t ret = GATE_RESULT_FAILED;
2268 1 gate_socketserverstream_t* ptr_sockstream = NULL;
2269
2270 do
2271 {
2272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (bind_ep == NULL)
2273 {
2274 ret = GATE_RESULT_INVALIDARG;
2275 break;
2276 }
2277 1 ptr_sockstream = (gate_socketserverstream_t*)gate_mem_alloc(sizeof(gate_socketserverstream_t));
2278
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == ptr_sockstream)
2279 {
2280 ret = GATE_RESULT_OUTOFMEMORY;
2281 break;
2282 }
2283 1 gate_atomic_int_init(&ptr_sockstream->ref_counter, 1);
2284 1 gate_init_socketserverstream_vtbl();
2285 1 ptr_sockstream->vtbl = &socketserverstream_vtbl;
2286 1 ptr_sockstream->bytes_sent = 0;
2287 1 ptr_sockstream->bytes_received = 0;
2288 1 ptr_sockstream->server_sock = GATE_SOCKET_INVALID;
2289 1 ptr_sockstream->connection_sock = GATE_SOCKET_INVALID;
2290 1 ptr_sockstream->connected = false;
2291
2292 1 gate_mem_copy(&ptr_sockstream->ep, bind_ep, sizeof(ptr_sockstream->ep));
2293
2294 1 ret = socketstream_create_socket(&ptr_sockstream->ep, &ptr_sockstream->server_sock);
2295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
2296
2297 1 ret = gate_socket_bind(ptr_sockstream->server_sock, &ptr_sockstream->ep);
2298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
2299
2300 1 ret = gate_socket_listen(ptr_sockstream->server_sock, 1);
2301
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
2302
2303
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_stream)
2304 {
2305 1 *ptr_stream = (gate_controlstream_t*)ptr_sockstream;
2306 1 ptr_sockstream = NULL;
2307 }
2308 1 ret = GATE_RESULT_OK;
2309 } while (0);
2310
2311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ptr_sockstream)
2312 {
2313 gate_object_release(ptr_sockstream);
2314 }
2315
2316 1 return ret;
2317 }
2318
2319