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;
254 WINPR_NAMED_PIPE* pipe = NULL;
259 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
260 SetLastError(ERROR_NOT_SUPPORTED);
264 pipe = (WINPR_NAMED_PIPE*)Object;
266 if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
268 if (pipe->clientfd == -1)
273 io_status = read(pipe->clientfd, lpBuffer, nNumberOfBytesToRead);
274 }
while ((io_status < 0) && (errno == EINTR));
278 SetLastError(ERROR_BROKEN_PIPE);
281 else if (io_status < 0)
288 SetLastError(ERROR_NO_DATA);
292 SetLastError(ERROR_BROKEN_PIPE);
297 if (lpNumberOfBytesRead)
298 *lpNumberOfBytesRead = (DWORD)io_status;
306 if (pipe->clientfd == -1)
309 pipe->lpOverlapped = lpOverlapped;
310#ifdef WINPR_HAVE_SYS_AIO_H
313 struct aiocb cb = { 0 };
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);
333 lpOverlapped->Internal = 0;
334 lpOverlapped->InternalHigh = (ULONG_PTR)nNumberOfBytesToRead;
335 lpOverlapped->DUMMYUNIONNAME.Pointer = (PVOID)lpBuffer;
336 (void)SetEvent(lpOverlapped->hEvent);
343BOOL NamedPipeWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
344 LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
346 SSIZE_T io_status = 0;
347 WINPR_NAMED_PIPE* pipe = NULL;
352 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
353 SetLastError(ERROR_NOT_SUPPORTED);
357 pipe = (WINPR_NAMED_PIPE*)Object;
359 if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
361 if (pipe->clientfd == -1)
366 io_status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite);
367 }
while ((io_status < 0) && (errno == EINTR));
371 *lpNumberOfBytesWritten = 0;
385 *lpNumberOfBytesWritten = (DWORD)io_status;
394 if (pipe->clientfd == -1)
397 pipe->lpOverlapped = lpOverlapped;
398#ifdef WINPR_HAVE_SYS_AIO_H
400 struct aiocb cb = { 0 };
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);
420 lpOverlapped->Internal = 1;
421 lpOverlapped->InternalHigh = (ULONG_PTR)nNumberOfBytesToWrite;
429 lpOverlapped->DUMMYUNIONNAME.Pointer = cnv.pv;
431 (void)SetEvent(lpOverlapped->hEvent);
438static HANDLE_OPS namedOps = { NamedPipeIsHandled,
439 NamedPipeCloseHandle,
460static BOOL InitWinPRPipeModule(
void)
462 if (g_NamedPipeServerSockets)
465 g_NamedPipeServerSockets = ArrayList_New(FALSE);
466 return g_NamedPipeServerSockets != NULL;
473BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes,
476 int pipe_fd[] = { -1, -1 };
477 WINPR_PIPE* pReadPipe = NULL;
478 WINPR_PIPE* pWritePipe = NULL;
480 WINPR_UNUSED(lpPipeAttributes);
483 if (pipe(pipe_fd) < 0)
490 WLog_ERR(TAG,
"failed to create pipe");
494 pReadPipe = (WINPR_PIPE*)calloc(1,
sizeof(WINPR_PIPE));
495 pWritePipe = (WINPR_PIPE*)calloc(1,
sizeof(WINPR_PIPE));
497 if (!pReadPipe || !pWritePipe)
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;
523static void winpr_unref_named_pipe(WINPR_NAMED_PIPE* pNamedPipe)
525 NamedPipeServerSocketEntry* baseSocket = NULL;
530 WINPR_ASSERT(pNamedPipe->name);
531 WINPR_ASSERT(g_NamedPipeServerSockets);
533 ArrayList_Lock(g_NamedPipeServerSockets);
535 for (
size_t index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
538 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
539 WINPR_ASSERT(baseSocket->name);
541 if (!strcmp(baseSocket->name, pNamedPipe->name))
543 WINPR_ASSERT(baseSocket->references > 0);
544 WINPR_ASSERT(baseSocket->serverfd != -1);
546 if (--baseSocket->references == 0)
550 ArrayList_Remove(g_NamedPipeServerSockets, baseSocket);
551 close(baseSocket->serverfd);
552 free(baseSocket->name);
560 ArrayList_Unlock(g_NamedPipeServerSockets);
563HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
564 DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut,
565 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
567 char* lpPipePath = NULL;
568 WINPR_NAMED_PIPE* pNamedPipe = NULL;
570 NamedPipeServerSocketEntry* baseSocket = NULL;
572 WINPR_UNUSED(lpSecurityAttributes);
574 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
576 WLog_ERR(TAG,
"WinPR does not support the FILE_FLAG_OVERLAPPED flag");
577 SetLastError(ERROR_NOT_SUPPORTED);
578 return INVALID_HANDLE_VALUE;
582 return INVALID_HANDLE_VALUE;
584 if (!InitWinPRPipeModule())
585 return INVALID_HANDLE_VALUE;
587 pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1,
sizeof(WINPR_NAMED_PIPE));
590 return INVALID_HANDLE_VALUE;
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;
597 if (!(pNamedPipe->name = _strdup(lpName)))
600 if (!(pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName)))
603 if (!(pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName)))
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;
617 for (
size_t index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
620 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
622 if (!strcmp(baseSocket->name, lpName))
624 serverfd = baseSocket->serverfd;
634 struct sockaddr_un s = { 0 };
636 if (!(lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA()))
639 if (!winpr_PathFileExists(lpPipePath))
641 if (!CreateDirectoryA(lpPipePath, 0))
647 UnixChangeFileMode(lpPipePath, 0xFFFF);
652 if (winpr_PathFileExists(pNamedPipe->lpFilePath))
653 winpr_DeleteFile(pNamedPipe->lpFilePath);
655 if ((serverfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
657 char ebuffer[256] = { 0 };
658 WLog_ERR(TAG,
"CreateNamedPipeA: socket error, %s",
659 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
663 s.sun_family = AF_UNIX;
664 (void)sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path),
"%s", pNamedPipe->lpFilePath);
666 if (bind(serverfd, (
struct sockaddr*)&s,
sizeof(
struct sockaddr_un)) == -1)
668 char ebuffer[256] = { 0 };
669 WLog_ERR(TAG,
"CreateNamedPipeA: bind error, %s",
670 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
674 if (listen(serverfd, 2) == -1)
676 char ebuffer[256] = { 0 };
677 WLog_ERR(TAG,
"CreateNamedPipeA: listen error, %s",
678 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
682 UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF);
684 if (!(baseSocket = (NamedPipeServerSocketEntry*)malloc(
sizeof(NamedPipeServerSocketEntry))))
687 if (!(baseSocket->name = _strdup(lpName)))
693 baseSocket->serverfd = serverfd;
694 baseSocket->references = 0;
696 if (!ArrayList_Append(g_NamedPipeServerSockets, baseSocket))
698 free(baseSocket->name);
707 pNamedPipe->serverfd = dup(baseSocket->serverfd);
710 pNamedPipe->pfnUnrefNamedPipe = winpr_unref_named_pipe;
711 baseSocket->references++;
713 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
716 WLog_ERR(TAG,
"TODO: implement this");
720 ArrayList_Unlock(g_NamedPipeServerSockets);
723 NamedPipeCloseHandle(pNamedPipe);
728 ArrayList_Unlock(g_NamedPipeServerSockets);
729 return INVALID_HANDLE_VALUE;
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)
739 WLog_ERR(TAG,
"is not implemented");
740 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
744BOOL ConnectNamedPipe(HANDLE hNamedPipe,
LPOVERLAPPED lpOverlapped)
747 socklen_t length = 0;
748 WINPR_NAMED_PIPE* pNamedPipe = NULL;
752 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
753 SetLastError(ERROR_NOT_SUPPORTED);
760 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
762 if (!(pNamedPipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
764 struct sockaddr_un s = { 0 };
765 length =
sizeof(
struct sockaddr_un);
766 status = accept(pNamedPipe->serverfd, (
struct sockaddr*)&s, &length);
770 WLog_ERR(TAG,
"ConnectNamedPipe: accept error");
774 pNamedPipe->clientfd = status;
775 pNamedPipe->ServerMode = FALSE;
782 if (pNamedPipe->serverfd == -1)
785 pNamedPipe->lpOverlapped = lpOverlapped;
787 lpOverlapped->Internal = 2;
788 lpOverlapped->InternalHigh = (ULONG_PTR)0;
789 lpOverlapped->DUMMYUNIONNAME.Pointer = (PVOID)NULL;
790 (void)SetEvent(lpOverlapped->hEvent);
796BOOL DisconnectNamedPipe(HANDLE hNamedPipe)
798 WINPR_NAMED_PIPE* pNamedPipe = NULL;
799 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
801 if (pNamedPipe->clientfd != -1)
803 close(pNamedPipe->clientfd);
804 pNamedPipe->clientfd = -1;
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)
815 WLog_ERR(TAG,
"Not implemented");
816 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
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,
826 WLog_ERR(TAG,
"Not implemented");
827 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
831BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut)
835 char* lpFilePath = NULL;
836 DWORD dwSleepInterval = 0;
838 if (!lpNamedPipeName)
841 lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpNamedPipeName);
846 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
851 dwSleepInterval = 10;
853 while (!winpr_PathFileExists(lpFilePath))
855 Sleep(dwSleepInterval);
856 nWaitTime += dwSleepInterval;
858 if (nWaitTime >= nTimeOut)
869BOOL WaitNamedPipeW(WINPR_ATTR_UNUSED LPCWSTR lpNamedPipeName, WINPR_ATTR_UNUSED DWORD nTimeOut)
871 WLog_ERR(TAG,
"Not implemented");
872 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
877BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount,
878 LPDWORD lpCollectDataTimeout)
883 WINPR_NAMED_PIPE* pNamedPipe = NULL;
884 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
888 pNamedPipe->dwPipeMode = *lpMode;
889 fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
894 flags = fcntl(fd, F_GETFL);
899 if (pNamedPipe->dwPipeMode & PIPE_NOWAIT)
900 flags = (flags | O_NONBLOCK);
902 flags = (flags & ~(O_NONBLOCK));
904 if (fcntl(fd, F_SETFL, flags) < 0)
908 if (lpMaxCollectionCount)
912 if (lpCollectDataTimeout)
919BOOL ImpersonateNamedPipeClient(WINPR_ATTR_UNUSED HANDLE hNamedPipe)
921 WLog_ERR(TAG,
"Not implemented");
922 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
926BOOL GetNamedPipeClientComputerNameA(WINPR_ATTR_UNUSED HANDLE Pipe,
927 WINPR_ATTR_UNUSED LPCSTR ClientComputerName,
928 WINPR_ATTR_UNUSED ULONG ClientComputerNameLength)
930 WLog_ERR(TAG,
"Not implemented");
931 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
935BOOL GetNamedPipeClientComputerNameW(WINPR_ATTR_UNUSED HANDLE Pipe,
936 WINPR_ATTR_UNUSED LPCWSTR ClientComputerName,
937 WINPR_ATTR_UNUSED ULONG ClientComputerNameLength)
939 WLog_ERR(TAG,
"Not implemented");
940 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);