22#include <winpr/config.h>
25#include <winpr/path.h>
26#include <winpr/synch.h>
27#include <winpr/handle.h>
29#include <winpr/pipe.h>
31#ifdef WINPR_HAVE_UNISTD_H
37#include "../handle/handle.h"
42#include <sys/socket.h>
43#include <winpr/assert.h>
45#ifdef WINPR_HAVE_SYS_AIO_H
46#undef WINPR_HAVE_SYS_AIO_H
49#ifdef WINPR_HAVE_SYS_AIO_H
56#define TAG WINPR_TAG("pipe")
71static wArrayList* g_NamedPipeServerSockets = NULL;
78} NamedPipeServerSocketEntry;
80static BOOL PipeIsHandled(HANDLE handle)
82 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_ANONYMOUS_PIPE, FALSE);
85static int PipeGetFd(HANDLE handle)
87 WINPR_PIPE* pipe = (WINPR_PIPE*)handle;
89 if (!PipeIsHandled(handle))
95static BOOL PipeCloseHandle(HANDLE handle)
97 WINPR_PIPE* pipe = (WINPR_PIPE*)handle;
99 if (!PipeIsHandled(handle))
112static BOOL PipeRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
115 SSIZE_T io_status = 0;
116 WINPR_PIPE* pipe = NULL;
121 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
122 SetLastError(ERROR_NOT_SUPPORTED);
126 pipe = (WINPR_PIPE*)Object;
130 io_status = read(pipe->fd, lpBuffer, nNumberOfBytesToRead);
131 }
while ((io_status < 0) && (errno == EINTR));
140 SetLastError(ERROR_NO_DATA);
147 if (lpNumberOfBytesRead)
148 *lpNumberOfBytesRead = (DWORD)io_status;
153static BOOL PipeWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
154 LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
156 SSIZE_T io_status = 0;
157 WINPR_PIPE* pipe = NULL;
161 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
162 SetLastError(ERROR_NOT_SUPPORTED);
166 pipe = (WINPR_PIPE*)Object;
170 io_status = write(pipe->fd, lpBuffer, nNumberOfBytesToWrite);
171 }
while ((io_status < 0) && (errno == EINTR));
173 if ((io_status < 0) && (errno == EWOULDBLOCK))
176 *lpNumberOfBytesWritten = (DWORD)io_status;
203static BOOL NamedPipeIsHandled(HANDLE handle)
205 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_NAMED_PIPE, TRUE);
208static int NamedPipeGetFd(HANDLE handle)
210 WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*)handle;
212 if (!NamedPipeIsHandled(handle))
215 if (pipe->ServerMode)
216 return pipe->serverfd;
218 return pipe->clientfd;
221static BOOL NamedPipeCloseHandle(HANDLE handle)
223 WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)handle;
228#ifndef __clang_analyzer__
229 if (!NamedPipeIsHandled(handle))
233 if (pNamedPipe->pfnUnrefNamedPipe)
234 pNamedPipe->pfnUnrefNamedPipe(pNamedPipe);
236 free(pNamedPipe->name);
237 free(pNamedPipe->lpFileName);
238 free(pNamedPipe->lpFilePath);
240 if (pNamedPipe->serverfd != -1)
241 close(pNamedPipe->serverfd);
243 if (pNamedPipe->clientfd != -1)
244 close(pNamedPipe->clientfd);
250BOOL NamedPipeRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
253 SSIZE_T io_status = 0;
256 WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*)Object;
258 if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
260 if (pipe->clientfd == -1)
265 io_status = read(pipe->clientfd, lpBuffer, nNumberOfBytesToRead);
266 }
while ((io_status < 0) && (errno == EINTR));
270 SetLastError(ERROR_BROKEN_PIPE);
273 else if (io_status < 0)
280 SetLastError(ERROR_NO_DATA);
284 SetLastError(ERROR_BROKEN_PIPE);
289 if (lpNumberOfBytesRead)
290 *lpNumberOfBytesRead = (DWORD)io_status;
297 WLog_ERR(TAG,
"%s requires lpOverlapped != NULL as FILE_FLAG_OVERLAPPED is set");
298 SetLastError(ERROR_NOT_SUPPORTED);
302 if (pipe->clientfd == -1)
305 pipe->lpOverlapped = lpOverlapped;
306#ifdef WINPR_HAVE_SYS_AIO_H
309 struct aiocb cb = { 0 };
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);
329 lpOverlapped->Internal = 0;
330 lpOverlapped->InternalHigh = (ULONG_PTR)nNumberOfBytesToRead;
331 lpOverlapped->DUMMYUNIONNAME.Pointer = (PVOID)lpBuffer;
332 (void)SetEvent(lpOverlapped->hEvent);
339BOOL NamedPipeWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
340 LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
342 SSIZE_T io_status = 0;
343 WINPR_NAMED_PIPE* pipe = NULL;
348 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
349 SetLastError(ERROR_NOT_SUPPORTED);
353 pipe = (WINPR_NAMED_PIPE*)Object;
355 if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
357 if (pipe->clientfd == -1)
362 io_status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite);
363 }
while ((io_status < 0) && (errno == EINTR));
367 *lpNumberOfBytesWritten = 0;
381 *lpNumberOfBytesWritten = (DWORD)io_status;
390 if (pipe->clientfd == -1)
393 pipe->lpOverlapped = lpOverlapped;
394#ifdef WINPR_HAVE_SYS_AIO_H
396 struct aiocb cb = { 0 };
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);
416 lpOverlapped->Internal = 1;
417 lpOverlapped->InternalHigh = (ULONG_PTR)nNumberOfBytesToWrite;
425 lpOverlapped->DUMMYUNIONNAME.Pointer = cnv.pv;
427 (void)SetEvent(lpOverlapped->hEvent);
434static HANDLE_OPS namedOps = { NamedPipeIsHandled,
435 NamedPipeCloseHandle,
456static BOOL InitWinPRPipeModule(
void)
458 if (g_NamedPipeServerSockets)
461 g_NamedPipeServerSockets = ArrayList_New(FALSE);
462 return g_NamedPipeServerSockets != NULL;
469BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes,
472 int pipe_fd[] = { -1, -1 };
473 WINPR_PIPE* pReadPipe = NULL;
474 WINPR_PIPE* pWritePipe = NULL;
476 WINPR_UNUSED(lpPipeAttributes);
479 if (pipe(pipe_fd) < 0)
486 WLog_ERR(TAG,
"failed to create pipe");
490 pReadPipe = (WINPR_PIPE*)calloc(1,
sizeof(WINPR_PIPE));
491 pWritePipe = (WINPR_PIPE*)calloc(1,
sizeof(WINPR_PIPE));
493 if (!pReadPipe || !pWritePipe)
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;
519static void winpr_unref_named_pipe(WINPR_NAMED_PIPE* pNamedPipe)
521 NamedPipeServerSocketEntry* baseSocket = NULL;
526 WINPR_ASSERT(pNamedPipe->name);
527 WINPR_ASSERT(g_NamedPipeServerSockets);
529 ArrayList_Lock(g_NamedPipeServerSockets);
531 for (
size_t index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
534 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
535 WINPR_ASSERT(baseSocket->name);
537 if (!strcmp(baseSocket->name, pNamedPipe->name))
539 WINPR_ASSERT(baseSocket->references > 0);
540 WINPR_ASSERT(baseSocket->serverfd != -1);
542 if (--baseSocket->references == 0)
546 ArrayList_Remove(g_NamedPipeServerSockets, baseSocket);
547 close(baseSocket->serverfd);
548 free(baseSocket->name);
556 ArrayList_Unlock(g_NamedPipeServerSockets);
559HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
560 DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut,
561 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
563 char* lpPipePath = NULL;
564 WINPR_NAMED_PIPE* pNamedPipe = NULL;
566 NamedPipeServerSocketEntry* baseSocket = NULL;
568 WINPR_UNUSED(lpSecurityAttributes);
570 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
572 WLog_ERR(TAG,
"WinPR does not support the FILE_FLAG_OVERLAPPED flag");
573 SetLastError(ERROR_NOT_SUPPORTED);
574 return INVALID_HANDLE_VALUE;
578 return INVALID_HANDLE_VALUE;
580 if (!InitWinPRPipeModule())
581 return INVALID_HANDLE_VALUE;
583 pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1,
sizeof(WINPR_NAMED_PIPE));
586 return INVALID_HANDLE_VALUE;
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;
593 if (!(pNamedPipe->name = _strdup(lpName)))
596 if (!(pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName)))
599 if (!(pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName)))
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;
613 for (
size_t index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
616 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
618 if (!strcmp(baseSocket->name, lpName))
620 serverfd = baseSocket->serverfd;
630 struct sockaddr_un s = { 0 };
632 if (!(lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA()))
635 if (!winpr_PathFileExists(lpPipePath))
637 if (!CreateDirectoryA(lpPipePath, 0))
643 UnixChangeFileMode(lpPipePath, 0xFFFF);
648 if (winpr_PathFileExists(pNamedPipe->lpFilePath))
649 winpr_DeleteFile(pNamedPipe->lpFilePath);
651 if ((serverfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
653 char ebuffer[256] = { 0 };
654 WLog_ERR(TAG,
"CreateNamedPipeA: socket error, %s",
655 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
659 s.sun_family = AF_UNIX;
660 (void)sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path),
"%s", pNamedPipe->lpFilePath);
662 if (bind(serverfd, (
struct sockaddr*)&s,
sizeof(
struct sockaddr_un)) == -1)
664 char ebuffer[256] = { 0 };
665 WLog_ERR(TAG,
"CreateNamedPipeA: bind error, %s",
666 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
670 if (listen(serverfd, 2) == -1)
672 char ebuffer[256] = { 0 };
673 WLog_ERR(TAG,
"CreateNamedPipeA: listen error, %s",
674 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
678 UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF);
680 if (!(baseSocket = (NamedPipeServerSocketEntry*)malloc(
sizeof(NamedPipeServerSocketEntry))))
683 if (!(baseSocket->name = _strdup(lpName)))
689 baseSocket->serverfd = serverfd;
690 baseSocket->references = 0;
692 if (!ArrayList_Append(g_NamedPipeServerSockets, baseSocket))
694 free(baseSocket->name);
703 pNamedPipe->serverfd = dup(baseSocket->serverfd);
706 pNamedPipe->pfnUnrefNamedPipe = winpr_unref_named_pipe;
707 baseSocket->references++;
709 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
712 WLog_ERR(TAG,
"TODO: implement this");
716 ArrayList_Unlock(g_NamedPipeServerSockets);
719 NamedPipeCloseHandle(pNamedPipe);
724 ArrayList_Unlock(g_NamedPipeServerSockets);
725 return INVALID_HANDLE_VALUE;
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)
735 WLog_ERR(TAG,
"is not implemented");
736 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
740BOOL ConnectNamedPipe(HANDLE hNamedPipe,
LPOVERLAPPED lpOverlapped)
743 socklen_t length = 0;
744 WINPR_NAMED_PIPE* pNamedPipe = NULL;
748 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
749 SetLastError(ERROR_NOT_SUPPORTED);
756 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
758 if (!(pNamedPipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
760 struct sockaddr_un s = { 0 };
761 length =
sizeof(
struct sockaddr_un);
762 status = accept(pNamedPipe->serverfd, (
struct sockaddr*)&s, &length);
766 WLog_ERR(TAG,
"ConnectNamedPipe: accept error");
770 pNamedPipe->clientfd = status;
771 pNamedPipe->ServerMode = FALSE;
778 if (pNamedPipe->serverfd == -1)
781 pNamedPipe->lpOverlapped = lpOverlapped;
783 lpOverlapped->Internal = 2;
784 lpOverlapped->InternalHigh = (ULONG_PTR)0;
785 lpOverlapped->DUMMYUNIONNAME.Pointer = (PVOID)NULL;
786 (void)SetEvent(lpOverlapped->hEvent);
792BOOL DisconnectNamedPipe(HANDLE hNamedPipe)
794 WINPR_NAMED_PIPE* pNamedPipe = NULL;
795 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
797 if (pNamedPipe->clientfd != -1)
799 close(pNamedPipe->clientfd);
800 pNamedPipe->clientfd = -1;
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)
811 WLog_ERR(TAG,
"Not implemented");
812 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
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,
822 WLog_ERR(TAG,
"Not implemented");
823 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
827BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut)
831 char* lpFilePath = NULL;
832 DWORD dwSleepInterval = 0;
834 if (!lpNamedPipeName)
837 lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpNamedPipeName);
842 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
847 dwSleepInterval = 10;
849 while (!winpr_PathFileExists(lpFilePath))
851 Sleep(dwSleepInterval);
852 nWaitTime += dwSleepInterval;
854 if (nWaitTime >= nTimeOut)
865BOOL WaitNamedPipeW(WINPR_ATTR_UNUSED LPCWSTR lpNamedPipeName, WINPR_ATTR_UNUSED DWORD nTimeOut)
867 WLog_ERR(TAG,
"Not implemented");
868 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
873BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount,
874 LPDWORD lpCollectDataTimeout)
879 WINPR_NAMED_PIPE* pNamedPipe = NULL;
880 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
884 pNamedPipe->dwPipeMode = *lpMode;
885 fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
890 flags = fcntl(fd, F_GETFL);
895 if (pNamedPipe->dwPipeMode & PIPE_NOWAIT)
896 flags = (flags | O_NONBLOCK);
898 flags = (flags & ~(O_NONBLOCK));
900 if (fcntl(fd, F_SETFL, flags) < 0)
904 if (lpMaxCollectionCount)
908 if (lpCollectDataTimeout)
915BOOL ImpersonateNamedPipeClient(WINPR_ATTR_UNUSED HANDLE hNamedPipe)
917 WLog_ERR(TAG,
"Not implemented");
918 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
922BOOL GetNamedPipeClientComputerNameA(WINPR_ATTR_UNUSED HANDLE Pipe,
923 WINPR_ATTR_UNUSED LPCSTR ClientComputerName,
924 WINPR_ATTR_UNUSED ULONG ClientComputerNameLength)
926 WLog_ERR(TAG,
"Not implemented");
927 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
931BOOL GetNamedPipeClientComputerNameW(WINPR_ATTR_UNUSED HANDLE Pipe,
932 WINPR_ATTR_UNUSED LPCWSTR ClientComputerName,
933 WINPR_ATTR_UNUSED ULONG ClientComputerNameLength)
935 WLog_ERR(TAG,
"Not implemented");
936 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);