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 |