GCC Code Coverage Report


Directory: src/gate/
File: src/gate/net/sockettools.c
Date: 2026-02-03 22:06:38
Exec Total Coverage
Lines: 705 990 71.2%
Functions: 63 85 74.1%
Branches: 230 477 48.2%

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