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,
477 WINPR_PIPE* pReadPipe = NULL;
478 WINPR_PIPE* pWritePipe = NULL;
480 WINPR_UNUSED(lpPipeAttributes);
486 if (pipe(pipe_fd) < 0)
488 WLog_ERR(TAG,
"failed to create pipe");
492 pReadPipe = (WINPR_PIPE*)calloc(1,
sizeof(WINPR_PIPE));
493 pWritePipe = (WINPR_PIPE*)calloc(1,
sizeof(WINPR_PIPE));
495 if (!pReadPipe || !pWritePipe)
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;
517static void winpr_unref_named_pipe(WINPR_NAMED_PIPE* pNamedPipe)
519 NamedPipeServerSocketEntry* baseSocket = NULL;
524 WINPR_ASSERT(pNamedPipe->name);
525 WINPR_ASSERT(g_NamedPipeServerSockets);
527 ArrayList_Lock(g_NamedPipeServerSockets);
529 for (
size_t index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
532 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
533 WINPR_ASSERT(baseSocket->name);
535 if (!strcmp(baseSocket->name, pNamedPipe->name))
537 WINPR_ASSERT(baseSocket->references > 0);
538 WINPR_ASSERT(baseSocket->serverfd != -1);
540 if (--baseSocket->references == 0)
544 ArrayList_Remove(g_NamedPipeServerSockets, baseSocket);
545 close(baseSocket->serverfd);
546 free(baseSocket->name);
554 ArrayList_Unlock(g_NamedPipeServerSockets);
557HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
558 DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut,
559 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
561 char* lpPipePath = NULL;
562 WINPR_NAMED_PIPE* pNamedPipe = NULL;
564 NamedPipeServerSocketEntry* baseSocket = NULL;
566 WINPR_UNUSED(lpSecurityAttributes);
568 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
570 WLog_ERR(TAG,
"WinPR does not support the FILE_FLAG_OVERLAPPED flag");
571 SetLastError(ERROR_NOT_SUPPORTED);
572 return INVALID_HANDLE_VALUE;
576 return INVALID_HANDLE_VALUE;
578 if (!InitWinPRPipeModule())
579 return INVALID_HANDLE_VALUE;
581 pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1,
sizeof(WINPR_NAMED_PIPE));
584 return INVALID_HANDLE_VALUE;
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;
591 if (!(pNamedPipe->name = _strdup(lpName)))
594 if (!(pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName)))
597 if (!(pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName)))
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;
611 for (
size_t index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
614 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
616 if (!strcmp(baseSocket->name, lpName))
618 serverfd = baseSocket->serverfd;
628 struct sockaddr_un s = { 0 };
630 if (!(lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA()))
633 if (!winpr_PathFileExists(lpPipePath))
635 if (!CreateDirectoryA(lpPipePath, 0))
641 UnixChangeFileMode(lpPipePath, 0xFFFF);
646 if (winpr_PathFileExists(pNamedPipe->lpFilePath))
647 winpr_DeleteFile(pNamedPipe->lpFilePath);
649 if ((serverfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
651 char ebuffer[256] = { 0 };
652 WLog_ERR(TAG,
"CreateNamedPipeA: socket error, %s",
653 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
657 s.sun_family = AF_UNIX;
658 (void)sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path),
"%s", pNamedPipe->lpFilePath);
660 if (bind(serverfd, (
struct sockaddr*)&s,
sizeof(
struct sockaddr_un)) == -1)
662 char ebuffer[256] = { 0 };
663 WLog_ERR(TAG,
"CreateNamedPipeA: bind error, %s",
664 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
668 if (listen(serverfd, 2) == -1)
670 char ebuffer[256] = { 0 };
671 WLog_ERR(TAG,
"CreateNamedPipeA: listen error, %s",
672 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
676 UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF);
678 if (!(baseSocket = (NamedPipeServerSocketEntry*)malloc(
sizeof(NamedPipeServerSocketEntry))))
681 if (!(baseSocket->name = _strdup(lpName)))
687 baseSocket->serverfd = serverfd;
688 baseSocket->references = 0;
690 if (!ArrayList_Append(g_NamedPipeServerSockets, baseSocket))
692 free(baseSocket->name);
701 pNamedPipe->serverfd = dup(baseSocket->serverfd);
704 pNamedPipe->pfnUnrefNamedPipe = winpr_unref_named_pipe;
705 baseSocket->references++;
707 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
710 WLog_ERR(TAG,
"TODO: implement this");
714 ArrayList_Unlock(g_NamedPipeServerSockets);
717 NamedPipeCloseHandle(pNamedPipe);
722 ArrayList_Unlock(g_NamedPipeServerSockets);
723 return INVALID_HANDLE_VALUE;
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)
733 WLog_ERR(TAG,
"is not implemented");
734 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
738BOOL ConnectNamedPipe(HANDLE hNamedPipe,
LPOVERLAPPED lpOverlapped)
741 socklen_t length = 0;
742 WINPR_NAMED_PIPE* pNamedPipe = NULL;
746 WLog_ERR(TAG,
"WinPR does not support the lpOverlapped parameter");
747 SetLastError(ERROR_NOT_SUPPORTED);
754 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
756 if (!(pNamedPipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
758 struct sockaddr_un s = { 0 };
759 length =
sizeof(
struct sockaddr_un);
760 status = accept(pNamedPipe->serverfd, (
struct sockaddr*)&s, &length);
764 WLog_ERR(TAG,
"ConnectNamedPipe: accept error");
768 pNamedPipe->clientfd = status;
769 pNamedPipe->ServerMode = FALSE;
776 if (pNamedPipe->serverfd == -1)
779 pNamedPipe->lpOverlapped = lpOverlapped;
781 lpOverlapped->Internal = 2;
782 lpOverlapped->InternalHigh = (ULONG_PTR)0;
783 lpOverlapped->DUMMYUNIONNAME.Pointer = (PVOID)NULL;
784 (void)SetEvent(lpOverlapped->hEvent);
790BOOL DisconnectNamedPipe(HANDLE hNamedPipe)
792 WINPR_NAMED_PIPE* pNamedPipe = NULL;
793 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
795 if (pNamedPipe->clientfd != -1)
797 close(pNamedPipe->clientfd);
798 pNamedPipe->clientfd = -1;
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)
809 WLog_ERR(TAG,
"Not implemented");
810 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
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,
820 WLog_ERR(TAG,
"Not implemented");
821 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
825BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut)
829 char* lpFilePath = NULL;
830 DWORD dwSleepInterval = 0;
832 if (!lpNamedPipeName)
835 lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpNamedPipeName);
840 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
845 dwSleepInterval = 10;
847 while (!winpr_PathFileExists(lpFilePath))
849 Sleep(dwSleepInterval);
850 nWaitTime += dwSleepInterval;
852 if (nWaitTime >= nTimeOut)
863BOOL WaitNamedPipeW(WINPR_ATTR_UNUSED LPCWSTR lpNamedPipeName, WINPR_ATTR_UNUSED DWORD nTimeOut)
865 WLog_ERR(TAG,
"Not implemented");
866 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
871BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount,
872 LPDWORD lpCollectDataTimeout)
877 WINPR_NAMED_PIPE* pNamedPipe = NULL;
878 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
882 pNamedPipe->dwPipeMode = *lpMode;
883 fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
888 flags = fcntl(fd, F_GETFL);
893 if (pNamedPipe->dwPipeMode & PIPE_NOWAIT)
894 flags = (flags | O_NONBLOCK);
896 flags = (flags & ~(O_NONBLOCK));
898 if (fcntl(fd, F_SETFL, flags) < 0)
902 if (lpMaxCollectionCount)
906 if (lpCollectDataTimeout)
913BOOL ImpersonateNamedPipeClient(WINPR_ATTR_UNUSED HANDLE hNamedPipe)
915 WLog_ERR(TAG,
"Not implemented");
916 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
920BOOL GetNamedPipeClientComputerNameA(WINPR_ATTR_UNUSED HANDLE Pipe,
921 WINPR_ATTR_UNUSED LPCSTR ClientComputerName,
922 WINPR_ATTR_UNUSED ULONG ClientComputerNameLength)
924 WLog_ERR(TAG,
"Not implemented");
925 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
929BOOL GetNamedPipeClientComputerNameW(WINPR_ATTR_UNUSED HANDLE Pipe,
930 WINPR_ATTR_UNUSED LPCWSTR ClientComputerName,
931 WINPR_ATTR_UNUSED ULONG ClientComputerNameLength)
933 WLog_ERR(TAG,
"Not implemented");
934 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);