FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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 WINPR_NAMED_PIPE* pipe = NULL;
255 BOOL status = TRUE;
256
257 if (lpOverlapped)
258 {
259 WLog_ERR(TAG, "WinPR does not support the lpOverlapped parameter");
260 SetLastError(ERROR_NOT_SUPPORTED);
261 return FALSE;
262 }
263
264 pipe = (WINPR_NAMED_PIPE*)Object;
265
266 if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
267 {
268 if (pipe->clientfd == -1)
269 return FALSE;
270
271 do
272 {
273 io_status = read(pipe->clientfd, lpBuffer, nNumberOfBytesToRead);
274 } while ((io_status < 0) && (errno == EINTR));
275
276 if (io_status == 0)
277 {
278 SetLastError(ERROR_BROKEN_PIPE);
279 status = FALSE;
280 }
281 else if (io_status < 0)
282 {
283 status = FALSE;
284
285 switch (errno)
286 {
287 case EWOULDBLOCK:
288 SetLastError(ERROR_NO_DATA);
289 break;
290
291 default:
292 SetLastError(ERROR_BROKEN_PIPE);
293 break;
294 }
295 }
296
297 if (lpNumberOfBytesRead)
298 *lpNumberOfBytesRead = (DWORD)io_status;
299 }
300 else
301 {
302 /* Overlapped I/O */
303 if (!lpOverlapped)
304 return FALSE;
305
306 if (pipe->clientfd == -1)
307 return FALSE;
308
309 pipe->lpOverlapped = lpOverlapped;
310#ifdef WINPR_HAVE_SYS_AIO_H
311 {
312 int aio_status;
313 struct aiocb cb = { 0 };
314
315 cb.aio_fildes = pipe->clientfd;
316 cb.aio_buf = lpBuffer;
317 cb.aio_nbytes = nNumberOfBytesToRead;
318 cb.aio_offset = lpOverlapped->Offset;
319 cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
320 cb.aio_sigevent.sigev_signo = SIGIO;
321 cb.aio_sigevent.sigev_value.sival_ptr = (void*)lpOverlapped;
322 InstallAioSignalHandler();
323 aio_status = aio_read(&cb);
324 WLog_DBG(TAG, "aio_read status: %d", aio_status);
325
326 if (aio_status < 0)
327 status = FALSE;
328
329 return status;
330 }
331#else
332 /* synchronous behavior */
333 lpOverlapped->Internal = 0;
334 lpOverlapped->InternalHigh = (ULONG_PTR)nNumberOfBytesToRead;
335 lpOverlapped->DUMMYUNIONNAME.Pointer = (PVOID)lpBuffer;
336 (void)SetEvent(lpOverlapped->hEvent);
337#endif
338 }
339
340 return status;
341}
342
343BOOL NamedPipeWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
344 LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
345{
346 SSIZE_T io_status = 0;
347 WINPR_NAMED_PIPE* pipe = NULL;
348 BOOL status = TRUE;
349
350 if (lpOverlapped)
351 {
352 WLog_ERR(TAG, "WinPR does not support the lpOverlapped parameter");
353 SetLastError(ERROR_NOT_SUPPORTED);
354 return FALSE;
355 }
356
357 pipe = (WINPR_NAMED_PIPE*)Object;
358
359 if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
360 {
361 if (pipe->clientfd == -1)
362 return FALSE;
363
364 do
365 {
366 io_status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite);
367 } while ((io_status < 0) && (errno == EINTR));
368
369 if (io_status < 0)
370 {
371 *lpNumberOfBytesWritten = 0;
372
373 switch (errno)
374 {
375 case EWOULDBLOCK:
376 io_status = 0;
377 status = TRUE;
378 break;
379
380 default:
381 status = FALSE;
382 }
383 }
384
385 *lpNumberOfBytesWritten = (DWORD)io_status;
386 return status;
387 }
388 else
389 {
390 /* Overlapped I/O */
391 if (!lpOverlapped)
392 return FALSE;
393
394 if (pipe->clientfd == -1)
395 return FALSE;
396
397 pipe->lpOverlapped = lpOverlapped;
398#ifdef WINPR_HAVE_SYS_AIO_H
399 {
400 struct aiocb cb = { 0 };
401
402 cb.aio_fildes = pipe->clientfd;
403 cb.aio_buf = (void*)lpBuffer;
404 cb.aio_nbytes = nNumberOfBytesToWrite;
405 cb.aio_offset = lpOverlapped->Offset;
406 cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
407 cb.aio_sigevent.sigev_signo = SIGIO;
408 cb.aio_sigevent.sigev_value.sival_ptr = (void*)lpOverlapped;
409 InstallAioSignalHandler();
410 io_status = aio_write(&cb);
411 WLog_DBG("aio_write status: %" PRIdz, io_status);
412
413 if (io_status < 0)
414 status = FALSE;
415
416 return status;
417 }
418#else
419 /* synchronous behavior */
420 lpOverlapped->Internal = 1;
421 lpOverlapped->InternalHigh = (ULONG_PTR)nNumberOfBytesToWrite;
422 {
423 union
424 {
425 LPCVOID cpv;
426 PVOID pv;
427 } cnv;
428 cnv.cpv = lpBuffer;
429 lpOverlapped->DUMMYUNIONNAME.Pointer = cnv.pv;
430 }
431 (void)SetEvent(lpOverlapped->hEvent);
432#endif
433 }
434
435 return TRUE;
436}
437
438static HANDLE_OPS namedOps = { NamedPipeIsHandled,
439 NamedPipeCloseHandle,
440 NamedPipeGetFd,
441 NULL, /* CleanupHandle */
442 NamedPipeRead,
443 NULL,
444 NULL,
445 NamedPipeWrite,
446 NULL,
447 NULL,
448 NULL,
449 NULL,
450 NULL,
451 NULL,
452 NULL,
453 NULL,
454 NULL,
455 NULL,
456 NULL,
457 NULL,
458 NULL };
459
460static BOOL InitWinPRPipeModule(void)
461{
462 if (g_NamedPipeServerSockets)
463 return TRUE;
464
465 g_NamedPipeServerSockets = ArrayList_New(FALSE);
466 return g_NamedPipeServerSockets != NULL;
467}
468
469/*
470 * Unnamed pipe
471 */
472
473BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes,
474 DWORD nSize)
475{
476 int pipe_fd[2];
477 WINPR_PIPE* pReadPipe = NULL;
478 WINPR_PIPE* pWritePipe = NULL;
479
480 WINPR_UNUSED(lpPipeAttributes);
481 WINPR_UNUSED(nSize);
482
483 pipe_fd[0] = -1;
484 pipe_fd[1] = -1;
485
486 if (pipe(pipe_fd) < 0)
487 {
488 WLog_ERR(TAG, "failed to create pipe");
489 return FALSE;
490 }
491
492 pReadPipe = (WINPR_PIPE*)calloc(1, sizeof(WINPR_PIPE));
493 pWritePipe = (WINPR_PIPE*)calloc(1, sizeof(WINPR_PIPE));
494
495 if (!pReadPipe || !pWritePipe)
496 {
497 free(pReadPipe);
498 free(pWritePipe);
499 return FALSE;
500 }
501
502 pReadPipe->fd = pipe_fd[0];
503 pWritePipe->fd = pipe_fd[1];
504 WINPR_HANDLE_SET_TYPE_AND_MODE(pReadPipe, HANDLE_TYPE_ANONYMOUS_PIPE, WINPR_FD_READ);
505 pReadPipe->common.ops = &ops;
506 *((ULONG_PTR*)hReadPipe) = (ULONG_PTR)pReadPipe;
507 WINPR_HANDLE_SET_TYPE_AND_MODE(pWritePipe, HANDLE_TYPE_ANONYMOUS_PIPE, WINPR_FD_READ);
508 pWritePipe->common.ops = &ops;
509 *((ULONG_PTR*)hWritePipe) = (ULONG_PTR)pWritePipe;
510 return TRUE;
511}
512
517static void winpr_unref_named_pipe(WINPR_NAMED_PIPE* pNamedPipe)
518{
519 NamedPipeServerSocketEntry* baseSocket = NULL;
520
521 if (!pNamedPipe)
522 return;
523
524 WINPR_ASSERT(pNamedPipe->name);
525 WINPR_ASSERT(g_NamedPipeServerSockets);
526 // WLog_VRB(TAG, "%p (%s)", (void*) pNamedPipe, pNamedPipe->name);
527 ArrayList_Lock(g_NamedPipeServerSockets);
528
529 for (size_t index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
530 {
531 baseSocket =
532 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
533 WINPR_ASSERT(baseSocket->name);
534
535 if (!strcmp(baseSocket->name, pNamedPipe->name))
536 {
537 WINPR_ASSERT(baseSocket->references > 0);
538 WINPR_ASSERT(baseSocket->serverfd != -1);
539
540 if (--baseSocket->references == 0)
541 {
542 // WLog_DBG(TAG, "removing shared server socked resource");
543 // WLog_DBG(TAG, "closing shared serverfd %d", baseSocket->serverfd);
544 ArrayList_Remove(g_NamedPipeServerSockets, baseSocket);
545 close(baseSocket->serverfd);
546 free(baseSocket->name);
547 free(baseSocket);
548 }
549
550 break;
551 }
552 }
553
554 ArrayList_Unlock(g_NamedPipeServerSockets);
555}
556
557HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
558 DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut,
559 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
560{
561 char* lpPipePath = NULL;
562 WINPR_NAMED_PIPE* pNamedPipe = NULL;
563 int serverfd = -1;
564 NamedPipeServerSocketEntry* baseSocket = NULL;
565
566 WINPR_UNUSED(lpSecurityAttributes);
567
568 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
569 {
570 WLog_ERR(TAG, "WinPR does not support the FILE_FLAG_OVERLAPPED flag");
571 SetLastError(ERROR_NOT_SUPPORTED);
572 return INVALID_HANDLE_VALUE;
573 }
574
575 if (!lpName)
576 return INVALID_HANDLE_VALUE;
577
578 if (!InitWinPRPipeModule())
579 return INVALID_HANDLE_VALUE;
580
581 pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1, sizeof(WINPR_NAMED_PIPE));
582
583 if (!pNamedPipe)
584 return INVALID_HANDLE_VALUE;
585
586 ArrayList_Lock(g_NamedPipeServerSockets);
587 WINPR_HANDLE_SET_TYPE_AND_MODE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE, WINPR_FD_READ);
588 pNamedPipe->serverfd = -1;
589 pNamedPipe->clientfd = -1;
590
591 if (!(pNamedPipe->name = _strdup(lpName)))
592 goto out;
593
594 if (!(pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName)))
595 goto out;
596
597 if (!(pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName)))
598 goto out;
599
600 pNamedPipe->dwOpenMode = dwOpenMode;
601 pNamedPipe->dwPipeMode = dwPipeMode;
602 pNamedPipe->nMaxInstances = nMaxInstances;
603 pNamedPipe->nOutBufferSize = nOutBufferSize;
604 pNamedPipe->nInBufferSize = nInBufferSize;
605 pNamedPipe->nDefaultTimeOut = nDefaultTimeOut;
606 pNamedPipe->dwFlagsAndAttributes = dwOpenMode;
607 pNamedPipe->clientfd = -1;
608 pNamedPipe->ServerMode = TRUE;
609 pNamedPipe->common.ops = &namedOps;
610
611 for (size_t index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
612 {
613 baseSocket =
614 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
615
616 if (!strcmp(baseSocket->name, lpName))
617 {
618 serverfd = baseSocket->serverfd;
619 // WLog_DBG(TAG, "using shared socked resource for pipe %p (%s)", (void*) pNamedPipe,
620 // lpName);
621 break;
622 }
623 }
624
625 /* If this is the first instance of the named pipe... */
626 if (serverfd == -1)
627 {
628 struct sockaddr_un s = { 0 };
629 /* Create the UNIX domain socket and start listening. */
630 if (!(lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA()))
631 goto out;
632
633 if (!winpr_PathFileExists(lpPipePath))
634 {
635 if (!CreateDirectoryA(lpPipePath, 0))
636 {
637 free(lpPipePath);
638 goto out;
639 }
640
641 UnixChangeFileMode(lpPipePath, 0xFFFF);
642 }
643
644 free(lpPipePath);
645
646 if (winpr_PathFileExists(pNamedPipe->lpFilePath))
647 winpr_DeleteFile(pNamedPipe->lpFilePath);
648
649 if ((serverfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
650 {
651 char ebuffer[256] = { 0 };
652 WLog_ERR(TAG, "CreateNamedPipeA: socket error, %s",
653 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
654 goto out;
655 }
656
657 s.sun_family = AF_UNIX;
658 (void)sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path), "%s", pNamedPipe->lpFilePath);
659
660 if (bind(serverfd, (struct sockaddr*)&s, sizeof(struct sockaddr_un)) == -1)
661 {
662 char ebuffer[256] = { 0 };
663 WLog_ERR(TAG, "CreateNamedPipeA: bind error, %s",
664 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
665 goto out;
666 }
667
668 if (listen(serverfd, 2) == -1)
669 {
670 char ebuffer[256] = { 0 };
671 WLog_ERR(TAG, "CreateNamedPipeA: listen error, %s",
672 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
673 goto out;
674 }
675
676 UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF);
677
678 if (!(baseSocket = (NamedPipeServerSocketEntry*)malloc(sizeof(NamedPipeServerSocketEntry))))
679 goto out;
680
681 if (!(baseSocket->name = _strdup(lpName)))
682 {
683 free(baseSocket);
684 goto out;
685 }
686
687 baseSocket->serverfd = serverfd;
688 baseSocket->references = 0;
689
690 if (!ArrayList_Append(g_NamedPipeServerSockets, baseSocket))
691 {
692 free(baseSocket->name);
693 free(baseSocket);
694 goto out;
695 }
696
697 // WLog_DBG(TAG, "created shared socked resource for pipe %p (%s). base serverfd = %d",
698 // (void*) pNamedPipe, lpName, serverfd);
699 }
700
701 pNamedPipe->serverfd = dup(baseSocket->serverfd);
702 // WLog_DBG(TAG, "using serverfd %d (duplicated from %d)", pNamedPipe->serverfd,
703 // baseSocket->serverfd);
704 pNamedPipe->pfnUnrefNamedPipe = winpr_unref_named_pipe;
705 baseSocket->references++;
706
707 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
708 {
709 // TODO: Implement
710 WLog_ERR(TAG, "TODO: implement this");
711 }
712
713 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ArrayList_Append takes ownership of baseSocket
714 ArrayList_Unlock(g_NamedPipeServerSockets);
715 return pNamedPipe;
716out:
717 NamedPipeCloseHandle(pNamedPipe);
718
719 if (serverfd != -1)
720 close(serverfd);
721
722 ArrayList_Unlock(g_NamedPipeServerSockets);
723 return INVALID_HANDLE_VALUE;
724}
725
726HANDLE CreateNamedPipeW(WINPR_ATTR_UNUSED LPCWSTR lpName, WINPR_ATTR_UNUSED DWORD dwOpenMode,
727 WINPR_ATTR_UNUSED DWORD dwPipeMode, WINPR_ATTR_UNUSED DWORD nMaxInstances,
728 WINPR_ATTR_UNUSED DWORD nOutBufferSize,
729 WINPR_ATTR_UNUSED DWORD nInBufferSize,
730 WINPR_ATTR_UNUSED DWORD nDefaultTimeOut,
731 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpSecurityAttributes)
732{
733 WLog_ERR(TAG, "is not implemented");
734 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
735 return NULL;
736}
737
738BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped)
739{
740 int status = 0;
741 socklen_t length = 0;
742 WINPR_NAMED_PIPE* pNamedPipe = NULL;
743
744 if (lpOverlapped)
745 {
746 WLog_ERR(TAG, "WinPR does not support the lpOverlapped parameter");
747 SetLastError(ERROR_NOT_SUPPORTED);
748 return FALSE;
749 }
750
751 if (!hNamedPipe)
752 return FALSE;
753
754 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
755
756 if (!(pNamedPipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
757 {
758 struct sockaddr_un s = { 0 };
759 length = sizeof(struct sockaddr_un);
760 status = accept(pNamedPipe->serverfd, (struct sockaddr*)&s, &length);
761
762 if (status < 0)
763 {
764 WLog_ERR(TAG, "ConnectNamedPipe: accept error");
765 return FALSE;
766 }
767
768 pNamedPipe->clientfd = status;
769 pNamedPipe->ServerMode = FALSE;
770 }
771 else
772 {
773 if (!lpOverlapped)
774 return FALSE;
775
776 if (pNamedPipe->serverfd == -1)
777 return FALSE;
778
779 pNamedPipe->lpOverlapped = lpOverlapped;
780 /* synchronous behavior */
781 lpOverlapped->Internal = 2;
782 lpOverlapped->InternalHigh = (ULONG_PTR)0;
783 lpOverlapped->DUMMYUNIONNAME.Pointer = (PVOID)NULL;
784 (void)SetEvent(lpOverlapped->hEvent);
785 }
786
787 return TRUE;
788}
789
790BOOL DisconnectNamedPipe(HANDLE hNamedPipe)
791{
792 WINPR_NAMED_PIPE* pNamedPipe = NULL;
793 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
794
795 if (pNamedPipe->clientfd != -1)
796 {
797 close(pNamedPipe->clientfd);
798 pNamedPipe->clientfd = -1;
799 }
800
801 return TRUE;
802}
803
804BOOL PeekNamedPipe(WINPR_ATTR_UNUSED HANDLE hNamedPipe, WINPR_ATTR_UNUSED LPVOID lpBuffer,
805 WINPR_ATTR_UNUSED DWORD nBufferSize, WINPR_ATTR_UNUSED LPDWORD lpBytesRead,
806 WINPR_ATTR_UNUSED LPDWORD lpTotalBytesAvail,
807 WINPR_ATTR_UNUSED LPDWORD lpBytesLeftThisMessage)
808{
809 WLog_ERR(TAG, "Not implemented");
810 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
811 return FALSE;
812}
813
814BOOL TransactNamedPipe(WINPR_ATTR_UNUSED HANDLE hNamedPipe, WINPR_ATTR_UNUSED LPVOID lpInBuffer,
815 WINPR_ATTR_UNUSED DWORD nInBufferSize, WINPR_ATTR_UNUSED LPVOID lpOutBuffer,
816 WINPR_ATTR_UNUSED DWORD nOutBufferSize,
817 WINPR_ATTR_UNUSED LPDWORD lpBytesRead,
818 WINPR_ATTR_UNUSED LPOVERLAPPED lpOverlapped)
819{
820 WLog_ERR(TAG, "Not implemented");
821 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
822 return FALSE;
823}
824
825BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut)
826{
827 BOOL status = 0;
828 DWORD nWaitTime = 0;
829 char* lpFilePath = NULL;
830 DWORD dwSleepInterval = 0;
831
832 if (!lpNamedPipeName)
833 return FALSE;
834
835 lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpNamedPipeName);
836
837 if (!lpFilePath)
838 return FALSE;
839
840 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
841 nTimeOut = 50;
842
843 nWaitTime = 0;
844 status = TRUE;
845 dwSleepInterval = 10;
846
847 while (!winpr_PathFileExists(lpFilePath))
848 {
849 Sleep(dwSleepInterval);
850 nWaitTime += dwSleepInterval;
851
852 if (nWaitTime >= nTimeOut)
853 {
854 status = FALSE;
855 break;
856 }
857 }
858
859 free(lpFilePath);
860 return status;
861}
862
863BOOL WaitNamedPipeW(WINPR_ATTR_UNUSED LPCWSTR lpNamedPipeName, WINPR_ATTR_UNUSED DWORD nTimeOut)
864{
865 WLog_ERR(TAG, "Not implemented");
866 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
867 return FALSE;
868}
869
870// NOLINTBEGIN(readability-non-const-parameter)
871BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount,
872 LPDWORD lpCollectDataTimeout)
873// NOLINTEND(readability-non-const-parameter)
874{
875 int fd = 0;
876 int flags = 0;
877 WINPR_NAMED_PIPE* pNamedPipe = NULL;
878 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
879
880 if (lpMode)
881 {
882 pNamedPipe->dwPipeMode = *lpMode;
883 fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
884
885 if (fd == -1)
886 return FALSE;
887
888 flags = fcntl(fd, F_GETFL);
889
890 if (flags < 0)
891 return FALSE;
892
893 if (pNamedPipe->dwPipeMode & PIPE_NOWAIT)
894 flags = (flags | O_NONBLOCK);
895 else
896 flags = (flags & ~(O_NONBLOCK));
897
898 if (fcntl(fd, F_SETFL, flags) < 0)
899 return FALSE;
900 }
901
902 if (lpMaxCollectionCount)
903 {
904 }
905
906 if (lpCollectDataTimeout)
907 {
908 }
909
910 return TRUE;
911}
912
913BOOL ImpersonateNamedPipeClient(WINPR_ATTR_UNUSED HANDLE hNamedPipe)
914{
915 WLog_ERR(TAG, "Not implemented");
916 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
917 return FALSE;
918}
919
920BOOL GetNamedPipeClientComputerNameA(WINPR_ATTR_UNUSED HANDLE Pipe,
921 WINPR_ATTR_UNUSED LPCSTR ClientComputerName,
922 WINPR_ATTR_UNUSED ULONG ClientComputerNameLength)
923{
924 WLog_ERR(TAG, "Not implemented");
925 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
926 return FALSE;
927}
928
929BOOL GetNamedPipeClientComputerNameW(WINPR_ATTR_UNUSED HANDLE Pipe,
930 WINPR_ATTR_UNUSED LPCWSTR ClientComputerName,
931 WINPR_ATTR_UNUSED ULONG ClientComputerNameLength)
932{
933 WLog_ERR(TAG, "Not implemented");
934 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
935 return FALSE;
936}
937
938#endif