Coverage Report

Created: 2023-11-19 06:16

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