1 /**
2 * WinPR: Windows Portable Runtime
3 * Pipe Functions
4 *
5 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
7 * Copyright 2017 Thincast Technologies GmbH
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <winpr/crt.h>
27 #include <winpr/path.h>
28 #include <winpr/synch.h>
29 #include <winpr/handle.h>
30
31 #include <winpr/pipe.h>
32
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36
37 #ifndef _WIN32
38
39 #include "../handle/handle.h"
40
41 #include <fcntl.h>
42 #include <errno.h>
43 #include <sys/un.h>
44 #include <sys/socket.h>
45 #include <assert.h>
46 #include <unistd.h>
47
48 #ifdef HAVE_SYS_AIO_H
49 #undef HAVE_SYS_AIO_H /* disable for now, incomplete */
50 #endif
51
52 #ifdef HAVE_SYS_AIO_H
53 #include <aio.h>
54 #endif
55
56 #include "pipe.h"
57
58 #include "../log.h"
59 #define TAG WINPR_TAG("pipe")
60
61 /*
62 * Since the WinPR implementation of named pipes makes use of UNIX domain
63 * sockets, it is not possible to bind the same name more than once (i.e.,
64 * SO_REUSEADDR does not work with UNIX domain sockets). As a result, the
65 * first call to CreateNamedPipe with name n creates a "shared" UNIX domain
66 * socket descriptor that gets duplicated via dup() for the first and all
67 * subsequent calls to CreateNamedPipe with name n.
68 *
69 * The following array keeps track of the references to the shared socked
70 * descriptors. If an entry's reference count is zero the base socket
71 * descriptor gets closed and the entry is removed from the list.
72 */
73
74 static wArrayList* g_NamedPipeServerSockets = NULL;
75
76 typedef struct _NamedPipeServerSocketEntry
77 {
78 char* name;
79 int serverfd;
80 int references;
81 } NamedPipeServerSocketEntry;
82
PipeIsHandled(HANDLE handle)83 static BOOL PipeIsHandled(HANDLE handle)
84 {
85 WINPR_PIPE* pPipe = (WINPR_PIPE*)handle;
86
87 if (!pPipe || (pPipe->Type != HANDLE_TYPE_ANONYMOUS_PIPE))
88 {
89 SetLastError(ERROR_INVALID_HANDLE);
90 return FALSE;
91 }
92
93 return TRUE;
94 }
95
PipeGetFd(HANDLE handle)96 static int PipeGetFd(HANDLE handle)
97 {
98 WINPR_PIPE* pipe = (WINPR_PIPE*)handle;
99
100 if (!PipeIsHandled(handle))
101 return -1;
102
103 return pipe->fd;
104 }
105
PipeCloseHandle(HANDLE handle)106 static BOOL PipeCloseHandle(HANDLE handle)
107 {
108 WINPR_PIPE* pipe = (WINPR_PIPE*)handle;
109
110 if (!PipeIsHandled(handle))
111 return FALSE;
112
113 if (pipe->fd != -1)
114 {
115 close(pipe->fd);
116 pipe->fd = -1;
117 }
118
119 free(handle);
120 return TRUE;
121 }
122
PipeRead(PVOID Object,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)123 static BOOL PipeRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
124 LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
125 {
126 int io_status;
127 WINPR_PIPE* pipe;
128 BOOL status = TRUE;
129
130 if (lpOverlapped)
131 {
132 WLog_ERR(TAG, "WinPR %s does not support the lpOverlapped parameter", __FUNCTION__);
133 SetLastError(ERROR_NOT_SUPPORTED);
134 return FALSE;
135 }
136
137 pipe = (WINPR_PIPE*)Object;
138
139 do
140 {
141 io_status = read(pipe->fd, lpBuffer, nNumberOfBytesToRead);
142 } while ((io_status < 0) && (errno == EINTR));
143
144 if (io_status < 0)
145 {
146 status = FALSE;
147
148 switch (errno)
149 {
150 case EWOULDBLOCK:
151 SetLastError(ERROR_NO_DATA);
152 break;
153 }
154 }
155
156 if (lpNumberOfBytesRead)
157 *lpNumberOfBytesRead = io_status;
158
159 return status;
160 }
161
PipeWrite(PVOID Object,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped)162 static BOOL PipeWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
163 LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
164 {
165 int io_status;
166 WINPR_PIPE* pipe;
167
168 if (lpOverlapped)
169 {
170 WLog_ERR(TAG, "WinPR %s does not support the lpOverlapped parameter", __FUNCTION__);
171 SetLastError(ERROR_NOT_SUPPORTED);
172 return FALSE;
173 }
174
175 pipe = (WINPR_PIPE*)Object;
176
177 do
178 {
179 io_status = write(pipe->fd, lpBuffer, nNumberOfBytesToWrite);
180 } while ((io_status < 0) && (errno == EINTR));
181
182 if ((io_status < 0) && (errno == EWOULDBLOCK))
183 io_status = 0;
184
185 *lpNumberOfBytesWritten = io_status;
186 return TRUE;
187 }
188
189 static HANDLE_OPS ops = {
190 PipeIsHandled, PipeCloseHandle,
191 PipeGetFd, NULL, /* CleanupHandle */
192 PipeRead, NULL, /* FileReadEx */
193 NULL, /* FileReadScatter */
194 PipeWrite, NULL, /* FileWriteEx */
195 NULL, /* FileWriteGather */
196 NULL, /* FileGetFileSize */
197 NULL, /* FlushFileBuffers */
198 NULL, /* FileSetEndOfFile */
199 NULL, /* FileSetFilePointer */
200 NULL, /* SetFilePointerEx */
201 NULL, /* FileLockFile */
202 NULL, /* FileLockFileEx */
203 NULL, /* FileUnlockFile */
204 NULL, /* FileUnlockFileEx */
205 NULL /* SetFileTime */
206 };
207
NamedPipeIsHandled(HANDLE handle)208 static BOOL NamedPipeIsHandled(HANDLE handle)
209 {
210 WINPR_NAMED_PIPE* pPipe = (WINPR_NAMED_PIPE*)handle;
211
212 if (!pPipe || (pPipe->Type != HANDLE_TYPE_NAMED_PIPE) || (pPipe == INVALID_HANDLE_VALUE))
213 {
214 SetLastError(ERROR_INVALID_HANDLE);
215 return FALSE;
216 }
217
218 return TRUE;
219 }
220
NamedPipeGetFd(HANDLE handle)221 static int NamedPipeGetFd(HANDLE handle)
222 {
223 WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*)handle;
224
225 if (!NamedPipeIsHandled(handle))
226 return -1;
227
228 if (pipe->ServerMode)
229 return pipe->serverfd;
230
231 return pipe->clientfd;
232 }
233
NamedPipeCloseHandle(HANDLE handle)234 static BOOL NamedPipeCloseHandle(HANDLE handle)
235 {
236 WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)handle;
237
238 /* This check confuses the analyzer. Since not all handle
239 * types are handled here, it guesses that the memory of a
240 * NamedPipeHandle may leak. */
241 #ifndef __clang_analyzer__
242 if (!NamedPipeIsHandled(handle))
243 return FALSE;
244 #endif
245
246 if (pNamedPipe->pfnUnrefNamedPipe)
247 pNamedPipe->pfnUnrefNamedPipe(pNamedPipe);
248
249 free(pNamedPipe->name);
250 free(pNamedPipe->lpFileName);
251 free(pNamedPipe->lpFilePath);
252
253 if (pNamedPipe->serverfd != -1)
254 close(pNamedPipe->serverfd);
255
256 if (pNamedPipe->clientfd != -1)
257 close(pNamedPipe->clientfd);
258
259 free(pNamedPipe);
260 return TRUE;
261 }
262
NamedPipeRead(PVOID Object,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)263 BOOL NamedPipeRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
264 LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
265 {
266 int io_status;
267 WINPR_NAMED_PIPE* pipe;
268 BOOL status = TRUE;
269
270 if (lpOverlapped)
271 {
272 WLog_ERR(TAG, "WinPR %s does not support the lpOverlapped parameter", __FUNCTION__);
273 SetLastError(ERROR_NOT_SUPPORTED);
274 return FALSE;
275 }
276
277 pipe = (WINPR_NAMED_PIPE*)Object;
278
279 if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
280 {
281 if (pipe->clientfd == -1)
282 return FALSE;
283
284 do
285 {
286 io_status = read(pipe->clientfd, lpBuffer, nNumberOfBytesToRead);
287 } while ((io_status < 0) && (errno == EINTR));
288
289 if (io_status == 0)
290 {
291 SetLastError(ERROR_BROKEN_PIPE);
292 status = FALSE;
293 }
294 else if (io_status < 0)
295 {
296 status = FALSE;
297
298 switch (errno)
299 {
300 case EWOULDBLOCK:
301 SetLastError(ERROR_NO_DATA);
302 break;
303
304 default:
305 SetLastError(ERROR_BROKEN_PIPE);
306 break;
307 }
308 }
309
310 if (lpNumberOfBytesRead)
311 *lpNumberOfBytesRead = io_status;
312 }
313 else
314 {
315 /* Overlapped I/O */
316 if (!lpOverlapped)
317 return FALSE;
318
319 if (pipe->clientfd == -1)
320 return FALSE;
321
322 pipe->lpOverlapped = lpOverlapped;
323 #ifdef HAVE_SYS_AIO_H
324 {
325 int aio_status;
326 struct aiocb cb;
327 ZeroMemory(&cb, sizeof(struct aiocb));
328 cb.aio_fildes = pipe->clientfd;
329 cb.aio_buf = lpBuffer;
330 cb.aio_nbytes = nNumberOfBytesToRead;
331 cb.aio_offset = lpOverlapped->Offset;
332 cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
333 cb.aio_sigevent.sigev_signo = SIGIO;
334 cb.aio_sigevent.sigev_value.sival_ptr = (void*)lpOverlapped;
335 InstallAioSignalHandler();
336 aio_status = aio_read(&cb);
337 WLog_DBG(TAG, "aio_read status: %d", aio_status);
338
339 if (aio_status < 0)
340 status = FALSE;
341
342 return status;
343 }
344 #else
345 /* synchronous behavior */
346 lpOverlapped->Internal = 0;
347 lpOverlapped->InternalHigh = (ULONG_PTR)nNumberOfBytesToRead;
348 lpOverlapped->Pointer = (PVOID)lpBuffer;
349 SetEvent(lpOverlapped->hEvent);
350 #endif
351 }
352
353 return status;
354 }
355
NamedPipeWrite(PVOID Object,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped)356 BOOL NamedPipeWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
357 LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
358 {
359 int io_status;
360 WINPR_NAMED_PIPE* pipe;
361 BOOL status = TRUE;
362
363 if (lpOverlapped)
364 {
365 WLog_ERR(TAG, "WinPR %s does not support the lpOverlapped parameter", __FUNCTION__);
366 SetLastError(ERROR_NOT_SUPPORTED);
367 return FALSE;
368 }
369
370 pipe = (WINPR_NAMED_PIPE*)Object;
371
372 if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
373 {
374 if (pipe->clientfd == -1)
375 return FALSE;
376
377 do
378 {
379 io_status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite);
380 } while ((io_status < 0) && (errno == EINTR));
381
382 if (io_status < 0)
383 {
384 *lpNumberOfBytesWritten = 0;
385
386 switch (errno)
387 {
388 case EWOULDBLOCK:
389 io_status = 0;
390 status = TRUE;
391 break;
392
393 default:
394 status = FALSE;
395 }
396 }
397
398 *lpNumberOfBytesWritten = io_status;
399 return status;
400 }
401 else
402 {
403 /* Overlapped I/O */
404 if (!lpOverlapped)
405 return FALSE;
406
407 if (pipe->clientfd == -1)
408 return FALSE;
409
410 pipe->lpOverlapped = lpOverlapped;
411 #ifdef HAVE_SYS_AIO_H
412 {
413 struct aiocb cb;
414 ZeroMemory(&cb, sizeof(struct aiocb));
415 cb.aio_fildes = pipe->clientfd;
416 cb.aio_buf = (void*)lpBuffer;
417 cb.aio_nbytes = nNumberOfBytesToWrite;
418 cb.aio_offset = lpOverlapped->Offset;
419 cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
420 cb.aio_sigevent.sigev_signo = SIGIO;
421 cb.aio_sigevent.sigev_value.sival_ptr = (void*)lpOverlapped;
422 InstallAioSignalHandler();
423 io_status = aio_write(&cb);
424 WLog_DBG("aio_write status: %d", io_status);
425
426 if (io_status < 0)
427 status = FALSE;
428
429 return status;
430 }
431 #else
432 /* synchronous behavior */
433 lpOverlapped->Internal = 1;
434 lpOverlapped->InternalHigh = (ULONG_PTR)nNumberOfBytesToWrite;
435 lpOverlapped->Pointer = (PVOID)lpBuffer;
436 SetEvent(lpOverlapped->hEvent);
437 #endif
438 }
439
440 return TRUE;
441 }
442
443 static HANDLE_OPS namedOps = { NamedPipeIsHandled,
444 NamedPipeCloseHandle,
445 NamedPipeGetFd,
446 NULL, /* CleanupHandle */
447 NamedPipeRead,
448 NULL,
449 NULL,
450 NamedPipeWrite,
451 NULL,
452 NULL,
453 NULL,
454 NULL,
455 NULL,
456 NULL,
457 NULL,
458 NULL,
459 NULL,
460 NULL,
461 NULL,
462 NULL };
463
InitWinPRPipeModule()464 static BOOL InitWinPRPipeModule()
465 {
466 if (g_NamedPipeServerSockets)
467 return TRUE;
468
469 g_NamedPipeServerSockets = ArrayList_New(FALSE);
470 return g_NamedPipeServerSockets != NULL;
471 }
472
473 /*
474 * Unnamed pipe
475 */
476
CreatePipe(PHANDLE hReadPipe,PHANDLE hWritePipe,LPSECURITY_ATTRIBUTES lpPipeAttributes,DWORD nSize)477 BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes,
478 DWORD nSize)
479 {
480 int pipe_fd[2];
481 WINPR_PIPE* pReadPipe;
482 WINPR_PIPE* pWritePipe;
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->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->ops = &ops;
509 *((ULONG_PTR*)hWritePipe) = (ULONG_PTR)pWritePipe;
510 return TRUE;
511 }
512
513 /**
514 * Named pipe
515 */
516
winpr_unref_named_pipe(WINPR_NAMED_PIPE * pNamedPipe)517 static void winpr_unref_named_pipe(WINPR_NAMED_PIPE* pNamedPipe)
518 {
519 int index;
520 NamedPipeServerSocketEntry* baseSocket;
521
522 if (!pNamedPipe)
523 return;
524
525 assert(pNamedPipe->name);
526 assert(g_NamedPipeServerSockets);
527 // WLog_VRB(TAG, "%p (%s)", (void*) pNamedPipe, pNamedPipe->name);
528 ArrayList_Lock(g_NamedPipeServerSockets);
529
530 for (index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
531 {
532 baseSocket =
533 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
534 assert(baseSocket->name);
535
536 if (!strcmp(baseSocket->name, pNamedPipe->name))
537 {
538 assert(baseSocket->references > 0);
539 assert(baseSocket->serverfd != -1);
540
541 if (--baseSocket->references == 0)
542 {
543 // WLog_DBG(TAG, "removing shared server socked resource");
544 // WLog_DBG(TAG, "closing shared serverfd %d", baseSocket->serverfd);
545 ArrayList_Remove(g_NamedPipeServerSockets, baseSocket);
546 close(baseSocket->serverfd);
547 free(baseSocket->name);
548 free(baseSocket);
549 }
550
551 break;
552 }
553 }
554
555 ArrayList_Unlock(g_NamedPipeServerSockets);
556 }
557
CreateNamedPipeA(LPCSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes)558 HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
559 DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut,
560 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
561 {
562 int index;
563 char* lpPipePath;
564 struct sockaddr_un s;
565 WINPR_NAMED_PIPE* pNamedPipe = NULL;
566 int serverfd = -1;
567 NamedPipeServerSocketEntry* baseSocket = NULL;
568
569 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
570 {
571 WLog_ERR(TAG, "WinPR %s does not support the FILE_FLAG_OVERLAPPED flag", __FUNCTION__);
572 SetLastError(ERROR_NOT_SUPPORTED);
573 return INVALID_HANDLE_VALUE;
574 }
575
576 if (!lpName)
577 return INVALID_HANDLE_VALUE;
578
579 if (!InitWinPRPipeModule())
580 return INVALID_HANDLE_VALUE;
581
582 pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1, sizeof(WINPR_NAMED_PIPE));
583
584 if (!pNamedPipe)
585 return INVALID_HANDLE_VALUE;
586
587 ArrayList_Lock(g_NamedPipeServerSockets);
588 WINPR_HANDLE_SET_TYPE_AND_MODE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE, WINPR_FD_READ);
589 pNamedPipe->serverfd = -1;
590 pNamedPipe->clientfd = -1;
591
592 if (!(pNamedPipe->name = _strdup(lpName)))
593 goto out;
594
595 if (!(pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName)))
596 goto out;
597
598 if (!(pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName)))
599 goto out;
600
601 pNamedPipe->dwOpenMode = dwOpenMode;
602 pNamedPipe->dwPipeMode = dwPipeMode;
603 pNamedPipe->nMaxInstances = nMaxInstances;
604 pNamedPipe->nOutBufferSize = nOutBufferSize;
605 pNamedPipe->nInBufferSize = nInBufferSize;
606 pNamedPipe->nDefaultTimeOut = nDefaultTimeOut;
607 pNamedPipe->dwFlagsAndAttributes = dwOpenMode;
608 pNamedPipe->clientfd = -1;
609 pNamedPipe->ServerMode = TRUE;
610 pNamedPipe->ops = &namedOps;
611
612 for (index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
613 {
614 baseSocket =
615 (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
616
617 if (!strcmp(baseSocket->name, lpName))
618 {
619 serverfd = baseSocket->serverfd;
620 // WLog_DBG(TAG, "using shared socked resource for pipe %p (%s)", (void*) pNamedPipe,
621 // lpName);
622 break;
623 }
624 }
625
626 /* If this is the first instance of the named pipe... */
627 if (serverfd == -1)
628 {
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 WLog_ERR(TAG, "CreateNamedPipeA: socket error, %s", strerror(errno));
652 goto out;
653 }
654
655 ZeroMemory(&s, sizeof(struct sockaddr_un));
656 s.sun_family = AF_UNIX;
657 sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path), "%s", pNamedPipe->lpFilePath);
658
659 if (bind(serverfd, (struct sockaddr*)&s, sizeof(struct sockaddr_un)) == -1)
660 {
661 WLog_ERR(TAG, "CreateNamedPipeA: bind error, %s", strerror(errno));
662 goto out;
663 }
664
665 if (listen(serverfd, 2) == -1)
666 {
667 WLog_ERR(TAG, "CreateNamedPipeA: listen error, %s", strerror(errno));
668 goto out;
669 }
670
671 UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF);
672
673 if (!(baseSocket = (NamedPipeServerSocketEntry*)malloc(sizeof(NamedPipeServerSocketEntry))))
674 goto out;
675
676 if (!(baseSocket->name = _strdup(lpName)))
677 {
678 free(baseSocket);
679 goto out;
680 }
681
682 baseSocket->serverfd = serverfd;
683 baseSocket->references = 0;
684
685 if (ArrayList_Add(g_NamedPipeServerSockets, baseSocket) < 0)
686 {
687 free(baseSocket->name);
688 goto out;
689 }
690
691 // WLog_DBG(TAG, "created shared socked resource for pipe %p (%s). base serverfd = %d",
692 // (void*) pNamedPipe, lpName, serverfd);
693 }
694
695 pNamedPipe->serverfd = dup(baseSocket->serverfd);
696 // WLog_DBG(TAG, "using serverfd %d (duplicated from %d)", pNamedPipe->serverfd,
697 // baseSocket->serverfd);
698 pNamedPipe->pfnUnrefNamedPipe = winpr_unref_named_pipe;
699 baseSocket->references++;
700
701 if (dwOpenMode & FILE_FLAG_OVERLAPPED)
702 {
703 #if 0
704 int flags = fcntl(pNamedPipe->serverfd, F_GETFL);
705
706 if (flags != -1)
707 fcntl(pNamedPipe->serverfd, F_SETFL, flags | O_NONBLOCK);
708
709 #endif
710 }
711
712 ArrayList_Unlock(g_NamedPipeServerSockets);
713 return pNamedPipe;
714 out:
715 NamedPipeCloseHandle(pNamedPipe);
716
717 if (serverfd != -1)
718 close(serverfd);
719
720 ArrayList_Unlock(g_NamedPipeServerSockets);
721 return INVALID_HANDLE_VALUE;
722 }
723
CreateNamedPipeW(LPCWSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes)724 HANDLE CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
725 DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut,
726 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
727 {
728 WLog_ERR(TAG, "%s is not implemented", __FUNCTION__);
729 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
730 return NULL;
731 }
732
ConnectNamedPipe(HANDLE hNamedPipe,LPOVERLAPPED lpOverlapped)733 BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped)
734 {
735 int status;
736 socklen_t length;
737 struct sockaddr_un s;
738 WINPR_NAMED_PIPE* pNamedPipe;
739
740 if (lpOverlapped)
741 {
742 WLog_ERR(TAG, "WinPR %s does not support the lpOverlapped parameter", __FUNCTION__);
743 SetLastError(ERROR_NOT_SUPPORTED);
744 return FALSE;
745 }
746
747 if (!hNamedPipe)
748 return FALSE;
749
750 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
751
752 if (!(pNamedPipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
753 {
754 length = sizeof(struct sockaddr_un);
755 ZeroMemory(&s, sizeof(struct sockaddr_un));
756 status = accept(pNamedPipe->serverfd, (struct sockaddr*)&s, &length);
757
758 if (status < 0)
759 {
760 WLog_ERR(TAG, "ConnectNamedPipe: accept error");
761 return FALSE;
762 }
763
764 pNamedPipe->clientfd = status;
765 pNamedPipe->ServerMode = FALSE;
766 }
767 else
768 {
769 if (!lpOverlapped)
770 return FALSE;
771
772 if (pNamedPipe->serverfd == -1)
773 return FALSE;
774
775 pNamedPipe->lpOverlapped = lpOverlapped;
776 /* synchronous behavior */
777 lpOverlapped->Internal = 2;
778 lpOverlapped->InternalHigh = (ULONG_PTR)0;
779 lpOverlapped->Pointer = (PVOID)NULL;
780 SetEvent(lpOverlapped->hEvent);
781 }
782
783 return TRUE;
784 }
785
DisconnectNamedPipe(HANDLE hNamedPipe)786 BOOL DisconnectNamedPipe(HANDLE hNamedPipe)
787 {
788 WINPR_NAMED_PIPE* pNamedPipe;
789 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
790
791 if (pNamedPipe->clientfd != -1)
792 {
793 close(pNamedPipe->clientfd);
794 pNamedPipe->clientfd = -1;
795 }
796
797 return TRUE;
798 }
799
PeekNamedPipe(HANDLE hNamedPipe,LPVOID lpBuffer,DWORD nBufferSize,LPDWORD lpBytesRead,LPDWORD lpTotalBytesAvail,LPDWORD lpBytesLeftThisMessage)800 BOOL PeekNamedPipe(HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, LPDWORD lpBytesRead,
801 LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage)
802 {
803 WLog_ERR(TAG, "%s: Not implemented", __FUNCTION__);
804 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
805 return FALSE;
806 }
807
TransactNamedPipe(HANDLE hNamedPipe,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,LPOVERLAPPED lpOverlapped)808 BOOL TransactNamedPipe(HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize,
809 LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead,
810 LPOVERLAPPED lpOverlapped)
811 {
812 WLog_ERR(TAG, "%s: Not implemented", __FUNCTION__);
813 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
814 return FALSE;
815 }
816
WaitNamedPipeA(LPCSTR lpNamedPipeName,DWORD nTimeOut)817 BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut)
818 {
819 BOOL status;
820 DWORD nWaitTime;
821 char* lpFilePath;
822 DWORD dwSleepInterval;
823
824 if (!lpNamedPipeName)
825 return FALSE;
826
827 lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpNamedPipeName);
828
829 if (!lpFilePath)
830 return FALSE;
831
832 if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
833 nTimeOut = 50;
834
835 nWaitTime = 0;
836 status = TRUE;
837 dwSleepInterval = 10;
838
839 while (!winpr_PathFileExists(lpFilePath))
840 {
841 Sleep(dwSleepInterval);
842 nWaitTime += dwSleepInterval;
843
844 if (nWaitTime >= nTimeOut)
845 {
846 status = FALSE;
847 break;
848 }
849 }
850
851 free(lpFilePath);
852 return status;
853 }
854
WaitNamedPipeW(LPCWSTR lpNamedPipeName,DWORD nTimeOut)855 BOOL WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut)
856 {
857 WLog_ERR(TAG, "%s: Not implemented", __FUNCTION__);
858 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
859 return FALSE;
860 }
861
SetNamedPipeHandleState(HANDLE hNamedPipe,LPDWORD lpMode,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout)862 BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount,
863 LPDWORD lpCollectDataTimeout)
864 {
865 int fd;
866 int flags;
867 WINPR_NAMED_PIPE* pNamedPipe;
868 pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
869
870 if (lpMode)
871 {
872 pNamedPipe->dwPipeMode = *lpMode;
873 fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
874
875 if (fd == -1)
876 return FALSE;
877
878 flags = fcntl(fd, F_GETFL);
879
880 if (flags < 0)
881 return FALSE;
882
883 if (pNamedPipe->dwPipeMode & PIPE_NOWAIT)
884 flags = (flags | O_NONBLOCK);
885 else
886 flags = (flags & ~(O_NONBLOCK));
887
888 if (fcntl(fd, F_SETFL, flags) < 0)
889 return FALSE;
890 }
891
892 if (lpMaxCollectionCount)
893 {
894 }
895
896 if (lpCollectDataTimeout)
897 {
898 }
899
900 return TRUE;
901 }
902
ImpersonateNamedPipeClient(HANDLE hNamedPipe)903 BOOL ImpersonateNamedPipeClient(HANDLE hNamedPipe)
904 {
905 WLog_ERR(TAG, "%s: Not implemented", __FUNCTION__);
906 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
907 return FALSE;
908 }
909
GetNamedPipeClientComputerNameA(HANDLE Pipe,LPCSTR ClientComputerName,ULONG ClientComputerNameLength)910 BOOL GetNamedPipeClientComputerNameA(HANDLE Pipe, LPCSTR ClientComputerName,
911 ULONG ClientComputerNameLength)
912 {
913 WLog_ERR(TAG, "%s: Not implemented", __FUNCTION__);
914 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
915 return FALSE;
916 }
917
GetNamedPipeClientComputerNameW(HANDLE Pipe,LPCWSTR ClientComputerName,ULONG ClientComputerNameLength)918 BOOL GetNamedPipeClientComputerNameW(HANDLE Pipe, LPCWSTR ClientComputerName,
919 ULONG ClientComputerNameLength)
920 {
921 WLog_ERR(TAG, "%s: Not implemented", __FUNCTION__);
922 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
923 return FALSE;
924 }
925
926 #endif
927