GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/pipes.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 78 205 38.0%
Functions: 7 21 33.3%
Branches: 35 106 33.0%

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