Blame winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c

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