summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
commita9bcc81f821d7c66f623779fa5147e728eb3c388 (patch)
tree98676963bcdd537ae5908a067a8eb110b93486a6 /winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c
parentInitial commit. (diff)
downloadfreerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz
freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c')
-rw-r--r--winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c510
1 files changed, 510 insertions, 0 deletions
diff --git a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c
new file mode 100644
index 0000000..8c8ead2
--- /dev/null
+++ b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c
@@ -0,0 +1,510 @@
+
+#include <stdio.h>
+#include <winpr/crt.h>
+#include <winpr/pipe.h>
+#include <winpr/file.h>
+#include <winpr/tchar.h>
+#include <winpr/winpr.h>
+#include <winpr/print.h>
+#include <winpr/synch.h>
+#include <winpr/wlog.h>
+#include <winpr/thread.h>
+#ifndef _WIN32
+#include <signal.h>
+#endif
+#include "../pipe.h"
+
+#define PIPE_BUFFER_SIZE 32
+
+static HANDLE ReadyEvent;
+
+static LPTSTR lpszPipeNameMt = _T("\\\\.\\pipe\\winpr_test_pipe_mt");
+static LPTSTR lpszPipeNameSt = _T("\\\\.\\pipe\\winpr_test_pipe_st");
+
+static BOOL testFailed = FALSE;
+
+static DWORD WINAPI named_pipe_client_thread(LPVOID arg)
+{
+ HANDLE hNamedPipe = NULL;
+ BYTE* lpReadBuffer = NULL;
+ BYTE* lpWriteBuffer = NULL;
+ BOOL fSuccess = FALSE;
+ DWORD nNumberOfBytesToRead = 0;
+ DWORD nNumberOfBytesToWrite = 0;
+ DWORD lpNumberOfBytesRead = 0;
+ DWORD lpNumberOfBytesWritten = 0;
+ WaitForSingleObject(ReadyEvent, INFINITE);
+ hNamedPipe =
+ CreateFile(lpszPipeNameMt, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (hNamedPipe == INVALID_HANDLE_VALUE)
+ {
+ printf("%s: Named Pipe CreateFile failure: INVALID_HANDLE_VALUE\n", __func__);
+ goto out;
+ }
+
+ if (!(lpReadBuffer = (BYTE*)malloc(PIPE_BUFFER_SIZE)))
+ {
+ printf("%s: Error allocating read buffer\n", __func__);
+ goto out;
+ }
+
+ if (!(lpWriteBuffer = (BYTE*)malloc(PIPE_BUFFER_SIZE)))
+ {
+ printf("%s: Error allocating write buffer\n", __func__);
+ goto out;
+ }
+
+ lpNumberOfBytesWritten = 0;
+ nNumberOfBytesToWrite = PIPE_BUFFER_SIZE;
+ FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x59);
+
+ if (!WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten,
+ NULL) ||
+ lpNumberOfBytesWritten != nNumberOfBytesToWrite)
+ {
+ printf("%s: Client NamedPipe WriteFile failure\n", __func__);
+ goto out;
+ }
+
+ lpNumberOfBytesRead = 0;
+ nNumberOfBytesToRead = PIPE_BUFFER_SIZE;
+ ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE);
+
+ if (!ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL) ||
+ lpNumberOfBytesRead != nNumberOfBytesToRead)
+ {
+ printf("%s: Client NamedPipe ReadFile failure\n", __func__);
+ goto out;
+ }
+
+ printf("Client ReadFile: %" PRIu32 " bytes\n", lpNumberOfBytesRead);
+ winpr_HexDump("pipe.test", WLOG_DEBUG, lpReadBuffer, lpNumberOfBytesRead);
+ fSuccess = TRUE;
+out:
+ free(lpReadBuffer);
+ free(lpWriteBuffer);
+ CloseHandle(hNamedPipe);
+
+ if (!fSuccess)
+ testFailed = TRUE;
+
+ ExitThread(0);
+ return 0;
+}
+
+static DWORD WINAPI named_pipe_server_thread(LPVOID arg)
+{
+ HANDLE hNamedPipe = NULL;
+ BYTE* lpReadBuffer = NULL;
+ BYTE* lpWriteBuffer = NULL;
+ BOOL fSuccess = FALSE;
+ BOOL fConnected = FALSE;
+ DWORD nNumberOfBytesToRead = 0;
+ DWORD nNumberOfBytesToWrite = 0;
+ DWORD lpNumberOfBytesRead = 0;
+ DWORD lpNumberOfBytesWritten = 0;
+ hNamedPipe = CreateNamedPipe(
+ lpszPipeNameMt, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL);
+
+ if (!hNamedPipe)
+ {
+ printf("%s: CreateNamedPipe failure: NULL handle\n", __func__);
+ goto out;
+ }
+
+ if (hNamedPipe == INVALID_HANDLE_VALUE)
+ {
+ printf("%s: CreateNamedPipe failure: INVALID_HANDLE_VALUE\n", __func__);
+ goto out;
+ }
+
+ SetEvent(ReadyEvent);
+
+ /**
+ * Note:
+ * If a client connects before ConnectNamedPipe is called, the function returns zero and
+ * GetLastError returns ERROR_PIPE_CONNECTED. This can happen if a client connects in the
+ * interval between the call to CreateNamedPipe and the call to ConnectNamedPipe.
+ * In this situation, there is a good connection between client and server, even though
+ * the function returns zero.
+ */
+ fConnected =
+ ConnectNamedPipe(hNamedPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
+
+ if (!fConnected)
+ {
+ printf("%s: ConnectNamedPipe failure\n", __func__);
+ goto out;
+ }
+
+ if (!(lpReadBuffer = (BYTE*)calloc(1, PIPE_BUFFER_SIZE)))
+ {
+ printf("%s: Error allocating read buffer\n", __func__);
+ goto out;
+ }
+
+ if (!(lpWriteBuffer = (BYTE*)malloc(PIPE_BUFFER_SIZE)))
+ {
+ printf("%s: Error allocating write buffer\n", __func__);
+ goto out;
+ }
+
+ lpNumberOfBytesRead = 0;
+ nNumberOfBytesToRead = PIPE_BUFFER_SIZE;
+
+ if (!ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL) ||
+ lpNumberOfBytesRead != nNumberOfBytesToRead)
+ {
+ printf("%s: Server NamedPipe ReadFile failure\n", __func__);
+ goto out;
+ }
+
+ printf("Server ReadFile: %" PRIu32 " bytes\n", lpNumberOfBytesRead);
+ winpr_HexDump("pipe.test", WLOG_DEBUG, lpReadBuffer, lpNumberOfBytesRead);
+ lpNumberOfBytesWritten = 0;
+ nNumberOfBytesToWrite = PIPE_BUFFER_SIZE;
+ FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x45);
+
+ if (!WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten,
+ NULL) ||
+ lpNumberOfBytesWritten != nNumberOfBytesToWrite)
+ {
+ printf("%s: Server NamedPipe WriteFile failure\n", __func__);
+ goto out;
+ }
+
+ fSuccess = TRUE;
+out:
+ free(lpReadBuffer);
+ free(lpWriteBuffer);
+ CloseHandle(hNamedPipe);
+
+ if (!fSuccess)
+ testFailed = TRUE;
+
+ ExitThread(0);
+ return 0;
+}
+
+#define TESTNUMPIPESST 16
+static DWORD WINAPI named_pipe_single_thread(LPVOID arg)
+{
+ HANDLE servers[TESTNUMPIPESST] = { 0 };
+ HANDLE clients[TESTNUMPIPESST] = { 0 };
+ DWORD dwRead = 0;
+ DWORD dwWritten = 0;
+ int numPipes = 0;
+ BOOL bSuccess = FALSE;
+ numPipes = TESTNUMPIPESST;
+ WaitForSingleObject(ReadyEvent, INFINITE);
+
+ for (int i = 0; i < numPipes; i++)
+ {
+ if (!(servers[i] = CreateNamedPipe(lpszPipeNameSt, PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE,
+ PIPE_BUFFER_SIZE, 0, NULL)))
+ {
+ printf("%s: CreateNamedPipe #%d failed\n", __func__, i);
+ goto out;
+ }
+ }
+
+#ifndef _WIN32
+
+ for (int i = 0; i < numPipes; i++)
+ {
+ WINPR_NAMED_PIPE* p = (WINPR_NAMED_PIPE*)servers[i];
+
+ if (strcmp(lpszPipeNameSt, p->name))
+ {
+ printf("%s: Pipe name mismatch for pipe #%d ([%s] instead of [%s])\n", __func__, i,
+ p->name, lpszPipeNameSt);
+ goto out;
+ }
+
+ if (p->clientfd != -1)
+ {
+ printf("%s: Unexpected client fd value for pipe #%d (%d instead of -1)\n", __func__, i,
+ p->clientfd);
+ goto out;
+ }
+
+ if (p->serverfd < 1)
+ {
+ printf("%s: Unexpected server fd value for pipe #%d (%d is not > 0)\n", __func__, i,
+ p->serverfd);
+ goto out;
+ }
+
+ if (p->ServerMode == FALSE)
+ {
+ printf("%s: Unexpected ServerMode value for pipe #%d (0 instead of 1)\n", __func__, i);
+ goto out;
+ }
+ }
+
+#endif
+
+ for (int i = 0; i < numPipes; i++)
+ {
+ BOOL fConnected = 0;
+ if ((clients[i] = CreateFile(lpszPipeNameSt, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
+ {
+ printf("%s: CreateFile #%d failed\n", __func__, i);
+ goto out;
+ }
+
+ /**
+ * Note:
+ * If a client connects before ConnectNamedPipe is called, the function returns zero and
+ * GetLastError returns ERROR_PIPE_CONNECTED. This can happen if a client connects in the
+ * interval between the call to CreateNamedPipe and the call to ConnectNamedPipe.
+ * In this situation, there is a good connection between client and server, even though
+ * the function returns zero.
+ */
+ fConnected =
+ ConnectNamedPipe(servers[i], NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
+
+ if (!fConnected)
+ {
+ printf("%s: ConnectNamedPipe #%d failed. (%" PRIu32 ")\n", __func__, i, GetLastError());
+ goto out;
+ }
+ }
+
+#ifndef _WIN32
+
+ for (int i = 0; i < numPipes; i++)
+ {
+ WINPR_NAMED_PIPE* p = servers[i];
+
+ if (p->clientfd < 1)
+ {
+ printf("%s: Unexpected client fd value for pipe #%d (%d is not > 0)\n", __func__, i,
+ p->clientfd);
+ goto out;
+ }
+
+ if (p->ServerMode)
+ {
+ printf("%s: Unexpected ServerMode value for pipe #%d (1 instead of 0)\n", __func__, i);
+ goto out;
+ }
+ }
+
+ for (int i = 0; i < numPipes; i++)
+ {
+ {
+ char sndbuf[PIPE_BUFFER_SIZE] = { 0 };
+ char rcvbuf[PIPE_BUFFER_SIZE] = { 0 };
+ /* Test writing from clients to servers */
+ sprintf_s(sndbuf, sizeof(sndbuf), "CLIENT->SERVER ON PIPE #%05d", i);
+
+ if (!WriteFile(clients[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL) ||
+ dwWritten != sizeof(sndbuf))
+ {
+ printf("%s: Error writing to client end of pipe #%d\n", __func__, i);
+ goto out;
+ }
+
+ if (!ReadFile(servers[i], rcvbuf, dwWritten, &dwRead, NULL) || dwRead != dwWritten)
+ {
+ printf("%s: Error reading on server end of pipe #%d\n", __func__, i);
+ goto out;
+ }
+
+ if (memcmp(sndbuf, rcvbuf, sizeof(sndbuf)))
+ {
+ printf("%s: Error data read on server end of pipe #%d is corrupted\n", __func__, i);
+ goto out;
+ }
+ }
+ {
+
+ char sndbuf[PIPE_BUFFER_SIZE] = { 0 };
+ char rcvbuf[PIPE_BUFFER_SIZE] = { 0 };
+ /* Test writing from servers to clients */
+
+ sprintf_s(sndbuf, sizeof(sndbuf), "SERVER->CLIENT ON PIPE #%05d", i);
+
+ if (!WriteFile(servers[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL) ||
+ dwWritten != sizeof(sndbuf))
+ {
+ printf("%s: Error writing to server end of pipe #%d\n", __func__, i);
+ goto out;
+ }
+
+ if (!ReadFile(clients[i], rcvbuf, dwWritten, &dwRead, NULL) || dwRead != dwWritten)
+ {
+ printf("%s: Error reading on client end of pipe #%d\n", __func__, i);
+ goto out;
+ }
+
+ if (memcmp(sndbuf, rcvbuf, sizeof(sndbuf)))
+ {
+ printf("%s: Error data read on client end of pipe #%d is corrupted\n", __func__, i);
+ goto out;
+ }
+ }
+ }
+
+#endif
+ /**
+ * After DisconnectNamedPipe on server end
+ * ReadFile/WriteFile must fail on client end
+ */
+ int i = numPipes - 1;
+ DisconnectNamedPipe(servers[i]);
+ {
+ char sndbuf[PIPE_BUFFER_SIZE] = { 0 };
+ char rcvbuf[PIPE_BUFFER_SIZE] = { 0 };
+ if (ReadFile(clients[i], rcvbuf, sizeof(rcvbuf), &dwRead, NULL))
+ {
+ printf("%s: Error ReadFile on client should have failed after DisconnectNamedPipe on "
+ "server\n",
+ __func__);
+ goto out;
+ }
+
+ if (WriteFile(clients[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL))
+ {
+ printf(
+ "%s: Error WriteFile on client end should have failed after DisconnectNamedPipe on "
+ "server\n",
+ __func__);
+ goto out;
+ }
+ }
+ CloseHandle(servers[i]);
+ CloseHandle(clients[i]);
+ numPipes--;
+ /**
+ * After CloseHandle (without calling DisconnectNamedPipe first) on server end
+ * ReadFile/WriteFile must fail on client end
+ */
+ i = numPipes - 1;
+ CloseHandle(servers[i]);
+
+ {
+ char sndbuf[PIPE_BUFFER_SIZE] = { 0 };
+ char rcvbuf[PIPE_BUFFER_SIZE] = { 0 };
+
+ if (ReadFile(clients[i], rcvbuf, sizeof(rcvbuf), &dwRead, NULL))
+ {
+ printf(
+ "%s: Error ReadFile on client end should have failed after CloseHandle on server\n",
+ __func__);
+ goto out;
+ }
+
+ if (WriteFile(clients[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL))
+ {
+ printf("%s: Error WriteFile on client end should have failed after CloseHandle on "
+ "server\n",
+ __func__);
+ goto out;
+ }
+ }
+ CloseHandle(clients[i]);
+ numPipes--;
+ /**
+ * After CloseHandle on client end
+ * ReadFile/WriteFile must fail on server end
+ */
+ i = numPipes - 1;
+ CloseHandle(clients[i]);
+
+ {
+ char sndbuf[PIPE_BUFFER_SIZE] = { 0 };
+ char rcvbuf[PIPE_BUFFER_SIZE] = { 0 };
+
+ if (ReadFile(servers[i], rcvbuf, sizeof(rcvbuf), &dwRead, NULL))
+ {
+ printf(
+ "%s: Error ReadFile on server end should have failed after CloseHandle on client\n",
+ __func__);
+ goto out;
+ }
+
+ if (WriteFile(servers[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL))
+ {
+ printf("%s: Error WriteFile on server end should have failed after CloseHandle on "
+ "client\n",
+ __func__);
+ goto out;
+ }
+ }
+
+ DisconnectNamedPipe(servers[i]);
+ CloseHandle(servers[i]);
+ numPipes--;
+
+ /* Close all remaining pipes */
+ for (int i = 0; i < numPipes; i++)
+ {
+ DisconnectNamedPipe(servers[i]);
+ CloseHandle(servers[i]);
+ CloseHandle(clients[i]);
+ }
+
+ bSuccess = TRUE;
+out:
+
+ if (!bSuccess)
+ testFailed = TRUE;
+
+ return 0;
+}
+
+int TestPipeCreateNamedPipe(int argc, char* argv[])
+{
+ HANDLE SingleThread = NULL;
+ HANDLE ClientThread = NULL;
+ HANDLE ServerThread = NULL;
+ HANDLE hPipe = NULL;
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+ /* Verify that CreateNamedPipe returns INVALID_HANDLE_VALUE on failure */
+ hPipe = CreateNamedPipeA(NULL, 0, 0, 0, 0, 0, 0, NULL);
+ if (hPipe != INVALID_HANDLE_VALUE)
+ {
+ printf("CreateNamedPipe unexpectedly returned %p instead of INVALID_HANDLE_VALUE (%p)\n",
+ hPipe, INVALID_HANDLE_VALUE);
+ return -1;
+ }
+
+#ifndef _WIN32
+ signal(SIGPIPE, SIG_IGN);
+#endif
+ if (!(ReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
+ {
+ printf("CreateEvent failure: (%" PRIu32 ")\n", GetLastError());
+ return -1;
+ }
+ if (!(SingleThread = CreateThread(NULL, 0, named_pipe_single_thread, NULL, 0, NULL)))
+ {
+ printf("CreateThread (SingleThread) failure: (%" PRIu32 ")\n", GetLastError());
+ return -1;
+ }
+ if (!(ClientThread = CreateThread(NULL, 0, named_pipe_client_thread, NULL, 0, NULL)))
+ {
+ printf("CreateThread (ClientThread) failure: (%" PRIu32 ")\n", GetLastError());
+ return -1;
+ }
+ if (!(ServerThread = CreateThread(NULL, 0, named_pipe_server_thread, NULL, 0, NULL)))
+ {
+ printf("CreateThread (ServerThread) failure: (%" PRIu32 ")\n", GetLastError());
+ return -1;
+ }
+ WaitForSingleObject(SingleThread, INFINITE);
+ WaitForSingleObject(ClientThread, INFINITE);
+ WaitForSingleObject(ServerThread, INFINITE);
+ CloseHandle(SingleThread);
+ CloseHandle(ClientThread);
+ CloseHandle(ServerThread);
+ return testFailed;
+}