GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/pipes.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 78 205 38.0%
Functions: 7 21 33.3%
Branches: 35 98 35.7%

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
29 #include "gate/io/pipes.h"
30 #include "gate/results.h"
31 #include "gate/debugging.h"
32
33 #if defined(GATE_SYS_WIN16)
34 # define GATE_IO_PIPES_NO_IMPL 1
35 #elif defined(GATE_SYS_WIN)
36 # define GATE_IO_PIPES_WINAPI_IMPL 1
37 #elif defined(GATE_SYS_POSIX)
38 # define GATE_IO_PIPES_POSIX_IMPL 1
39 #else
40 # define GATE_IO_PIPES_NO_IMPL 1
41 #endif
42
43
44 typedef struct
45 {
46 GATE_INTERFACE_VTBL(gate_stream)* vtbl;
47 gate_atomic_int_t ref_counter;
48 gate_pipe_t reader;
49 gate_pipe_t writer;
50
51 } pipestream_impl_t;
52
53 static char const* pipestream_get_interface_name(void* ptr)
54 {
55 GATE_UNUSED_ARG(ptr);
56 return GATE_INTERFACE_NAME_STREAM;
57 }
58
59 static void pipestream_destroy(pipestream_impl_t* self)
60 {
61 if (self->reader != gate_pipe_invalid)
62 {
63 gate_pipe_close(self->reader);
64 }
65 if (self->writer != gate_pipe_invalid)
66 {
67 gate_pipe_close(self->writer);
68 }
69 gate_mem_dealloc(self);
70 }
71
72 static void pipestream_release(void* ptr)
73 {
74 pipestream_impl_t* self = (pipestream_impl_t*)ptr;
75 GATE_DEBUG_ASSERT(self != NULL);
76
77 if (gate_atomic_int_dec(&self->ref_counter) == 0)
78 {
79 pipestream_destroy(self);
80 }
81 }
82 static int pipestream_retain(void* ptr)
83 {
84 pipestream_impl_t* self = (pipestream_impl_t*)ptr;
85 GATE_DEBUG_ASSERT(self != NULL);
86
87 return (int)gate_atomic_int_inc(&self->ref_counter);
88 }
89
90 static gate_result_t pipestream_read(void* ptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
91 {
92 pipestream_impl_t* self = (pipestream_impl_t*)ptr;
93 GATE_DEBUG_ASSERT(self != NULL);
94
95 if (self->reader == gate_pipe_invalid)
96 {
97 return GATE_RESULT_NOTSUPPORTED;
98 }
99 return gate_pipe_read(self->reader, buffer, bufferlength, returned);
100 }
101 static gate_result_t pipestream_peek(void* ptr, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
102 {
103 return GATE_RESULT_NOTSUPPORTED;
104 }
105 static gate_result_t pipestream_write(void* ptr, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
106 {
107 pipestream_impl_t* self = (pipestream_impl_t*)ptr;
108 GATE_DEBUG_ASSERT(self != NULL);
109
110 if (self->writer == gate_pipe_invalid)
111 {
112 return GATE_RESULT_NOTSUPPORTED;
113 }
114 return gate_pipe_write(self->writer, buffer, bufferlength, written);
115
116 }
117 static gate_result_t pipestream_flush(void* ptr)
118 {
119 return GATE_RESULT_OK;
120 }
121
122
123
124 static GATE_INTERFACE_VTBL(gate_stream) pipestream_vtbl;
125
126 static void init_pipestream_vtbl()
127 {
128 if (pipestream_vtbl.get_interface_name == NULL)
129 {
130 pipestream_vtbl.get_interface_name = &pipestream_get_interface_name;
131 pipestream_vtbl.release = &pipestream_release;
132 pipestream_vtbl.retain = &pipestream_retain;
133 pipestream_vtbl.read = &pipestream_read;
134 pipestream_vtbl.peek = &pipestream_peek;
135 pipestream_vtbl.write = &pipestream_write;
136 pipestream_vtbl.flush = &pipestream_flush;
137 }
138 }
139
140 gate_result_t gate_pipe_open_stream(gate_string_t* name, gate_enumint_t flags, gate_stream_t** ptr_stream)
141 {
142 gate_result_t ret;
143 pipestream_impl_t* ptr_impl = NULL;
144
145 do
146 {
147 ptr_impl = (pipestream_impl_t*)gate_mem_alloc(sizeof(pipestream_impl_t));
148 if (NULL == ptr_impl)
149 {
150 ret = GATE_RESULT_OUTOFMEMORY;
151 break;
152 }
153 gate_mem_clear(ptr_impl, sizeof(pipestream_impl_t));
154 init_pipestream_vtbl();
155 ptr_impl->vtbl = &pipestream_vtbl;
156 gate_atomic_int_init(&ptr_impl->ref_counter, 1);
157
158 ptr_impl->reader = gate_pipe_invalid;
159 ptr_impl->writer = gate_pipe_invalid;
160
161 ret = gate_pipe_open(name, flags, &ptr_impl->reader, &ptr_impl->writer);
162 GATE_BREAK_IF_FAILED(ret);
163
164 if (ptr_stream)
165 {
166 *ptr_stream = (gate_stream_t*)ptr_impl;
167 ptr_impl = NULL;
168 }
169 ret = GATE_RESULT_OK;
170 } while (0);
171
172 if (ptr_impl)
173 {
174 pipestream_destroy(ptr_impl);
175 }
176
177 return ret;
178 }
179
180
181
182 #if defined(GATE_IO_PIPES_WINAPI_IMPL)
183
184 #include "gate/platforms.h"
185 #include "gate/atomics.h"
186
187 gate_pipe_t const gate_pipe_invalid = (gate_pipe_t)INVALID_HANDLE_VALUE;
188
189
190 #if defined(GATE_SYS_WINCE)
191
192 gate_result_t gate_pipe_create(gate_pipe_t* readpipe, gate_pipe_t* writepipe)
193 {
194 return GATE_RESULT_NOTSUPPORTED;
195 }
196 gate_result_t gate_pipe_open(gate_string_t* name, gate_enumint_t flags, gate_pipe_t* readpipe, gate_pipe_t* writepipe)
197 {
198 return GATE_RESULT_NOTSUPPORTED;
199 }
200 gate_result_t gate_pipe_close(gate_pipe_t pipe)
201 {
202 return GATE_RESULT_NOTSUPPORTED;
203 }
204 gate_result_t gate_pipe_data_available(gate_pipe_t pipe, gate_bool_t* data_available)
205 {
206 return GATE_RESULT_NOTSUPPORTED;
207 }
208 gate_result_t gate_pipe_read(gate_pipe_t pipe, char* buffer, gate_size_t bufferlen, gate_size_t* returned)
209 {
210 return GATE_RESULT_NOTSUPPORTED;
211 }
212 gate_result_t gate_pipe_write(gate_pipe_t pipe, char const* buffer, gate_size_t bufferlen, gate_size_t* written)
213 {
214 return GATE_RESULT_NOTSUPPORTED;
215 }
216 gate_result_t gate_pipe_duplicate(gate_pipe_t src, gate_pipe_t* dst)
217 {
218 return GATE_RESULT_NOTSUPPORTED;
219 }
220 gate_result_t gate_pipe_export(gate_pipe_t pipe, gate_string_t* pipeid)
221 {
222 return GATE_RESULT_NOTSUPPORTED;
223 }
224 gate_result_t gate_pipe_import(gate_string_t const* pipeid, gate_pipe_t* pipe)
225 {
226 return GATE_RESULT_NOTSUPPORTED;
227 }
228
229 #else /* !GATE_SYS_WINCE*/
230
231 gate_result_t gate_pipe_create(gate_pipe_t* readpipe, gate_pipe_t* writepipe)
232 {
233 gate_result_t ret;
234 HANDLE hread, hwrite;
235 if (CreatePipe(&hread, &hwrite, NULL, 0))
236 {
237 if (readpipe != NULL)
238 {
239 *readpipe = (gate_pipe_t)hread;
240 }
241 else
242 {
243 CloseHandle(hread);
244 }
245 if (writepipe != NULL)
246 {
247 *writepipe = (gate_pipe_t)hwrite;
248 }
249 else
250 {
251 CloseHandle(hwrite);
252 }
253 ret = GATE_RESULT_OK;
254 }
255 else
256 {
257 gate_win32_print_lasterror(&ret, NULL, 0);
258 }
259 return ret;
260 }
261
262 static gate_result_t gate_pipe_generate_name(gate_string_t* pipename)
263 {
264 gate_result_t ret = GATE_RESULT_OK;
265 gate_strbuilder_t builder;
266 static gate_atomic_int_t local_pipe_id = 0;
267
268 if (pipename->length == 0)
269 {
270 do
271 {
272 gate_strbuilder_create(&builder, 64);
273 if (0 == gate_strbuilder_append_text(&builder, "GatePipe-", 9))
274 {
275 ret = GATE_RESULT_FAILED;
276 break;
277 }
278 gate_strbuilder_append_uint64(&builder, (gate_uint64_t)GetCurrentProcessId());
279 gate_strbuilder_append_text(&builder, "-", 1);
280 gate_strbuilder_append_uint64(&builder, (gate_uint64_t)gate_win32_get_thread_id());
281 gate_strbuilder_append_text(&builder, "-", 1);
282 gate_strbuilder_append_uint32(&builder, (gate_uint32_t)gate_atomic_int_inc(&local_pipe_id));
283 if (NULL == gate_strbuilder_to_string(&builder, pipename))
284 {
285 ret = GATE_RESULT_FAILED;
286 }
287 gate_strbuilder_release(&builder);
288 } while (0);
289 }
290
291 return ret;
292 }
293
294 static HANDLE duplicate_pipe(HANDLE hpipe)
295 {
296 HANDLE hProc = GetCurrentProcess();
297 HANDLE hdup = NULL;
298 DuplicateHandle(hProc, hpipe, hProc, &hdup, 0, FALSE, DUPLICATE_SAME_ACCESS);
299 return hdup;
300 }
301
302 gate_result_t gate_pipe_open(gate_string_t* name, gate_enumint_t flags, gate_pipe_t* readpipe, gate_pipe_t* writepipe)
303 {
304 gate_result_t ret = GATE_RESULT_FAILED;
305 HANDLE hpipe = INVALID_HANDLE_VALUE;
306 SECURITY_ATTRIBUTES attribs;
307 TCHAR namebuffer[GATE_MAX_FILENAME_LENGTH] = _T("\\\\.\\Pipe\\");
308 gate_size_t bufferused = 9;
309 DWORD pipesize = 0;
310 DWORD desiredAccess;
311
312 do
313 {
314 if (GATE_FLAG_ENABLED(flags, GATE_PIPE_FLAG_CREATE))
315 {
316 /* create a new named pipe */
317
318 ret = gate_pipe_generate_name(name);
319 if (GATE_FAILED(ret)) break;
320
321 gate_win32_utf8_2_winstr(name->str, name->length, &namebuffer[bufferused], sizeof(namebuffer) / sizeof(namebuffer[0]) - bufferused);
322
323 attribs.nLength = sizeof(attribs);
324 attribs.bInheritHandle = TRUE;
325 attribs.lpSecurityDescriptor = NULL;
326
327 hpipe = CreateNamedPipe(namebuffer, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_WAIT,
328 1, pipesize, pipesize, 0, &attribs);
329 if (INVALID_HANDLE_VALUE == hpipe)
330 {
331 gate_win32_print_lasterror(&ret, NULL, 0);
332 break;
333 }
334
335 if (readpipe != NULL)
336 {
337 *readpipe = (gate_pipe_t)duplicate_pipe(hpipe);
338 }
339
340 if (writepipe != NULL)
341 {
342 *writepipe = (gate_pipe_t)duplicate_pipe(hpipe);
343 }
344 gate_win32_closehandle(hpipe);
345 ret = GATE_RESULT_OK;
346 break;
347 }
348
349 /* open an existing pipe */
350 switch (flags)
351 {
352 case GATE_PIPE_FLAG_READ: desiredAccess = GENERIC_READ; break;
353 case GATE_PIPE_FLAG_WRITE: desiredAccess = GENERIC_WRITE; break;
354 case (GATE_PIPE_FLAG_READ | GATE_PIPE_FLAG_WRITE): desiredAccess = GENERIC_READ | GENERIC_WRITE; break;
355 default: desiredAccess = 0; break;
356 }
357
358 if (desiredAccess == 0)
359 {
360 ret = GATE_RESULT_INVALIDARG;
361 break;
362 }
363
364 if (gate_string_is_empty(name))
365 {
366 ret = GATE_RESULT_INVALIDARG;
367 break;
368 }
369
370 gate_win32_utf8_2_winstr(name->str, name->length, &namebuffer[bufferused], sizeof(namebuffer) / sizeof(namebuffer[0]) - bufferused);
371 hpipe = gate_win32_createfile(namebuffer, desiredAccess, 0, OPEN_EXISTING, 0, FILE_FLAG_OVERLAPPED, NULL);
372 if (INVALID_HANDLE_VALUE == hpipe)
373 {
374 gate_win32_print_lasterror(&ret, NULL, 0);
375 break;
376 }
377
378 if (GATE_FLAG_ENABLED(flags, GATE_PIPE_FLAG_READ) && readpipe)
379 {
380 *readpipe = (gate_pipe_t)duplicate_pipe(hpipe);
381 }
382 if (GATE_FLAG_ENABLED(flags, GATE_PIPE_FLAG_WRITE) && writepipe)
383 {
384 *writepipe = (gate_pipe_t)duplicate_pipe(hpipe);
385 }
386
387 gate_win32_closehandle(hpipe);
388 ret = GATE_RESULT_OK;
389
390 } while (0);
391 return ret;
392 }
393 gate_result_t gate_pipe_close(gate_pipe_t pipe)
394 {
395 gate_result_t ret = GATE_RESULT_INVALIDARG;
396 if (pipe != gate_pipe_invalid)
397 {
398 if (CloseHandle((HANDLE)pipe))
399 {
400 ret = GATE_RESULT_OK;
401 }
402 else
403 {
404 gate_win32_print_lasterror(&ret, NULL, 0);
405 }
406 }
407 return ret;
408 }
409 gate_result_t gate_pipe_export(gate_pipe_t pipe, gate_string_t* pipeid)
410 {
411 gate_result_t ret = GATE_RESULT_OUTOFMEMORY;
412 gate_strbuilder_t builder;
413
414 gate_strbuilder_create(&builder, 32);
415 if (0 != gate_strbuilder_append_uint64(&builder, (gate_uint64_t)(gate_uintptr_t)pipe))
416 {
417 if (NULL != gate_strbuilder_to_string(&builder, pipeid))
418 {
419 ret = GATE_RESULT_OK;
420 }
421 }
422 gate_strbuilder_release(&builder);
423 return ret;
424 }
425 gate_result_t gate_pipe_import(gate_string_t const* pipeid, gate_pipe_t* pipe)
426 {
427 gate_result_t ret;
428 gate_uint64_t id = 0;
429 do
430 {
431 if ((pipeid == NULL) || (pipe == NULL))
432 {
433 ret = GATE_RESULT_NULLPOINTER;
434 break;
435 }
436 if (0 == gate_str_parse_uint64(pipeid->str, pipeid->length, &id))
437 {
438 ret = GATE_RESULT_INVALIDINPUT;
439 break;
440 }
441 *pipe = (gate_pipe_t)(gate_uintptr_t)id;
442 ret = GATE_RESULT_OK;
443 } while (0);
444 return ret;
445 }
446
447 gate_result_t gate_pipe_data_available(gate_pipe_t pipe, gate_bool_t* data_available)
448 {
449 HANDLE hpipe = (HANDLE)pipe;
450 DWORD bytes_avail = 0;
451 BOOL succeeded = PeekNamedPipe(hpipe, NULL, 0, NULL, &bytes_avail, NULL);
452 if (succeeded)
453 {
454 if (data_available)
455 {
456 *data_available = bytes_avail > 0;
457 }
458 return GATE_RESULT_OK;
459 }
460 return gate_platform_print_last_error(NULL, 0);
461 }
462
463 gate_result_t gate_pipe_read(gate_pipe_t pipe, char* buffer, gate_size_t bufferlen, gate_size_t* returned)
464 {
465 gate_result_t ret;
466 HANDLE hpipe = (HANDLE)pipe;
467 DWORD bytesread;
468 DWORD dwerror;
469
470 if (gate_win32_readfile(hpipe, buffer, (DWORD)bufferlen, &bytesread, NULL))
471 {
472 if (returned != NULL)
473 {
474 *returned = (gate_size_t)bytesread;
475 }
476 ret = GATE_RESULT_OK;
477 }
478 else
479 {
480 dwerror = gate_win32_getlasterror();
481 if (ERROR_BROKEN_PIPE == dwerror)
482 {
483 if (returned != NULL)
484 {
485 *returned = 0;
486 }
487 ret = GATE_RESULT_OK;
488 }
489 else
490 {
491 gate_win32_print_lasterror(&ret, NULL, 0);
492 }
493 }
494 return ret;
495
496 }
497 gate_result_t gate_pipe_write(gate_pipe_t pipe, char const* buffer, gate_size_t bufferlen, gate_size_t* written)
498 {
499 gate_result_t ret;
500 HANDLE hpipe = (HANDLE)pipe;
501 DWORD byteswritten;
502 if (gate_win32_writefile(hpipe, buffer, (DWORD)bufferlen, &byteswritten, NULL))
503 {
504 if (written != NULL)
505 {
506 *written = (gate_size_t)byteswritten;
507 }
508 ret = GATE_RESULT_OK;
509 }
510 else
511 {
512 gate_win32_print_lasterror(&ret, NULL, 0);
513 }
514 return ret;
515 }
516 gate_result_t gate_pipe_duplicate(gate_pipe_t src, gate_pipe_t* dst)
517 {
518 gate_result_t ret;
519 HANDLE hproc;
520 HANDLE orighandle = (HANDLE)src;
521 HANDLE newhandle;
522 do
523 {
524 hproc = GetCurrentProcess();
525 if (FALSE == DuplicateHandle(hproc, orighandle, hproc, &newhandle, 0, FALSE, DUPLICATE_SAME_ACCESS))
526 {
527 gate_win32_print_lasterror(&ret, NULL, 0);
528 break;
529 }
530 if (dst == NULL)
531 {
532 CloseHandle(newhandle);
533 }
534 else
535 {
536 *dst = (gate_pipe_t)newhandle;
537 }
538 ret = GATE_RESULT_OK;
539 } while (0);
540
541 return ret;
542 }
543
544 #endif /* !GATE_SYS_WINCE*/
545
546 #endif /* GATE_IO_PIPES_WINAPI_IMPL */
547
548
549
550 #if defined(GATE_IO_PIPES_POSIX_IMPL)
551
552 #include "gate/platforms.h"
553 #include <sys/stat.h>
554 #include <sys/select.h>
555 #include <unistd.h>
556 #include <fcntl.h>
557 #include <pthread.h>
558
559 gate_pipe_t const gate_pipe_invalid = (gate_pipe_t)(gate_intptr_t)-1;
560
561 gate_result_t gate_pipe_create(gate_pipe_t* readpipe, gate_pipe_t* writepipe)
562 {
563 gate_result_t ret;
564 int fds[2];
565 if (-1 == pipe(fds))
566 {
567 gate_posix_errno(&ret);
568 }
569 else
570 {
571 if (readpipe != NULL)
572 {
573 *readpipe = (gate_pipe_t)(gate_intptr_t)fds[0];
574 }
575 else
576 {
577 close(fds[0]);
578 }
579
580 if (writepipe != NULL)
581 {
582 *writepipe = (gate_pipe_t)(gate_intptr_t)fds[1];
583 }
584 else
585 {
586 close(fds[1]);
587 }
588 ret = GATE_RESULT_OK;
589 }
590 return ret;
591 }
592 2 static gate_result_t gate_pipe_generate_name(gate_string_t* pipename)
593 {
594 2 gate_result_t ret = GATE_RESULT_OK;
595 gate_strbuilder_t builder;
596 static gate_atomic_int_t local_pipe_id = 0;
597
598
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (pipename->length == 0)
599 {
600 do
601 {
602 2 gate_strbuilder_create(&builder, 64);
603
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (0 == gate_strbuilder_append_text(&builder, "/tmp/GatePipe-", 14))
604 {
605 ret = GATE_RESULT_FAILED;
606 break;
607 }
608 2 gate_strbuilder_append_uint64(&builder, (gate_uint64_t)getpid());
609 2 gate_strbuilder_append_text(&builder, "-", 1);
610 2 gate_strbuilder_append_uint64(&builder, (gate_uint64_t)pthread_self());
611 2 gate_strbuilder_append_text(&builder, "-", 1);
612 2 gate_strbuilder_append_uint32(&builder, (gate_uint32_t)gate_atomic_int_inc(&local_pipe_id));
613
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (NULL == gate_strbuilder_to_string(&builder, pipename))
614 {
615 ret = GATE_RESULT_FAILED;
616 }
617 2 gate_strbuilder_release(&builder);
618 } while (0);
619 }
620
621 2 return ret;
622 }
623 4 gate_result_t gate_pipe_open(gate_string_t* name, gate_enumint_t flags, gate_pipe_t* readpipe, gate_pipe_t* writepipe)
624 {
625 gate_result_t ret;
626 char namebuffer[GATE_MAX_FILENAME_LENGTH];
627 4 int fd_read = -1;
628 4 int fd_write = -1;
629 4 gate_bool_t unlink_fifo = false;
630
631 do
632 {
633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (name == NULL)
634 {
635 ret = GATE_RESULT_INVALIDARG;
636 break;
637 }
638
639
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (GATE_FLAG_ENABLED(flags, GATE_PIPE_FLAG_CREATE))
640 {
641 /* create a new FIFO object */
642 2 gate_pipe_generate_name(name);
643 2 gate_string_to_buffer(name, namebuffer, sizeof(namebuffer));
644
645
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (-1 == mkfifo(namebuffer, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IWOTH | S_IROTH))
646 {
647 gate_posix_errno(&ret);
648 break;
649 }
650
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (readpipe)
651 {
652 2 flags |= GATE_PIPE_FLAG_READ;
653 }
654
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (writepipe)
655 {
656 2 flags |= GATE_PIPE_FLAG_WRITE;
657 }
658 }
659 else
660 {
661 /* fill namebuffer with fifo-filepath to be used in following open() calls*/
662 2 gate_string_to_buffer(name, namebuffer, sizeof(namebuffer));
663 }
664
665
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 if (GATE_FLAG_ENABLED(flags, GATE_PIPE_FLAG_READ) && (readpipe != NULL))
666 {
667 /* read-access to FIFO, must be non-blocking to succeed without writer */
668 4 fd_read = gate_posix_open(namebuffer, O_RDONLY | O_NONBLOCK, 0);
669
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (fd_read == -1)
670 {
671 /* failed to open read-FIFO */
672 unlink_fifo = true;
673 gate_posix_errno(&ret);
674 break;
675 }
676 4 *readpipe = (gate_pipe_t)(gate_intptr_t)fd_read;
677 }
678
679
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 if (GATE_FLAG_ENABLED(flags, GATE_PIPE_FLAG_WRITE) && (writepipe != NULL))
680 {
681 /* write-access to FIFO (must be first, open-read would fail if no writer is available) */
682 2 fd_write = gate_posix_open(namebuffer, O_WRONLY | O_NONBLOCK, 0);
683
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (fd_write == -1)
684 {
685 /* failed to open write-FIFO */
686 unlink_fifo = true;
687 gate_posix_errno(&ret);
688 break;
689 }
690 2 *writepipe = (gate_pipe_t)(gate_intptr_t)fd_write;
691 }
692
693 /* success case: */
694 4 fd_write = -1;
695 4 fd_read = -1;
696 4 ret = GATE_RESULT_OK;
697 } while (0);
698
699
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (fd_read != -1)
700 {
701 gate_posix_close(fd_read);
702 }
703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (fd_write != -1)
704 {
705 gate_posix_close(fd_write);
706 }
707
708
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (unlink_fifo)
709 {
710 unlink(namebuffer);
711 }
712
713 4 return ret;
714 }
715 6 gate_result_t gate_pipe_close(gate_pipe_t pipe)
716 {
717 gate_result_t ret;
718
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (-1 == gate_posix_close((int)(gate_intptr_t)pipe))
719 {
720 gate_posix_errno(&ret);
721 }
722 else
723 {
724 6 ret = GATE_RESULT_OK;
725 }
726 6 return ret;
727 }
728
729 3 static gate_result_t check_pipe_activity(int fd, gate_bool_t check_write, gate_bool_t block, gate_bool_t* has_activity)
730 {
731 3 struct timeval timeout = { 0 };
732 int status;
733
734 fd_set fds;
735 3 FD_ZERO(&fds);
736 3 FD_SET(fd, &fds);
737
738
6/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 2 times.
3 status = select(fd + 1, check_write ? NULL : &fds, check_write ? &fds : NULL, NULL, block ? NULL : &timeout);
739
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (status == -1)
740 {
741 return GATE_RESULT_FAILED;
742 }
743 else
744 {
745
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (has_activity)
746 {
747 1 *has_activity = FD_ISSET(fd, &fds);
748 }
749 3 return GATE_RESULT_OK;
750 }
751 }
752
753 1 gate_result_t gate_pipe_data_available(gate_pipe_t pipe, gate_bool_t* data_available)
754 {
755 1 const int fd = (int)(gate_intptr_t)pipe;
756 1 return check_pipe_activity(fd, false, false, data_available);
757 }
758 1 gate_result_t gate_pipe_read(gate_pipe_t pipe, char* buffer, gate_size_t bufferlen, gate_size_t* returned)
759 {
760 1 const int fd = (int)(gate_intptr_t)pipe;
761 gate_result_t ret;
762 ssize_t bytes;
763 do
764 {
765 1 ret = check_pipe_activity(fd, false, true, NULL);
766
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
767
768 1 bytes = gate_posix_read(fd, buffer, bufferlen);
769
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (bytes < 0)
770 {
771 /* read failed */
772 gate_posix_errno(&ret);
773 break;
774 }
775
776 /* success case: */
777
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (returned != NULL)
778 {
779 1 *returned = (gate_size_t)bytes;
780 }
781 1 ret = GATE_RESULT_OK;
782 } while (0);
783
784 1 return ret;
785 }
786
787 1 gate_result_t gate_pipe_write(gate_pipe_t pipe, char const* buffer, gate_size_t bufferlen, gate_size_t* written)
788 {
789 1 const int fd = (int)(gate_intptr_t)pipe;
790 gate_result_t ret;
791 ssize_t bytes;
792
793 do
794 {
795 1 ret = check_pipe_activity(fd, true, true, NULL);
796
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
797
798 1 bytes = gate_posix_write(fd, buffer, bufferlen);
799
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (bytes < 0)
800 {
801 /* write failed */
802 gate_posix_errno(&ret);
803 break;
804 }
805
806 /* success case: */
807
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (written != NULL)
808 {
809 1 *written = (gate_size_t)bytes;
810 }
811 1 ret = GATE_RESULT_OK;
812 } while (0);
813
814 1 return ret;
815 }
816 gate_result_t gate_pipe_duplicate(gate_pipe_t src, gate_pipe_t* dst)
817 {
818 gate_result_t ret;
819 int fd = (int)(gate_intptr_t)src;
820 int newfd = dup(fd);
821 if (-1 == newfd)
822 {
823 gate_posix_errno(&ret);
824 }
825 else
826 {
827 if (dst != NULL)
828 {
829 *dst = (gate_pipe_t)(gate_intptr_t)newfd;
830 }
831 ret = GATE_RESULT_OK;
832 }
833 return ret;
834 }
835 gate_result_t gate_pipe_export(gate_pipe_t pipe, gate_string_t* pipeid)
836 {
837 gate_result_t ret = GATE_RESULT_OUTOFMEMORY;
838 gate_strbuilder_t builder;
839
840 gate_strbuilder_create(&builder, 32);
841 if (0 != gate_strbuilder_append_uint64(&builder, (gate_int64_t)(gate_intptr_t)pipe))
842 {
843 if (NULL != gate_strbuilder_to_string(&builder, pipeid))
844 {
845 ret = GATE_RESULT_OK;
846 }
847 }
848 gate_strbuilder_release(&builder);
849 return ret;
850 }
851 gate_result_t gate_pipe_import(gate_string_t const* pipeid, gate_pipe_t* pipe)
852 {
853 gate_result_t ret;
854 gate_int64_t id = 0;
855 do
856 {
857 if ((pipeid == NULL) || (pipe == NULL))
858 {
859 ret = GATE_RESULT_NULLPOINTER;
860 break;
861 }
862 if (0 == gate_str_parse_int64(pipeid->str, pipeid->length, &id))
863 {
864 ret = GATE_RESULT_INVALIDINPUT;
865 break;
866 }
867 *pipe = (gate_pipe_t)(gate_intptr_t)id;
868 ret = GATE_RESULT_OK;
869 } while (0);
870 return ret;
871 }
872
873 #endif /* GATE_IO_PIPES_POSIX_IMPL */
874
875
876
877 #if defined(GATE_IO_PIPES_NO_IMPL)
878
879 gate_pipe_t const gate_pipe_invalid = (gate_pipe_t)(gate_intptr_t)-1;
880
881 gate_result_t gate_pipe_create(gate_pipe_t* readpipe, gate_pipe_t* writepipe)
882 {
883 GATE_UNUSED_ARG(readpipe);
884 GATE_UNUSED_ARG(writepipe);
885 return GATE_RESULT_NOTIMPLEMENTED;
886 }
887 gate_result_t gate_pipe_open(gate_string_t* name, gate_enumint_t flags, gate_pipe_t* readpipe, gate_pipe_t* writepipe)
888 {
889 GATE_UNUSED_ARG(name);
890 GATE_UNUSED_ARG(flags);
891 GATE_UNUSED_ARG(readpipe);
892 GATE_UNUSED_ARG(writepipe);
893 return GATE_RESULT_NOTIMPLEMENTED;
894 }
895 gate_result_t gate_pipe_close(gate_pipe_t pipe)
896 {
897 GATE_UNUSED_ARG(pipe);
898 return GATE_RESULT_NOTIMPLEMENTED;
899 }
900 gate_result_t gate_pipe_data_available(gate_pipe_t pipe, gate_bool_t* data_available)
901 {
902 GATE_UNUSED_ARG(pipe);
903 GATE_UNUSED_ARG(data_available);
904 return GATE_RESULT_NOTIMPLEMENTED;
905 }
906 gate_result_t gate_pipe_read(gate_pipe_t pipe, char* buffer, gate_size_t bufferlen, gate_size_t* returned)
907 {
908 GATE_UNUSED_ARG(pipe);
909 GATE_UNUSED_ARG(buffer);
910 GATE_UNUSED_ARG(bufferlen);
911 GATE_UNUSED_ARG(returned);
912 return GATE_RESULT_NOTIMPLEMENTED;
913 }
914 gate_result_t gate_pipe_write(gate_pipe_t pipe, char const* buffer, gate_size_t bufferlen, gate_size_t* written)
915 {
916 GATE_UNUSED_ARG(pipe);
917 GATE_UNUSED_ARG(buffer);
918 GATE_UNUSED_ARG(bufferlen);
919 GATE_UNUSED_ARG(written);
920 return GATE_RESULT_NOTIMPLEMENTED;
921 }
922 gate_result_t gate_pipe_duplicate(gate_pipe_t src, gate_pipe_t* dst)
923 {
924 GATE_UNUSED_ARG(src);
925 GATE_UNUSED_ARG(dst);
926 return GATE_RESULT_NOTIMPLEMENTED;
927 }
928 gate_result_t gate_pipe_export(gate_pipe_t pipe, gate_string_t* pipeid)
929 {
930 GATE_UNUSED_ARG(pipe);
931 GATE_UNUSED_ARG(pipeid);
932 return GATE_RESULT_NOTIMPLEMENTED;
933 }
934 gate_result_t gate_pipe_import(gate_string_t const* pipeid, gate_pipe_t* pipe)
935 {
936 GATE_UNUSED_ARG(pipeid);
937 GATE_UNUSED_ARG(pipe);
938 return GATE_RESULT_NOTIMPLEMENTED;
939 }
940
941
942 #endif /* GATE_IO_PIPES_NO_IMPL */
943