22 #include <winpr/config.h>
24 #include <winpr/crt.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")
71 static wArrayList* g_NamedPipeServerSockets = NULL;
78 } NamedPipeServerSocketEntry;
80 static BOOL PipeIsHandled(HANDLE handle)
82 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_ANONYMOUS_PIPE, FALSE);
85 static int PipeGetFd(HANDLE handle)
87 WINPR_PIPE* pipe = (WINPR_PIPE*)handle;
89 if (!PipeIsHandled(handle))
95 static BOOL PipeCloseHandle(HANDLE handle)
97 WINPR_PIPE* pipe = (WINPR_PIPE*)handle;
99 if (!PipeIsHandled(handle))
112 static 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;
153 static 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;
203 static BOOL NamedPipeIsHandled(HANDLE handle)
205 return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_NAMED_PIPE, TRUE);
208 static 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;
221 static 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);
250 BOOL 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->Pointer = (PVOID)lpBuffer;
336 (void)SetEvent(lpOverlapped->hEvent);
343 BOOL 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->Pointer = cnv.pv;
431 (void)SetEvent(lpOverlapped->hEvent);
438 static HANDLE_OPS namedOps = { NamedPipeIsHandled,
439 NamedPipeCloseHandle,
460 static BOOL InitWinPRPipeModule(
void)
462 if (g_NamedPipeServerSockets)
465 g_NamedPipeServerSockets = ArrayList_New(FALSE);
466 return g_NamedPipeServerSockets != NULL;
473 BOOL 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;
517 static 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);
557 HANDLE 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 int flags = fcntl(pNamedPipe->serverfd, F_GETFL);
713 fcntl(pNamedPipe->serverfd, F_SETFL, flags | O_NONBLOCK);
719 ArrayList_Unlock(g_NamedPipeServerSockets);
722 NamedPipeCloseHandle(pNamedPipe);
727 ArrayList_Unlock(g_NamedPipeServerSockets);
728 return INVALID_HANDLE_VALUE;
731 HANDLE CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
732 DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut,
733 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
735 WLog_ERR(TAG,
"is not implemented");
736 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
740 BOOL 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->Pointer = (PVOID)NULL;
786 (void)SetEvent(lpOverlapped->hEvent);
792 BOOL 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;
806 BOOL PeekNamedPipe(HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, LPDWORD lpBytesRead,
807 LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage)
809 WLog_ERR(TAG,
"Not implemented");
810 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
814 BOOL TransactNamedPipe(HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize,
815 LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead,
818 WLog_ERR(TAG,
"Not implemented");
819 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
823 BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut)
827 char* lpFilePath = NULL;
828 DWORD dwSleepInterval = 0;
830 if (!lpNamedPipeName)
833 lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpNamedPipeName);
838 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
843 dwSleepInterval = 10;
845 while (!winpr_PathFileExists(lpFilePath))
847 Sleep(dwSleepInterval);
848 nWaitTime += dwSleepInterval;
850 if (nWaitTime >= nTimeOut)
861 BOOL WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut)
863 WLog_ERR(TAG,
"Not implemented");
864 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
869 BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount,
870 LPDWORD lpCollectDataTimeout)
875 WINPR_NAMED_PIPE* pNamedPipe = NULL;
876 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
880 pNamedPipe->dwPipeMode = *lpMode;
881 fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
886 flags = fcntl(fd, F_GETFL);
891 if (pNamedPipe->dwPipeMode & PIPE_NOWAIT)
892 flags = (flags | O_NONBLOCK);
894 flags = (flags & ~(O_NONBLOCK));
896 if (fcntl(fd, F_SETFL, flags) < 0)
900 if (lpMaxCollectionCount)
904 if (lpCollectDataTimeout)
911 BOOL ImpersonateNamedPipeClient(HANDLE hNamedPipe)
913 WLog_ERR(TAG,
"Not implemented");
914 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
918 BOOL GetNamedPipeClientComputerNameA(HANDLE Pipe, LPCSTR ClientComputerName,
919 ULONG ClientComputerNameLength)
921 WLog_ERR(TAG,
"Not implemented");
922 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
926 BOOL GetNamedPipeClientComputerNameW(HANDLE Pipe, LPCWSTR ClientComputerName,
927 ULONG ClientComputerNameLength)
929 WLog_ERR(TAG,
"Not implemented");
930 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);