FreeRDP
Loading...
Searching...
No Matches
pipe.c
1
22#include <winpr/config.h>
23
24#include <winpr/crt.h>
25#include <winpr/path.h>
26#include <winpr/synch.h>
27#include <winpr/handle.h>
28
29#include <winpr/pipe.h>
30
31#ifdef WINPR_HAVE_UNISTD_H
32#include <unistd.h>
33#endif
34
35#ifndef _WIN32
36
37#include "../handle/handle.h"
38
39#include <fcntl.h>
40#include <errno.h>
41#include <sys/un.h>
42#include <sys/socket.h>
43#include <winpr/assert.h>
44
45#ifdef WINPR_HAVE_SYS_AIO_H
46#undef WINPR_HAVE_SYS_AIO_H /* disable for now, incomplete */
47#endif
48
49#ifdef WINPR_HAVE_SYS_AIO_H
50#include <aio.h>
51#endif
52
53#include "pipe.h"
54
55#include "../log.h"
56#define TAG WINPR_TAG("pipe")
57
58/*
59 * Since the WinPR implementation of named pipes makes use of UNIX domain
60 * sockets, it is not possible to bind the same name more than once (i.e.,
61 * SO_REUSEADDR does not work with UNIX domain sockets). As a result, the
62 * first call to CreateNamedPipe with name n creates a "shared" UNIX domain
63 * socket descriptor that gets duplicated via dup() for the first and all
64 * subsequent calls to CreateNamedPipe with name n.
65 *
66 * The following array keeps track of the references to the shared socked
67 * descriptors. If an entry's reference count is zero the base socket
68 * descriptor gets closed and the entry is removed from the list.
69 */
70
71static wArrayList* g_NamedPipeServerSockets = NULL;
72
73typedef struct
74{
75 char* name;
76 int serverfd;
77 int references;
78} NamedPipeServerSocketEntry;
79
80static BOOL PipeIsHandled(HANDLE handle)
81{
82 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_ANONYMOUS_PIPE, FALSE);
83}
84
85static int PipeGetFd(HANDLE handle)
86{
87 WINPR_PIPE* pipe = (WINPR_PIPE*)handle;
88
89 if (!PipeIsHandled(handle))
90 return -1;
91
92 return pipe->fd;
93}
94
95static BOOL PipeCloseHandle(HANDLE handle)
96{
97 WINPR_PIPE* pipe = (WINPR_PIPE*)handle;
98
99 if (!PipeIsHandled(handle))
100 return FALSE;
101
102 if (pipe->fd != -1)
103 {
104 close(pipe->fd);
105 pipe->fd = -1;
106 }
107
108 free(handle);
109 return TRUE;
110}
111
112static BOOL PipeRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
113 LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
114{
115 SSIZE_T io_status = 0;
116 WINPR_PIPE* pipe = NULL;
117 BOOL status = TRUE;
118
119 if (lpOverlapped)
120 {
121 WLog_ERR(TAG, "WinPR does not support the lpOverlapped parameter");
122 SetLastError(ERROR_NOT_SUPPORTED);
123 return FALSE;
124 }
125
126 pipe = (WINPR_PIPE*)Object;
127
128 do
129 {
130 io_status = read(pipe->fd, lpBuffer, nNumberOfBytesToRead);
131 } while ((io_status < 0) && (errno == EINTR));
132
133 if (io_status < 0)
134 {
135 status = FALSE;
136
137 switch (errno)
138 {
139 case EWOULDBLOCK:
140 SetLastError(ERROR_NO_DATA);
141 break;
142 default:
143 break;
144 }
145 }
146
147 if (lpNumberOfBytesRead)
148 *lpNumberOfBytesRead = (DWORD)io_status;
149
150 return status;
151}
152
153static BOOL PipeWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
154 LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
155{
156 SSIZE_T io_status = 0;
157 WINPR_PIPE* pipe = NULL;
158
159 if (lpOverlapped)
160 {
161 WLog_ERR(TAG, "WinPR does not support the lpOverlapped parameter");
162 SetLastError(ERROR_NOT_SUPPORTED);
163 return FALSE;
164 }
165
166 pipe = (WINPR_PIPE*)Object;
167
168 do
169 {
170 io_status = write(pipe->fd, lpBuffer, nNumberOfBytesToWrite);
171 } while ((io_status < 0) && (errno == EINTR));
172
173 if ((io_status < 0) && (errno == EWOULDBLOCK))
174 io_status = 0;
175
176 *lpNumberOfBytesWritten = (DWORD)io_status;
177 return TRUE;
178}
179
180static HANDLE_OPS ops = { PipeIsHandled,
181 PipeCloseHandle,
182 PipeGetFd,
183 NULL, /* CleanupHandle */
184 PipeRead,
185 NULL, /* FileReadEx */
186 NULL, /* FileReadScatter */
187 PipeWrite,
188 NULL, /* FileWriteEx */
189 NULL, /* FileWriteGather */
190 NULL, /* FileGetFileSize */
191 NULL, /* FlushFileBuffers */
192 NULL, /* FileSetEndOfFile */
193 NULL, /* FileSetFilePointer */
194 NULL, /* SetFilePointerEx */
195 NULL, /* FileLockFile */
196 NULL, /* FileLockFileEx */
197 NULL, /* FileUnlockFile */
198 NULL, /* FileUnlockFileEx */
199 NULL /* SetFileTime */
200 ,
201 NULL };
202
203static BOOL NamedPipeIsHandled(HANDLE handle)
204{
205 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_NAMED_PIPE, TRUE);
206}
207
208static int NamedPipeGetFd(HANDLE handle)
209{
210 WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*)handle;
211
212 if (!NamedPipeIsHandled(handle))
213 return -1;
214
215 if (pipe->ServerMode)
216 return pipe->serverfd;
217
218 return pipe->clientfd;
219}
220
221static BOOL NamedPipeCloseHandle(HANDLE handle)
222{
223 WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)handle;
224
225 /* This check confuses the analyzer. Since not all handle
226 * types are handled here, it guesses that the memory of a
227 * NamedPipeHandle may leak. */
228#ifndef __clang_analyzer__
229 if (!NamedPipeIsHandled(handle))
230 return FALSE;
231#endif
232
233 if (pNamedPipe->pfnUnrefNamedPipe)
234 pNamedPipe->pfnUnrefNamedPipe(pNamedPipe);
235
236 free(pNamedPipe->name);
237 free(pNamedPipe->lpFileName);
238 free(pNamedPipe->lpFilePath);
239
240 if (pNamedPipe->serverfd != -1)
241 close(pNamedPipe->serverfd);
242
243 if (pNamedPipe->clientfd != -1)
244 close(pNamedPipe->clientfd);
245
246 free(pNamedPipe);
247 return TRUE;
248}
249
250BOOL NamedPipeRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
251 LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
252{
253 SSIZE_T io_status = 0;
254 BOOL status = TRUE;
255
256 WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*)Object;
257
258 if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
259 {
260 if (pipe->clientfd == -1)
261 return FALSE;
262
263 do
264 {
265 io_status = read(pipe->clientfd, lpBuffer, nNumberOfBytesToRead);
266 } while ((io_status < 0) && (errno == EINTR));
267
268 if (io_status == 0)
269 {
270 SetLastError(ERROR_BROKEN_PIPE);
271 status = FALSE;
272 }
273 else if (io_status < 0)
274 {
275 status = FALSE;
276
277 switch (errno)
278 {
279 case EWOULDBLOCK:
280 SetLastError(ERROR_NO_DATA);
281 break;
282
283 default:
284 SetLastError(ERROR_BROKEN_PIPE);
285 break;
286 }
287 }
288
289 if (lpNumberOfBytesRead)
290 *lpNumberOfBytesRead = (DWORD)io_status;
291 }
292 else
293 {
294 /* Overlapped I/O */
295 if (!lpOverlapped)
296 {
297 WLog_ERR(TAG, "%s requires lpOverlapped != NULL as FILE_FLAG_OVERLAPPED is set");
298 SetLastError(ERROR_NOT_SUPPORTED);
299 return FALSE;
300 }
301
302 if (pipe->clientfd == -1)
303 return FALSE;
304
305 pipe->lpOverlapped = lpOverlapped;
306#ifdef WINPR_HAVE_SYS_AIO_H
307 {
308 int aio_status;
309 struct aiocb cb = { 0 };
310
311 cb.aio_fildes = pipe->clientfd;
312 cb.aio_buf = lpBuffer;
313 cb.aio_nbytes = nNumberOfBytesToRead;
314 cb.aio_offset = lpOverlapped->Offset;
315 cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
316 cb.aio_sigevent.sigev_signo = SIGIO;
317 cb.aio_sigevent.sigev_value.sival_ptr = (void*)lpOverlapped;
318 InstallAioSignalHandler();
319 aio_status = aio_read(&cb);
320 WLog_DBG(TAG, "aio_read status: %d", aio_status);
321
322 if (aio_status < 0)
323 status = FALSE;
324
325 return status;
326 }
327#else
328 /* synchronous behavior */
329 lpOverlapped->Internal = 0;
330 lpOverlapped->InternalHigh = (ULONG_PTR)nNumberOfBytesToRead;
331 lpOverlapped->DUMMYUNIONNAME.Pointer = (PVOID)lpBuffer;
332 (void)SetEvent(lpOverlapped->hEvent);
333#endif
334 }
335
336 return status;
337}
338
339BOOL NamedPipeWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
340 LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
341{
342 SSIZE_T io_status = 0;
343 WINPR_NAMED_PIPE* pipe = NULL;
344 BOOL status = TRUE;
345
346 if (lpOverlapped)
347 {
348 WLog_ERR(TAG, "WinPR does not support the lpOverlapped parameter");
349 SetLastError(ERROR_NOT_SUPPORTED);
350 return FALSE;
351 }
352
353 pipe = (WINPR_NAMED_PIPE*)Object;
354
355 if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
356 {
357 if (pipe->clientfd == -1)
358 return FALSE;
359
360 do
361 {
362 io_status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite);
363 } while ((io_status < 0) && (errno == EINTR));
364
365 if (io_status < 0)
366 {
367 *lpNumberOfBytesWritten = 0;
368
369 switch (errno)
370 {
371 case EWOULDBLOCK:
372 io_status = 0;
373 status = TRUE;
374 break;
375
376 default:
377 status = FALSE;
378 }
379 }
380
381 *lpNumberOfBytesWritten = (DWORD)io_status;
382 return status;
383 }
384 else
385 {
386 /* Overlapped I/O */
387 if (!lpOverlapped)
388 return FALSE;
389
390 if (pipe->clientfd == -1)
391 return FALSE;
392
393 pipe->lpOverlapped = lpOverlapped;
394#ifdef WINPR_HAVE_SYS_AIO_H
395 {
396 struct aiocb cb = { 0 };
397
398 cb.aio_fildes = pipe->clientfd;
399 cb.aio_buf = (void*)lpBuffer;
400 cb.aio_nbytes = nNumberOfBytesToWrite;
401 cb.aio_offset = lpOverlapped->Offset;
402 cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
403 cb.aio_sigevent.sigev_signo = SIGIO;
404 cb.aio_sigevent.sigev_value.sival_ptr = (void*)lpOverlapped;
405 InstallAioSignalHandler();
406 io_status = aio_write(&cb);
407 WLog_DBG("aio_write status: %" PRIdz, io_status);
408
409 if (io_status < 0)
410 status = FALSE;
411
412 return status;
413 }
414#else
415 /* synchronous behavior */
416 lpOverlapped->Internal = 1;
417 lpOverlapped->InternalHigh = (ULONG_PTR)nNumberOfBytesToWrite;
418 {
419 union
420 {
421 LPCVOID cpv;
422 PVOID pv;
423 } cnv;
424 cnv.cpv = lpBuffer;
425 lpOverlapped->DUMMYUNIONNAME.Pointer = cnv.pv;
426 }
427 (void)SetEvent(lpOverlapped->hEvent);
428#endif
429 }
430
431 return TRUE;
432}
433
434static HANDLE_OPS namedOps = { NamedPipeIsHandled,
435 NamedPipeCloseHandle,
436 NamedPipeGetFd,
437 NULL, /* CleanupHandle */
438 NamedPipeRead,
439 NULL,
440 NULL,
441 NamedPipeWrite,
442 NULL,
443 NULL,
444 NULL,
445 NULL,
446 NULL,
447 NULL,
448 NULL,
449 NULL,
450 NULL,
451 NULL,
452 NULL,
453 NULL,
454 NULL };
455
456static BOOL InitWinPRPipeModule(void)
457{
458 if (g_NamedPipeServerSockets)
459 return TRUE;
460
461 g_NamedPipeServerSockets = ArrayList_New(FALSE);
462 return g_NamedPipeServerSockets != NULL;
463}
464
465/*
466 * Unnamed pipe
467 */
468
469BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes,
470 DWORD nSize)
471{
472 int pipe_fd[] = { -1, -1 };
473 WINPR_PIPE* pReadPipe = NULL;
474 WINPR_PIPE* pWritePipe = NULL;
475
476 WINPR_UNUSED(lpPipeAttributes);
477 WINPR_UNUSED(nSize);
478
479 if (pipe(pipe_fd) < 0)
480 {
481 if (pipe_fd[0] >= 0)
482 close(pipe_fd[0]);
483 if (pipe_fd[1] >= 0)
484 close(pipe_fd[1]);
485
486 WLog_ERR(TAG, "failed to create pipe");
487 return FALSE;
488 }
489
490 pReadPipe = (WINPR_PIPE*)calloc(1, sizeof(WINPR_PIPE));
491 pWritePipe = (WINPR_PIPE*)calloc(1, sizeof(WINPR_PIPE));
492
493 if (!pReadPipe || !pWritePipe)
494 {
495 if (pipe_fd[0] >= 0)
496 close(pipe_fd[0]);
497 if (pipe_fd[1] >= 0)
498 close(pipe_fd[1]);
499 free(pReadPipe);
500 free(pWritePipe);
501 return FALSE;
502 }
503
504 pReadPipe->fd = pipe_fd[0];
505 pWritePipe->fd = pipe_fd[1];
506 WINPR_HANDLE_SET_TYPE_AND_MODE(pReadPipe, HANDLE_TYPE_ANONYMOUS_PIPE, WINPR_FD_READ);
507 pReadPipe->common.ops = &ops;
508 *((ULONG_PTR*)hReadPipe) = (ULONG_PTR)pReadPipe;
509 WINPR_HANDLE_SET_TYPE_AND_MODE(pWritePipe, HANDLE_TYPE_ANONYMOUS_PIPE, WINPR_FD_READ);
510 pWritePipe->common.ops = &ops;
511 *((ULONG_PTR*)hWritePipe) = (ULONG_PTR)pWritePipe;
512 return TRUE;
513}
514
519static void winpr_unref_named_pipe(WINPR_NAMED_PIPE* pNamedPipe)
520{
521 NamedPipeServerSocketEntry* baseSocket = NULL;
522
523 if (!pNamedPipe)
524 return;
525
526 WINPR_ASSERT(pNamedPipe->name);
527 WINPR_ASSERT(g_NamedPipeServerSockets);
528 // WLog_VRB(TAG, "%p (%s)", (void*) pNamedPipe, pNamedPipe->name);
529 ArrayList_Lock(g_NamedPipeServerSockets);
530
531 for (size_t index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
532 {
533 baseSocket =
534 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
535 WINPR_ASSERT(baseSocket->name);
536
537 if (!strcmp(baseSocket->name, pNamedPipe->name))
538 {
539 WINPR_ASSERT(baseSocket->references > 0);
540 WINPR_ASSERT(baseSocket->serverfd != -1);
541
542 if (--baseSocket->references == 0)
543 {
544 // WLog_DBG(TAG, "removing shared server socked resource");
545 // WLog_DBG(TAG, "closing shared serverfd %d", baseSocket->serverfd);
546 ArrayList_Remove(g_NamedPipeServerSockets, baseSocket);
547 close(baseSocket->serverfd);
548 free(baseSocket->name);
549 free(baseSocket);
550 }
551
552 break;
553 }
554 }
555
556 ArrayList_Unlock(g_NamedPipeServerSockets);
557}
558
559HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
560 DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut,
561 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
562{
563 char* lpPipePath = NULL;
564 WINPR_NAMED_PIPE* pNamedPipe = NULL;
565 int serverfd = -1;
566 NamedPipeServerSocketEntry* baseSocket = NULL;
567
568 WINPR_UNUSED(lpSecurityAttributes);
569
570 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
571 {
572 WLog_ERR(TAG, "WinPR does not support the FILE_FLAG_OVERLAPPED flag");
573 SetLastError(ERROR_NOT_SUPPORTED);
574 return INVALID_HANDLE_VALUE;
575 }
576
577 if (!lpName)
578 return INVALID_HANDLE_VALUE;
579
580 if (!InitWinPRPipeModule())
581 return INVALID_HANDLE_VALUE;
582
583 pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1, sizeof(WINPR_NAMED_PIPE));
584
585 if (!pNamedPipe)
586 return INVALID_HANDLE_VALUE;
587
588 ArrayList_Lock(g_NamedPipeServerSockets);
589 WINPR_HANDLE_SET_TYPE_AND_MODE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE, WINPR_FD_READ);
590 pNamedPipe->serverfd = -1;
591 pNamedPipe->clientfd = -1;
592
593 if (!(pNamedPipe->name = _strdup(lpName)))
594 goto out;
595
596 if (!(pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName)))
597 goto out;
598
599 if (!(pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName)))
600 goto out;
601
602 pNamedPipe->dwOpenMode = dwOpenMode;
603 pNamedPipe->dwPipeMode = dwPipeMode;
604 pNamedPipe->nMaxInstances = nMaxInstances;
605 pNamedPipe->nOutBufferSize = nOutBufferSize;
606 pNamedPipe->nInBufferSize = nInBufferSize;
607 pNamedPipe->nDefaultTimeOut = nDefaultTimeOut;
608 pNamedPipe->dwFlagsAndAttributes = dwOpenMode;
609 pNamedPipe->clientfd = -1;
610 pNamedPipe->ServerMode = TRUE;
611 pNamedPipe->common.ops = &namedOps;
612
613 for (size_t index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
614 {
615 baseSocket =
616 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
617
618 if (!strcmp(baseSocket->name, lpName))
619 {
620 serverfd = baseSocket->serverfd;
621 // WLog_DBG(TAG, "using shared socked resource for pipe %p (%s)", (void*) pNamedPipe,
622 // lpName);
623 break;
624 }
625 }
626
627 /* If this is the first instance of the named pipe... */
628 if (serverfd == -1)
629 {
630 struct sockaddr_un s = { 0 };
631 /* Create the UNIX domain socket and start listening. */
632 if (!(lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA()))
633 goto out;
634
635 if (!winpr_PathFileExists(lpPipePath))
636 {
637 if (!CreateDirectoryA(lpPipePath, 0))
638 {
639 free(lpPipePath);
640 goto out;
641 }
642
643 UnixChangeFileMode(lpPipePath, 0xFFFF);
644 }
645
646 free(lpPipePath);
647
648 if (winpr_PathFileExists(pNamedPipe->lpFilePath))
649 winpr_DeleteFile(pNamedPipe->lpFilePath);
650
651 if ((serverfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
652 {
653 char ebuffer[256] = { 0 };
654 WLog_ERR(TAG, "CreateNamedPipeA: socket error, %s",
655 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
656 goto out;
657 }
658
659 s.sun_family = AF_UNIX;
660 (void)sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path), "%s", pNamedPipe->lpFilePath);
661
662 if (bind(serverfd, (struct sockaddr*)&s, sizeof(struct sockaddr_un)) == -1)
663 {
664 char ebuffer[256] = { 0 };
665 WLog_ERR(TAG, "CreateNamedPipeA: bind error, %s",
666 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
667 goto out;
668 }
669
670 if (listen(serverfd, 2) == -1)
671 {
672 char ebuffer[256] = { 0 };
673 WLog_ERR(TAG, "CreateNamedPipeA: listen error, %s",
674 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
675 goto out;
676 }
677
678 UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF);
679
680 if (!(baseSocket = (NamedPipeServerSocketEntry*)malloc(sizeof(NamedPipeServerSocketEntry))))
681 goto out;
682
683 if (!(baseSocket->name = _strdup(lpName)))
684 {
685 free(baseSocket);
686 goto out;
687 }
688
689 baseSocket->serverfd = serverfd;
690 baseSocket->references = 0;
691
692 if (!ArrayList_Append(g_NamedPipeServerSockets, baseSocket))
693 {
694 free(baseSocket->name);
695 free(baseSocket);
696 goto out;
697 }
698
699 // WLog_DBG(TAG, "created shared socked resource for pipe %p (%s). base serverfd = %d",
700 // (void*) pNamedPipe, lpName, serverfd);
701 }
702
703 pNamedPipe->serverfd = dup(baseSocket->serverfd);
704 // WLog_DBG(TAG, "using serverfd %d (duplicated from %d)", pNamedPipe->serverfd,
705 // baseSocket->serverfd);
706 pNamedPipe->pfnUnrefNamedPipe = winpr_unref_named_pipe;
707 baseSocket->references++;
708
709 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
710 {
711 // TODO: Implement
712 WLog_ERR(TAG, "TODO: implement this");
713 }
714
715 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ArrayList_Append takes ownership of baseSocket
716 ArrayList_Unlock(g_NamedPipeServerSockets);
717 return pNamedPipe;
718out:
719 NamedPipeCloseHandle(pNamedPipe);
720
721 if (serverfd != -1)
722 close(serverfd);
723
724 ArrayList_Unlock(g_NamedPipeServerSockets);
725 return INVALID_HANDLE_VALUE;
726}
727
728HANDLE CreateNamedPipeW(WINPR_ATTR_UNUSED LPCWSTR lpName, WINPR_ATTR_UNUSED DWORD dwOpenMode,
729 WINPR_ATTR_UNUSED DWORD dwPipeMode, WINPR_ATTR_UNUSED DWORD nMaxInstances,
730 WINPR_ATTR_UNUSED DWORD nOutBufferSize,
731 WINPR_ATTR_UNUSED DWORD nInBufferSize,
732 WINPR_ATTR_UNUSED DWORD nDefaultTimeOut,
733 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpSecurityAttributes)
734{
735 WLog_ERR(TAG, "is not implemented");
736 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
737 return NULL;
738}
739
740BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped)
741{
742 int status = 0;
743 socklen_t length = 0;
744 WINPR_NAMED_PIPE* pNamedPipe = NULL;
745
746 if (lpOverlapped)
747 {
748 WLog_ERR(TAG, "WinPR does not support the lpOverlapped parameter");
749 SetLastError(ERROR_NOT_SUPPORTED);
750 return FALSE;
751 }
752
753 if (!hNamedPipe)
754 return FALSE;
755
756 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
757
758 if (!(pNamedPipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
759 {
760 struct sockaddr_un s = { 0 };
761 length = sizeof(struct sockaddr_un);
762 status = accept(pNamedPipe->serverfd, (struct sockaddr*)&s, &length);
763
764 if (status < 0)
765 {
766 WLog_ERR(TAG, "ConnectNamedPipe: accept error");
767 return FALSE;
768 }
769
770 pNamedPipe->clientfd = status;
771 pNamedPipe->ServerMode = FALSE;
772 }
773 else
774 {
775 if (!lpOverlapped)
776 return FALSE;
777
778 if (pNamedPipe->serverfd == -1)
779 return FALSE;
780
781 pNamedPipe->lpOverlapped = lpOverlapped;
782 /* synchronous behavior */
783 lpOverlapped->Internal = 2;
784 lpOverlapped->InternalHigh = (ULONG_PTR)0;
785 lpOverlapped->DUMMYUNIONNAME.Pointer = (PVOID)NULL;
786 (void)SetEvent(lpOverlapped->hEvent);
787 }
788
789 return TRUE;
790}
791
792BOOL DisconnectNamedPipe(HANDLE hNamedPipe)
793{
794 WINPR_NAMED_PIPE* pNamedPipe = NULL;
795 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
796
797 if (pNamedPipe->clientfd != -1)
798 {
799 close(pNamedPipe->clientfd);
800 pNamedPipe->clientfd = -1;
801 }
802
803 return TRUE;
804}
805
806BOOL PeekNamedPipe(WINPR_ATTR_UNUSED HANDLE hNamedPipe, WINPR_ATTR_UNUSED LPVOID lpBuffer,
807 WINPR_ATTR_UNUSED DWORD nBufferSize, WINPR_ATTR_UNUSED LPDWORD lpBytesRead,
808 WINPR_ATTR_UNUSED LPDWORD lpTotalBytesAvail,
809 WINPR_ATTR_UNUSED LPDWORD lpBytesLeftThisMessage)
810{
811 WLog_ERR(TAG, "Not implemented");
812 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
813 return FALSE;
814}
815
816BOOL TransactNamedPipe(WINPR_ATTR_UNUSED HANDLE hNamedPipe, WINPR_ATTR_UNUSED LPVOID lpInBuffer,
817 WINPR_ATTR_UNUSED DWORD nInBufferSize, WINPR_ATTR_UNUSED LPVOID lpOutBuffer,
818 WINPR_ATTR_UNUSED DWORD nOutBufferSize,
819 WINPR_ATTR_UNUSED LPDWORD lpBytesRead,
820 WINPR_ATTR_UNUSED LPOVERLAPPED lpOverlapped)
821{
822 WLog_ERR(TAG, "Not implemented");
823 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
824 return FALSE;
825}
826
827BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut)
828{
829 BOOL status = 0;
830 DWORD nWaitTime = 0;
831 char* lpFilePath = NULL;
832 DWORD dwSleepInterval = 0;
833
834 if (!lpNamedPipeName)
835 return FALSE;
836
837 lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpNamedPipeName);
838
839 if (!lpFilePath)
840 return FALSE;
841
842 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
843 nTimeOut = 50;
844
845 nWaitTime = 0;
846 status = TRUE;
847 dwSleepInterval = 10;
848
849 while (!winpr_PathFileExists(lpFilePath))
850 {
851 Sleep(dwSleepInterval);
852 nWaitTime += dwSleepInterval;
853
854 if (nWaitTime >= nTimeOut)
855 {
856 status = FALSE;
857 break;
858 }
859 }
860
861 free(lpFilePath);
862 return status;
863}
864
865BOOL WaitNamedPipeW(WINPR_ATTR_UNUSED LPCWSTR lpNamedPipeName, WINPR_ATTR_UNUSED DWORD nTimeOut)
866{
867 WLog_ERR(TAG, "Not implemented");
868 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
869 return FALSE;
870}
871
872// NOLINTBEGIN(readability-non-const-parameter)
873BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount,
874 LPDWORD lpCollectDataTimeout)
875// NOLINTEND(readability-non-const-parameter)
876{
877 int fd = 0;
878 int flags = 0;
879 WINPR_NAMED_PIPE* pNamedPipe = NULL;
880 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
881
882 if (lpMode)
883 {
884 pNamedPipe->dwPipeMode = *lpMode;
885 fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
886
887 if (fd == -1)
888 return FALSE;
889
890 flags = fcntl(fd, F_GETFL);
891
892 if (flags < 0)
893 return FALSE;
894
895 if (pNamedPipe->dwPipeMode & PIPE_NOWAIT)
896 flags = (flags | O_NONBLOCK);
897 else
898 flags = (flags & ~(O_NONBLOCK));
899
900 if (fcntl(fd, F_SETFL, flags) < 0)
901 return FALSE;
902 }
903
904 if (lpMaxCollectionCount)
905 {
906 }
907
908 if (lpCollectDataTimeout)
909 {
910 }
911
912 return TRUE;
913}
914
915BOOL ImpersonateNamedPipeClient(WINPR_ATTR_UNUSED HANDLE hNamedPipe)
916{
917 WLog_ERR(TAG, "Not implemented");
918 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
919 return FALSE;
920}
921
922BOOL GetNamedPipeClientComputerNameA(WINPR_ATTR_UNUSED HANDLE Pipe,
923 WINPR_ATTR_UNUSED LPCSTR ClientComputerName,
924 WINPR_ATTR_UNUSED ULONG ClientComputerNameLength)
925{
926 WLog_ERR(TAG, "Not implemented");
927 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
928 return FALSE;
929}
930
931BOOL GetNamedPipeClientComputerNameW(WINPR_ATTR_UNUSED HANDLE Pipe,
932 WINPR_ATTR_UNUSED LPCWSTR ClientComputerName,
933 WINPR_ATTR_UNUSED ULONG ClientComputerNameLength)
934{
935 WLog_ERR(TAG, "Not implemented");
936 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
937 return FALSE;
938}
939
940#endif