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