summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c397
1 files changed, 397 insertions, 0 deletions
diff --git a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c
new file mode 100644
index 0000000..de95840
--- /dev/null
+++ b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c
@@ -0,0 +1,397 @@
+
+#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/wlog.h>
+#include <winpr/print.h>
+#include <winpr/synch.h>
+#include <winpr/thread.h>
+
+#define PIPE_BUFFER_SIZE 32
+#define PIPE_TIMEOUT_MS 20000 // 20 seconds
+
+static BYTE SERVER_MESSAGE[PIPE_BUFFER_SIZE];
+static BYTE CLIENT_MESSAGE[PIPE_BUFFER_SIZE];
+
+static BOOL bClientSuccess = FALSE;
+static BOOL bServerSuccess = FALSE;
+
+static HANDLE serverReadyEvent = NULL;
+
+static LPTSTR lpszPipeName = _T("\\\\.\\pipe\\winpr_test_pipe_overlapped");
+
+static DWORD WINAPI named_pipe_client_thread(LPVOID arg)
+{
+ DWORD status = 0;
+ HANDLE hEvent = NULL;
+ HANDLE hNamedPipe = NULL;
+ BYTE* lpReadBuffer = NULL;
+ BOOL fSuccess = FALSE;
+ OVERLAPPED overlapped = { 0 };
+ DWORD nNumberOfBytesToRead = 0;
+ DWORD nNumberOfBytesToWrite = 0;
+ DWORD NumberOfBytesTransferred = 0;
+
+ WINPR_UNUSED(arg);
+
+ status = WaitForSingleObject(serverReadyEvent, PIPE_TIMEOUT_MS);
+ if (status != WAIT_OBJECT_0)
+ {
+ printf("client: failed to wait for server ready event: %" PRIu32 "\n", status);
+ goto finish;
+ }
+
+ /* 1: initialize overlapped structure */
+ if (!(hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
+ {
+ printf("client: CreateEvent failure: %" PRIu32 "\n", GetLastError());
+ goto finish;
+ }
+ overlapped.hEvent = hEvent;
+
+ /* 2: connect to server named pipe */
+
+ hNamedPipe = CreateFile(lpszPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED, NULL);
+
+ if (hNamedPipe == INVALID_HANDLE_VALUE)
+ {
+ printf("client: Named Pipe CreateFile failure: %" PRIu32 "\n", GetLastError());
+ goto finish;
+ }
+
+ /* 3: write to named pipe */
+
+ nNumberOfBytesToWrite = PIPE_BUFFER_SIZE;
+ NumberOfBytesTransferred = 0;
+
+ fSuccess = WriteFile(hNamedPipe, CLIENT_MESSAGE, nNumberOfBytesToWrite, NULL, &overlapped);
+
+ if (!fSuccess)
+ fSuccess = (GetLastError() == ERROR_IO_PENDING);
+
+ if (!fSuccess)
+ {
+ printf("client: NamedPipe WriteFile failure (initial): %" PRIu32 "\n", GetLastError());
+ goto finish;
+ }
+
+ status = WaitForSingleObject(hEvent, PIPE_TIMEOUT_MS);
+ if (status != WAIT_OBJECT_0)
+ {
+ printf("client: failed to wait for overlapped event (write): %" PRIu32 "\n", status);
+ goto finish;
+ }
+
+ fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, FALSE);
+ if (!fSuccess)
+ {
+ printf("client: NamedPipe WriteFile failure (final): %" PRIu32 "\n", GetLastError());
+ goto finish;
+ }
+ printf("client: WriteFile transferred %" PRIu32 " bytes:\n", NumberOfBytesTransferred);
+
+ /* 4: read from named pipe */
+
+ if (!(lpReadBuffer = (BYTE*)calloc(1, PIPE_BUFFER_SIZE)))
+ {
+ printf("client: Error allocating read buffer\n");
+ goto finish;
+ }
+
+ nNumberOfBytesToRead = PIPE_BUFFER_SIZE;
+ NumberOfBytesTransferred = 0;
+
+ fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, NULL, &overlapped);
+
+ if (!fSuccess)
+ fSuccess = (GetLastError() == ERROR_IO_PENDING);
+
+ if (!fSuccess)
+ {
+ printf("client: NamedPipe ReadFile failure (initial): %" PRIu32 "\n", GetLastError());
+ goto finish;
+ }
+
+ status = WaitForMultipleObjects(1, &hEvent, FALSE, PIPE_TIMEOUT_MS);
+ if (status != WAIT_OBJECT_0)
+ {
+ printf("client: failed to wait for overlapped event (read): %" PRIu32 "\n", status);
+ goto finish;
+ }
+
+ fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE);
+ if (!fSuccess)
+ {
+ printf("client: NamedPipe ReadFile failure (final): %" PRIu32 "\n", GetLastError());
+ goto finish;
+ }
+
+ printf("client: ReadFile transferred %" PRIu32 " bytes:\n", NumberOfBytesTransferred);
+ winpr_HexDump("pipe.test", WLOG_DEBUG, lpReadBuffer, NumberOfBytesTransferred);
+
+ if (NumberOfBytesTransferred != PIPE_BUFFER_SIZE ||
+ memcmp(lpReadBuffer, SERVER_MESSAGE, PIPE_BUFFER_SIZE))
+ {
+ printf("client: received unexpected data from server\n");
+ goto finish;
+ }
+
+ printf("client: finished successfully\n");
+ bClientSuccess = TRUE;
+
+finish:
+ free(lpReadBuffer);
+ if (hNamedPipe)
+ CloseHandle(hNamedPipe);
+ if (hEvent)
+ CloseHandle(hEvent);
+
+ return 0;
+}
+
+static DWORD WINAPI named_pipe_server_thread(LPVOID arg)
+{
+ DWORD status = 0;
+ HANDLE hEvent = NULL;
+ HANDLE hNamedPipe = NULL;
+ BYTE* lpReadBuffer = NULL;
+ OVERLAPPED overlapped = { 0 };
+ BOOL fSuccess = FALSE;
+ BOOL fConnected = FALSE;
+ DWORD nNumberOfBytesToRead = 0;
+ DWORD nNumberOfBytesToWrite = 0;
+ DWORD NumberOfBytesTransferred = 0;
+
+ WINPR_UNUSED(arg);
+
+ /* 1: initialize overlapped structure */
+ if (!(hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
+ {
+ printf("server: CreateEvent failure: %" PRIu32 "\n", GetLastError());
+ SetEvent(serverReadyEvent); /* unblock client thread */
+ goto finish;
+ }
+ overlapped.hEvent = hEvent;
+
+ /* 2: create named pipe and set ready event */
+
+ hNamedPipe =
+ CreateNamedPipe(lpszPipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
+ PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL);
+
+ if (hNamedPipe == INVALID_HANDLE_VALUE)
+ {
+ printf("server: CreateNamedPipe failure: %" PRIu32 "\n", GetLastError());
+ SetEvent(serverReadyEvent); /* unblock client thread */
+ goto finish;
+ }
+
+ SetEvent(serverReadyEvent);
+
+ /* 3: connect named pipe */
+
+#if 0
+ /* This sleep will most certainly cause ERROR_PIPE_CONNECTED below */
+ Sleep(2000);
+#endif
+
+ fConnected = ConnectNamedPipe(hNamedPipe, &overlapped);
+ status = GetLastError();
+
+ /**
+ * At this point if fConnected is FALSE, we have to check GetLastError() for:
+ * ERROR_PIPE_CONNECTED:
+ * client has already connected before we have called ConnectNamedPipe.
+ * this is quite common depending on the timings and indicates success
+ * ERROR_IO_PENDING:
+ * Since we're using ConnectNamedPipe asynchronously here, the function returns
+ * immediately and this error code simply indicates that the operation is
+ * still in progress. Hence we have to wait for the completion event and use
+ * GetOverlappedResult to query the actual result of the operation (note that
+ * the lpNumberOfBytesTransferred parameter is undefined/useless for a
+ * ConnectNamedPipe operation)
+ */
+
+ if (!fConnected)
+ fConnected = (status == ERROR_PIPE_CONNECTED);
+
+ printf("server: ConnectNamedPipe status: %" PRIu32 "\n", status);
+
+ if (!fConnected && status == ERROR_IO_PENDING)
+ {
+ DWORD dwDummy = 0;
+ printf("server: waiting up to %u ms for connection ...\n", PIPE_TIMEOUT_MS);
+ status = WaitForSingleObject(hEvent, PIPE_TIMEOUT_MS);
+ if (status == WAIT_OBJECT_0)
+ fConnected = GetOverlappedResult(hNamedPipe, &overlapped, &dwDummy, FALSE);
+ else
+ printf("server: failed to wait for overlapped event (connect): %" PRIu32 "\n", status);
+ }
+
+ if (!fConnected)
+ {
+ printf("server: ConnectNamedPipe failed: %" PRIu32 "\n", status);
+ goto finish;
+ }
+
+ printf("server: named pipe successfully connected\n");
+
+ /* 4: read from named pipe */
+
+ if (!(lpReadBuffer = (BYTE*)calloc(1, PIPE_BUFFER_SIZE)))
+ {
+ printf("server: Error allocating read buffer\n");
+ goto finish;
+ }
+
+ nNumberOfBytesToRead = PIPE_BUFFER_SIZE;
+ NumberOfBytesTransferred = 0;
+
+ fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, NULL, &overlapped);
+
+ if (!fSuccess)
+ fSuccess = (GetLastError() == ERROR_IO_PENDING);
+
+ if (!fSuccess)
+ {
+ printf("server: NamedPipe ReadFile failure (initial): %" PRIu32 "\n", GetLastError());
+ goto finish;
+ }
+
+ status = WaitForSingleObject(hEvent, PIPE_TIMEOUT_MS);
+ if (status != WAIT_OBJECT_0)
+ {
+ printf("server: failed to wait for overlapped event (read): %" PRIu32 "\n", status);
+ goto finish;
+ }
+
+ fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, FALSE);
+ if (!fSuccess)
+ {
+ printf("server: NamedPipe ReadFile failure (final): %" PRIu32 "\n", GetLastError());
+ goto finish;
+ }
+
+ printf("server: ReadFile transferred %" PRIu32 " bytes:\n", NumberOfBytesTransferred);
+ winpr_HexDump("pipe.test", WLOG_DEBUG, lpReadBuffer, NumberOfBytesTransferred);
+
+ if (NumberOfBytesTransferred != PIPE_BUFFER_SIZE ||
+ memcmp(lpReadBuffer, CLIENT_MESSAGE, PIPE_BUFFER_SIZE))
+ {
+ printf("server: received unexpected data from client\n");
+ goto finish;
+ }
+
+ /* 5: write to named pipe */
+
+ nNumberOfBytesToWrite = PIPE_BUFFER_SIZE;
+ NumberOfBytesTransferred = 0;
+
+ fSuccess = WriteFile(hNamedPipe, SERVER_MESSAGE, nNumberOfBytesToWrite, NULL, &overlapped);
+
+ if (!fSuccess)
+ fSuccess = (GetLastError() == ERROR_IO_PENDING);
+
+ if (!fSuccess)
+ {
+ printf("server: NamedPipe WriteFile failure (initial): %" PRIu32 "\n", GetLastError());
+ goto finish;
+ }
+
+ status = WaitForSingleObject(hEvent, PIPE_TIMEOUT_MS);
+ if (status != WAIT_OBJECT_0)
+ {
+ printf("server: failed to wait for overlapped event (write): %" PRIu32 "\n", status);
+ goto finish;
+ }
+
+ fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, FALSE);
+ if (!fSuccess)
+ {
+ printf("server: NamedPipe WriteFile failure (final): %" PRIu32 "\n", GetLastError());
+ goto finish;
+ }
+
+ printf("server: WriteFile transferred %" PRIu32 " bytes:\n", NumberOfBytesTransferred);
+ // winpr_HexDump("pipe.test", WLOG_DEBUG, lpWriteBuffer, NumberOfBytesTransferred);
+
+ bServerSuccess = TRUE;
+ printf("server: finished successfully\n");
+
+finish:
+ CloseHandle(hNamedPipe);
+ CloseHandle(hEvent);
+ free(lpReadBuffer);
+ return 0;
+}
+
+int TestPipeCreateNamedPipeOverlapped(int argc, char* argv[])
+{
+ HANDLE ClientThread = NULL;
+ HANDLE ServerThread = NULL;
+ int result = -1;
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+ FillMemory(SERVER_MESSAGE, PIPE_BUFFER_SIZE, 0xAA);
+ FillMemory(CLIENT_MESSAGE, PIPE_BUFFER_SIZE, 0xBB);
+
+ if (!(serverReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
+ {
+ printf("CreateEvent failed: %" PRIu32 "\n", GetLastError());
+ goto out;
+ }
+ if (!(ClientThread = CreateThread(NULL, 0, named_pipe_client_thread, NULL, 0, NULL)))
+ {
+ printf("CreateThread (client) failed: %" PRIu32 "\n", GetLastError());
+ goto out;
+ }
+ if (!(ServerThread = CreateThread(NULL, 0, named_pipe_server_thread, NULL, 0, NULL)))
+ {
+ printf("CreateThread (server) failed: %" PRIu32 "\n", GetLastError());
+ goto out;
+ }
+
+ if (WAIT_OBJECT_0 != WaitForSingleObject(ClientThread, INFINITE))
+ {
+ printf("%s: Failed to wait for client thread: %" PRIu32 "\n", __func__, GetLastError());
+ goto out;
+ }
+ if (WAIT_OBJECT_0 != WaitForSingleObject(ServerThread, INFINITE))
+ {
+ printf("%s: Failed to wait for server thread: %" PRIu32 "\n", __func__, GetLastError());
+ goto out;
+ }
+
+ if (bClientSuccess && bServerSuccess)
+ result = 0;
+
+out:
+
+ if (ClientThread)
+ CloseHandle(ClientThread);
+ if (ServerThread)
+ CloseHandle(ServerThread);
+ if (serverReadyEvent)
+ CloseHandle(serverReadyEvent);
+
+#ifndef _WIN32
+ if (result == 0)
+ {
+ printf("%s: Error, this test is currently expected not to succeed on this platform.\n",
+ __func__);
+ result = -1;
+ }
+ else
+ {
+ printf("%s: This test is currently expected to fail on this platform.\n", __func__);
+ result = 0;
+ }
+#endif
+
+ return result;
+}