GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/pipes.c
Date: 2025-09-22 22:57:09
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* 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 1 const int fd = (int)(gate_intptr_t)pipe;
766 gate_result_t ret;
767 ssize_t bytes;
768 do
769 {
770 1 ret = check_pipe_activity(fd, false, true, NULL);
771
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
772
773 1 bytes = gate_posix_read(fd, buffer, bufferlen);
774
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (bytes < 0)
775 {
776 /* read failed */
777 ✗ gate_posix_errno(&ret);
778 ✗ break;
779 }
780
781 /* success case: */
782
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (returned != NULL)
783 {
784 1 *returned = (gate_size_t)bytes;
785 }
786 1 ret = GATE_RESULT_OK;
787 } while (0);
788
789 1 return ret;
790 }
791
792 1 gate_result_t gate_pipe_write(gate_pipe_t pipe, char const* buffer, gate_size_t bufferlen, gate_size_t* written)
793 {
794 1 const int fd = (int)(gate_intptr_t)pipe;
795 gate_result_t ret;
796 ssize_t bytes;
797
798 do
799 {
800 1 ret = check_pipe_activity(fd, true, true, NULL);
801
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
802
803 1 bytes = gate_posix_write(fd, buffer, bufferlen);
804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (bytes < 0)
805 {
806 /* write failed */
807 ✗ gate_posix_errno(&ret);
808 ✗ break;
809 }
810
811 /* success case: */
812
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (written != NULL)
813 {
814 1 *written = (gate_size_t)bytes;
815 }
816 1 ret = GATE_RESULT_OK;
817 } while (0);
818
819 1 return ret;
820 }
821 ✗ gate_result_t gate_pipe_duplicate(gate_pipe_t src, gate_pipe_t* dst)
822 {
823 gate_result_t ret;
824 ✗ int fd = (int)(gate_intptr_t)src;
825 ✗ int newfd = dup(fd);
826 ✗ if (-1 == newfd)
827 {
828 ✗ gate_posix_errno(&ret);
829 }
830 else
831 {
832 ✗ if (dst != NULL)
833 {
834 ✗ *dst = (gate_pipe_t)(gate_intptr_t)newfd;
835 }
836 ✗ ret = GATE_RESULT_OK;
837 }
838 ✗ return ret;
839 }
840 ✗ gate_result_t gate_pipe_export(gate_pipe_t pipe, gate_string_t* pipeid)
841 {
842 ✗ gate_result_t ret = GATE_RESULT_OUTOFMEMORY;
843 gate_strbuilder_t builder;
844
845 ✗ gate_strbuilder_create(&builder, 32);
846 ✗ if (0 != gate_strbuilder_append_uint64(&builder, (gate_int64_t)(gate_intptr_t)pipe))
847 {
848 ✗ if (NULL != gate_strbuilder_to_string(&builder, pipeid))
849 {
850 ✗ ret = GATE_RESULT_OK;
851 }
852 }
853 ✗ gate_strbuilder_release(&builder);
854 ✗ return ret;
855 }
856 ✗ gate_result_t gate_pipe_import(gate_string_t const* pipeid, gate_pipe_t* pipe)
857 {
858 gate_result_t ret;
859 ✗ gate_int64_t id = 0;
860 do
861 {
862 ✗ if ((pipeid == NULL) || (pipe == NULL))
863 {
864 ✗ ret = GATE_RESULT_NULLPOINTER;
865 ✗ break;
866 }
867 ✗ if (0 == gate_str_parse_int64(pipeid->str, pipeid->length, &id))
868 {
869 ✗ ret = GATE_RESULT_INVALIDINPUT;
870 ✗ break;
871 }
872 ✗ *pipe = (gate_pipe_t)(gate_intptr_t)id;
873 ✗ ret = GATE_RESULT_OK;
874 } while (0);
875 ✗ return ret;
876 }
877
878 #endif /* GATE_IO_PIPES_POSIX_IMPL */
879
880
881
882 #if defined(GATE_IO_PIPES_NO_IMPL)
883
884 gate_pipe_t const gate_pipe_invalid = (gate_pipe_t)(gate_intptr_t)-1;
885
886 gate_result_t gate_pipe_create(gate_pipe_t* readpipe, gate_pipe_t* writepipe)
887 {
888 GATE_UNUSED_ARG(readpipe);
889 GATE_UNUSED_ARG(writepipe);
890 return GATE_RESULT_NOTIMPLEMENTED;
891 }
892 gate_result_t gate_pipe_open(gate_string_t* name, gate_enumint_t flags, gate_pipe_t* readpipe, gate_pipe_t* writepipe)
893 {
894 GATE_UNUSED_ARG(name);
895 GATE_UNUSED_ARG(flags);
896 GATE_UNUSED_ARG(readpipe);
897 GATE_UNUSED_ARG(writepipe);
898 return GATE_RESULT_NOTIMPLEMENTED;
899 }
900 gate_result_t gate_pipe_close(gate_pipe_t pipe)
901 {
902 GATE_UNUSED_ARG(pipe);
903 return GATE_RESULT_NOTIMPLEMENTED;
904 }
905 gate_result_t gate_pipe_data_available(gate_pipe_t pipe, gate_bool_t* data_available)
906 {
907 GATE_UNUSED_ARG(pipe);
908 GATE_UNUSED_ARG(data_available);
909 return GATE_RESULT_NOTIMPLEMENTED;
910 }
911 gate_result_t gate_pipe_read(gate_pipe_t pipe, char* buffer, gate_size_t bufferlen, gate_size_t* returned)
912 {
913 GATE_UNUSED_ARG(pipe);
914 GATE_UNUSED_ARG(buffer);
915 GATE_UNUSED_ARG(bufferlen);
916 GATE_UNUSED_ARG(returned);
917 return GATE_RESULT_NOTIMPLEMENTED;
918 }
919 gate_result_t gate_pipe_write(gate_pipe_t pipe, char const* buffer, gate_size_t bufferlen, gate_size_t* written)
920 {
921 GATE_UNUSED_ARG(pipe);
922 GATE_UNUSED_ARG(buffer);
923 GATE_UNUSED_ARG(bufferlen);
924 GATE_UNUSED_ARG(written);
925 return GATE_RESULT_NOTIMPLEMENTED;
926 }
927 gate_result_t gate_pipe_duplicate(gate_pipe_t src, gate_pipe_t* dst)
928 {
929 GATE_UNUSED_ARG(src);
930 GATE_UNUSED_ARG(dst);
931 return GATE_RESULT_NOTIMPLEMENTED;
932 }
933 gate_result_t gate_pipe_export(gate_pipe_t pipe, gate_string_t* pipeid)
934 {
935 GATE_UNUSED_ARG(pipe);
936 GATE_UNUSED_ARG(pipeid);
937 return GATE_RESULT_NOTIMPLEMENTED;
938 }
939 gate_result_t gate_pipe_import(gate_string_t const* pipeid, gate_pipe_t* pipe)
940 {
941 GATE_UNUSED_ARG(pipeid);
942 GATE_UNUSED_ARG(pipe);
943 return GATE_RESULT_NOTIMPLEMENTED;
944 }
945
946
947 #endif /* GATE_IO_PIPES_NO_IMPL */
948