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 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[] = { -1, -1 };
477 WINPR_PIPE* pReadPipe = NULL;
478 WINPR_PIPE* pWritePipe = NULL;
479
480 WINPR_UNUSED(lpPipeAttributes);
481 WINPR_UNUSED(nSize);
482
483 if (pipe(pipe_fd) < 0)
484 {
485 if (pipe_fd[0] >= 0)
486 close(pipe_fd[0]);
487 if (pipe_fd[1] >= 0)
488 close(pipe_fd[1]);
489
490 WLog_ERR(TAG, "failed to create pipe");
491 return FALSE;
492 }
493
494 pReadPipe = (WINPR_PIPE*)calloc(1, sizeof(WINPR_PIPE));
495 pWritePipe = (WINPR_PIPE*)calloc(1, sizeof(WINPR_PIPE));
496
497 if (!pReadPipe || !pWritePipe)
498 {
499 if (pipe_fd[0] >= 0)
500 close(pipe_fd[0]);
501 if (pipe_fd[1] >= 0)
502 close(pipe_fd[1]);
503 free(pReadPipe);
504 free(pWritePipe);
505 return FALSE;
506 }
507
508 pReadPipe->fd = pipe_fd[0];
509 pWritePipe->fd = pipe_fd[1];
510 WINPR_HANDLE_SET_TYPE_AND_MODE(pReadPipe, HANDLE_TYPE_ANONYMOUS_PIPE, WINPR_FD_READ);
511 pReadPipe->common.ops = &ops;
512 *((ULONG_PTR*)hReadPipe) = (ULONG_PTR)pReadPipe;
513 WINPR_HANDLE_SET_TYPE_AND_MODE(pWritePipe, HANDLE_TYPE_ANONYMOUS_PIPE, WINPR_FD_READ);
514 pWritePipe->common.ops = &ops;
515 *((ULONG_PTR*)hWritePipe) = (ULONG_PTR)pWritePipe;
516 return TRUE;
517}
518
523static void winpr_unref_named_pipe(WINPR_NAMED_PIPE* pNamedPipe)
524{
525 NamedPipeServerSocketEntry* baseSocket = NULL;
526
527 if (!pNamedPipe)
528 return;
529
530 WINPR_ASSERT(pNamedPipe->name);
531 WINPR_ASSERT(g_NamedPipeServerSockets);
532 // WLog_VRB(TAG, "%p (%s)", (void*) pNamedPipe, pNamedPipe->name);
533 ArrayList_Lock(g_NamedPipeServerSockets);
534
535 for (size_t index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
536 {
537 baseSocket =
538 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
539 WINPR_ASSERT(baseSocket->name);
540
541 if (!strcmp(baseSocket->name, pNamedPipe->name))
542 {
543 WINPR_ASSERT(baseSocket->references > 0);
544 WINPR_ASSERT(baseSocket->serverfd != -1);
545
546 if (--baseSocket->references == 0)
547 {
548 // WLog_DBG(TAG, "removing shared server socked resource");
549 // WLog_DBG(TAG, "closing shared serverfd %d", baseSocket->serverfd);
550 ArrayList_Remove(g_NamedPipeServerSockets, baseSocket);
551 close(baseSocket->serverfd);
552 free(baseSocket->name);
553 free(baseSocket);
554 }
555
556 break;
557 }
558 }
559
560 ArrayList_Unlock(g_NamedPipeServerSockets);
561}
562
563HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
564 DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut,
565 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
566{
567 char* lpPipePath = NULL;
568 WINPR_NAMED_PIPE* pNamedPipe = NULL;
569 int serverfd = -1;
570 NamedPipeServerSocketEntry* baseSocket = NULL;
571
572 WINPR_UNUSED(lpSecurityAttributes);
573
574 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
575 {
576 WLog_ERR(TAG, "WinPR does not support the FILE_FLAG_OVERLAPPED flag");
577 SetLastError(ERROR_NOT_SUPPORTED);
578 return INVALID_HANDLE_VALUE;
579 }
580
581 if (!lpName)
582 return INVALID_HANDLE_VALUE;
583
584 if (!InitWinPRPipeModule())
585 return INVALID_HANDLE_VALUE;
586
587 pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1, sizeof(WINPR_NAMED_PIPE));
588
589 if (!pNamedPipe)
590 return INVALID_HANDLE_VALUE;
591
592 ArrayList_Lock(g_NamedPipeServerSockets);
593 WINPR_HANDLE_SET_TYPE_AND_MODE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE, WINPR_FD_READ);
594 pNamedPipe->serverfd = -1;
595 pNamedPipe->clientfd = -1;
596
597 if (!(pNamedPipe->name = _strdup(lpName)))
598 goto out;
599
600 if (!(pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName)))
601 goto out;
602
603 if (!(pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName)))
604 goto out;
605
606 pNamedPipe->dwOpenMode = dwOpenMode;
607 pNamedPipe->dwPipeMode = dwPipeMode;
608 pNamedPipe->nMaxInstances = nMaxInstances;
609 pNamedPipe->nOutBufferSize = nOutBufferSize;
610 pNamedPipe->nInBufferSize = nInBufferSize;
611 pNamedPipe->nDefaultTimeOut = nDefaultTimeOut;
612 pNamedPipe->dwFlagsAndAttributes = dwOpenMode;
613 pNamedPipe->clientfd = -1;
614 pNamedPipe->ServerMode = TRUE;
615 pNamedPipe->common.ops = &namedOps;
616
617 for (size_t index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
618 {
619 baseSocket =
620 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
621
622 if (!strcmp(baseSocket->name, lpName))
623 {
624 serverfd = baseSocket->serverfd;
625 // WLog_DBG(TAG, "using shared socked resource for pipe %p (%s)", (void*) pNamedPipe,
626 // lpName);
627 break;
628 }
629 }
630
631 /* If this is the first instance of the named pipe... */
632 if (serverfd == -1)
633 {
634 struct sockaddr_un s = { 0 };
635 /* Create the UNIX domain socket and start listening. */
636 if (!(lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA()))
637 goto out;
638
639 if (!winpr_PathFileExists(lpPipePath))
640 {
641 if (!CreateDirectoryA(lpPipePath, 0))
642 {
643 free(lpPipePath);
644 goto out;
645 }
646
647 UnixChangeFileMode(lpPipePath, 0xFFFF);
648 }
649
650 free(lpPipePath);
651
652 if (winpr_PathFileExists(pNamedPipe->lpFilePath))
653 winpr_DeleteFile(pNamedPipe->lpFilePath);
654
655 if ((serverfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
656 {
657 char ebuffer[256] = { 0 };
658 WLog_ERR(TAG, "CreateNamedPipeA: socket error, %s",
659 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
660 goto out;
661 }
662
663 s.sun_family = AF_UNIX;
664 (void)sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path), "%s", pNamedPipe->lpFilePath);
665
666 if (bind(serverfd, (struct sockaddr*)&s, sizeof(struct sockaddr_un)) == -1)
667 {
668 char ebuffer[256] = { 0 };
669 WLog_ERR(TAG, "CreateNamedPipeA: bind error, %s",
670 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
671 goto out;
672 }
673
674 if (listen(serverfd, 2) == -1)
675 {
676 char ebuffer[256] = { 0 };
677 WLog_ERR(TAG, "CreateNamedPipeA: listen error, %s",
678 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
679 goto out;
680 }
681
682 UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF);
683
684 if (!(baseSocket = (NamedPipeServerSocketEntry*)malloc(sizeof(NamedPipeServerSocketEntry))))
685 goto out;
686
687 if (!(baseSocket->name = _strdup(lpName)))
688 {
689 free(baseSocket);
690 goto out;
691 }
692
693 baseSocket->serverfd = serverfd;
694 baseSocket->references = 0;
695
696 if (!ArrayList_Append(g_NamedPipeServerSockets, baseSocket))
697 {
698 free(baseSocket->name);
699 free(baseSocket);
700 goto out;
701 }
702
703 // WLog_DBG(TAG, "created shared socked resource for pipe %p (%s). base serverfd = %d",
704 // (void*) pNamedPipe, lpName, serverfd);
705 }
706
707 pNamedPipe->serverfd = dup(baseSocket->serverfd);
708 // WLog_DBG(TAG, "using serverfd %d (duplicated from %d)", pNamedPipe->serverfd,
709 // baseSocket->serverfd);
710 pNamedPipe->pfnUnrefNamedPipe = winpr_unref_named_pipe;
711 baseSocket->references++;
712
713 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
714 {
715 // TODO: Implement
716 WLog_ERR(TAG, "TODO: implement this");
717 }
718
719 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ArrayList_Append takes ownership of baseSocket
720 ArrayList_Unlock(g_NamedPipeServerSockets);
721 return pNamedPipe;
722out:
723 NamedPipeCloseHandle(pNamedPipe);
724
725 if (serverfd != -1)
726 close(serverfd);
727
728 ArrayList_Unlock(g_NamedPipeServerSockets);
729 return INVALID_HANDLE_VALUE;
730}
731
732HANDLE CreateNamedPipeW(WINPR_ATTR_UNUSED LPCWSTR lpName, WINPR_ATTR_UNUSED DWORD dwOpenMode,
733 WINPR_ATTR_UNUSED DWORD dwPipeMode, WINPR_ATTR_UNUSED DWORD nMaxInstances,
734 WINPR_ATTR_UNUSED DWORD nOutBufferSize,
735 WINPR_ATTR_UNUSED DWORD nInBufferSize,
736 WINPR_ATTR_UNUSED DWORD nDefaultTimeOut,
737 WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpSecurityAttributes)
738{
739 WLog_ERR(TAG, "is not implemented");
740 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
741 return NULL;
742}
743
744BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped)
745{
746 int status = 0;
747 socklen_t length = 0;
748 WINPR_NAMED_PIPE* pNamedPipe = NULL;
749
750 if (lpOverlapped)
751 {
752 WLog_ERR(TAG, "WinPR does not support the lpOverlapped parameter");
753 SetLastError(ERROR_NOT_SUPPORTED);
754 return FALSE;
755 }
756
757 if (!hNamedPipe)
758 return FALSE;
759
760 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
761
762 if (!(pNamedPipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
763 {
764 struct sockaddr_un s = { 0 };
765 length = sizeof(struct sockaddr_un);
766 status = accept(pNamedPipe->serverfd, (struct sockaddr*)&s, &length);
767
768 if (status < 0)
769 {
770 WLog_ERR(TAG, "ConnectNamedPipe: accept error");
771 return FALSE;
772 }
773
774 pNamedPipe->clientfd = status;
775 pNamedPipe->ServerMode = FALSE;
776 }
777 else
778 {
779 if (!lpOverlapped)
780 return FALSE;
781
782 if (pNamedPipe->serverfd == -1)
783 return FALSE;
784
785 pNamedPipe->lpOverlapped = lpOverlapped;
786 /* synchronous behavior */
787 lpOverlapped->Internal = 2;
788 lpOverlapped->InternalHigh = (ULONG_PTR)0;
789 lpOverlapped->DUMMYUNIONNAME.Pointer = (PVOID)NULL;
790 (void)SetEvent(lpOverlapped->hEvent);
791 }
792
793 return TRUE;
794}
795
796BOOL DisconnectNamedPipe(HANDLE hNamedPipe)
797{
798 WINPR_NAMED_PIPE* pNamedPipe = NULL;
799 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
800
801 if (pNamedPipe->clientfd != -1)
802 {
803 close(pNamedPipe->clientfd);
804 pNamedPipe->clientfd = -1;
805 }
806
807 return TRUE;
808}
809
810BOOL PeekNamedPipe(WINPR_ATTR_UNUSED HANDLE hNamedPipe, WINPR_ATTR_UNUSED LPVOID lpBuffer,
811 WINPR_ATTR_UNUSED DWORD nBufferSize, WINPR_ATTR_UNUSED LPDWORD lpBytesRead,
812 WINPR_ATTR_UNUSED LPDWORD lpTotalBytesAvail,
813 WINPR_ATTR_UNUSED LPDWORD lpBytesLeftThisMessage)
814{
815 WLog_ERR(TAG, "Not implemented");
816 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
817 return FALSE;
818}
819
820BOOL TransactNamedPipe(WINPR_ATTR_UNUSED HANDLE hNamedPipe, WINPR_ATTR_UNUSED LPVOID lpInBuffer,
821 WINPR_ATTR_UNUSED DWORD nInBufferSize, WINPR_ATTR_UNUSED LPVOID lpOutBuffer,
822 WINPR_ATTR_UNUSED DWORD nOutBufferSize,
823 WINPR_ATTR_UNUSED LPDWORD lpBytesRead,
824 WINPR_ATTR_UNUSED LPOVERLAPPED lpOverlapped)
825{
826 WLog_ERR(TAG, "Not implemented");
827 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
828 return FALSE;
829}
830
831BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut)
832{
833 BOOL status = 0;
834 DWORD nWaitTime = 0;
835 char* lpFilePath = NULL;
836 DWORD dwSleepInterval = 0;
837
838 if (!lpNamedPipeName)
839 return FALSE;
840
841 lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpNamedPipeName);
842
843 if (!lpFilePath)
844 return FALSE;
845
846 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
847 nTimeOut = 50;
848
849 nWaitTime = 0;
850 status = TRUE;
851 dwSleepInterval = 10;
852
853 while (!winpr_PathFileExists(lpFilePath))
854 {
855 Sleep(dwSleepInterval);
856 nWaitTime += dwSleepInterval;
857
858 if (nWaitTime >= nTimeOut)
859 {
860 status = FALSE;
861 break;
862 }
863 }
864
865 free(lpFilePath);
866 return status;
867}
868
869BOOL WaitNamedPipeW(WINPR_ATTR_UNUSED LPCWSTR lpNamedPipeName, WINPR_ATTR_UNUSED DWORD nTimeOut)
870{
871 WLog_ERR(TAG, "Not implemented");
872 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
873 return FALSE;
874}
875
876// NOLINTBEGIN(readability-non-const-parameter)
877BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount,
878 LPDWORD lpCollectDataTimeout)
879// NOLINTEND(readability-non-const-parameter)
880{
881 int fd = 0;
882 int flags = 0;
883 WINPR_NAMED_PIPE* pNamedPipe = NULL;
884 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
885
886 if (lpMode)
887 {
888 pNamedPipe->dwPipeMode = *lpMode;
889 fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
890
891 if (fd == -1)
892 return FALSE;
893
894 flags = fcntl(fd, F_GETFL);
895
896 if (flags < 0)
897 return FALSE;
898
899 if (pNamedPipe->dwPipeMode & PIPE_NOWAIT)
900 flags = (flags | O_NONBLOCK);
901 else
902 flags = (flags & ~(O_NONBLOCK));
903
904 if (fcntl(fd, F_SETFL, flags) < 0)
905 return FALSE;
906 }
907
908 if (lpMaxCollectionCount)
909 {
910 }
911
912 if (lpCollectDataTimeout)
913 {
914 }
915
916 return TRUE;
917}
918
919BOOL ImpersonateNamedPipeClient(WINPR_ATTR_UNUSED HANDLE hNamedPipe)
920{
921 WLog_ERR(TAG, "Not implemented");
922 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
923 return FALSE;
924}
925
926BOOL GetNamedPipeClientComputerNameA(WINPR_ATTR_UNUSED HANDLE Pipe,
927 WINPR_ATTR_UNUSED LPCSTR ClientComputerName,
928 WINPR_ATTR_UNUSED ULONG ClientComputerNameLength)
929{
930 WLog_ERR(TAG, "Not implemented");
931 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
932 return FALSE;
933}
934
935BOOL GetNamedPipeClientComputerNameW(WINPR_ATTR_UNUSED HANDLE Pipe,
936 WINPR_ATTR_UNUSED LPCWSTR ClientComputerName,
937 WINPR_ATTR_UNUSED ULONG ClientComputerNameLength)
938{
939 WLog_ERR(TAG, "Not implemented");
940 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
941 return FALSE;
942}
943
944#endif