GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/pipes.c
Date: 2026-03-20 22:56:14
Exec Total Coverage
Lines: 110 206 53.4%
Functions: 12 22 54.5%
Branches: 45 106 42.5%

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