204ae5462a
The used method for initalizing and registering the handle creators had certain disadvantages like that it was necessary to have the creators initialized before the first call to CreateFile. In case of comm it wouldn't have been possible to open an comm port without calling any other call related function first. Now the handle creators are initialized the first time CreateFile is called. This way it is also possible to ensure a certain order of the handler invocations. This commit also splits out the client side named pipe code from the generic file handling (now called generic.c instead of file.c) and uses the new handle creator infrastructure to register.
464 lines
12 KiB
C
464 lines
12 KiB
C
|
|
#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");
|
|
|
|
BOOL testFailed = FALSE;
|
|
|
|
static void* named_pipe_client_thread(void* arg)
|
|
{
|
|
HANDLE hNamedPipe = NULL;
|
|
BYTE* lpReadBuffer = NULL;
|
|
BYTE* lpWriteBuffer = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
DWORD nNumberOfBytesToRead;
|
|
DWORD nNumberOfBytesToWrite;
|
|
DWORD lpNumberOfBytesRead;
|
|
DWORD lpNumberOfBytesWritten;
|
|
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", __FUNCTION__);
|
|
goto out;
|
|
}
|
|
|
|
if (!(lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE)))
|
|
{
|
|
printf("%s: Error allocating read buffer\n", __FUNCTION__);
|
|
goto out;
|
|
}
|
|
|
|
if (!(lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE)))
|
|
{
|
|
printf("%s: Error allocating write buffer\n", __FUNCTION__);
|
|
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", __FUNCTION__);
|
|
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", __FUNCTION__);
|
|
goto out;
|
|
}
|
|
|
|
printf("Client ReadFile (%d):\n", lpNumberOfBytesRead);
|
|
winpr_HexDump("pipe.test", WLOG_DEBUG, lpReadBuffer, lpNumberOfBytesRead);
|
|
fSuccess = TRUE;
|
|
out:
|
|
free(lpReadBuffer);
|
|
free(lpWriteBuffer);
|
|
CloseHandle(hNamedPipe);
|
|
|
|
if (!fSuccess)
|
|
testFailed = TRUE;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void* named_pipe_server_thread(void* arg)
|
|
{
|
|
HANDLE hNamedPipe = NULL;
|
|
BYTE* lpReadBuffer = NULL;
|
|
BYTE* lpWriteBuffer = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
BOOL fConnected = FALSE;
|
|
DWORD nNumberOfBytesToRead;
|
|
DWORD nNumberOfBytesToWrite;
|
|
DWORD lpNumberOfBytesRead;
|
|
DWORD lpNumberOfBytesWritten;
|
|
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", __FUNCTION__);
|
|
goto out;
|
|
}
|
|
|
|
if (hNamedPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
printf("%s: CreateNamedPipe failure: INVALID_HANDLE_VALUE\n", __FUNCTION__);
|
|
goto out;
|
|
}
|
|
|
|
SetEvent(ReadyEvent);
|
|
fConnected = ConnectNamedPipe(hNamedPipe, NULL);
|
|
|
|
if (!fConnected)
|
|
fConnected = (GetLastError() == ERROR_PIPE_CONNECTED);
|
|
|
|
if (!fConnected)
|
|
{
|
|
printf("%s: ConnectNamedPipe failure\n", __FUNCTION__);
|
|
goto out;
|
|
}
|
|
|
|
if (!(lpReadBuffer = (BYTE*) calloc(1, PIPE_BUFFER_SIZE)))
|
|
{
|
|
printf("%s: Error allocating read buffer\n", __FUNCTION__);
|
|
goto out;
|
|
}
|
|
|
|
if (!(lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE)))
|
|
{
|
|
printf("%s: Error allocating write buffer\n", __FUNCTION__);
|
|
goto out;
|
|
}
|
|
|
|
lpNumberOfBytesRead = 0;
|
|
nNumberOfBytesToRead = PIPE_BUFFER_SIZE;
|
|
|
|
if (!ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL) ||
|
|
lpNumberOfBytesRead != nNumberOfBytesToRead)
|
|
{
|
|
printf("%s: Server NamedPipe ReadFile failure\n", __FUNCTION__);
|
|
goto out;
|
|
}
|
|
|
|
printf("Server ReadFile (%d):\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", __FUNCTION__);
|
|
goto out;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
out:
|
|
free(lpReadBuffer);
|
|
free(lpWriteBuffer);
|
|
CloseHandle(hNamedPipe);
|
|
|
|
if (!fSuccess)
|
|
testFailed = TRUE;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#define TESTNUMPIPESST 16
|
|
static void* named_pipe_single_thread(void* arg)
|
|
{
|
|
HANDLE servers[TESTNUMPIPESST];
|
|
HANDLE clients[TESTNUMPIPESST];
|
|
char sndbuf[PIPE_BUFFER_SIZE];
|
|
char rcvbuf[PIPE_BUFFER_SIZE];
|
|
DWORD dwRead;
|
|
DWORD dwWritten;
|
|
int i;
|
|
int numPipes;
|
|
BOOL bSuccess = FALSE;
|
|
#ifndef _WIN32
|
|
WINPR_NAMED_PIPE* p;
|
|
#endif
|
|
numPipes = TESTNUMPIPESST;
|
|
memset(servers, 0, sizeof(servers));
|
|
memset(clients, 0, sizeof(clients));
|
|
WaitForSingleObject(ReadyEvent, INFINITE);
|
|
|
|
for (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", __FUNCTION__, i);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
|
|
for (i = 0; i < numPipes; i++)
|
|
{
|
|
p = (WINPR_NAMED_PIPE*)servers[i];
|
|
|
|
if (strcmp(lpszPipeNameSt, p->name))
|
|
{
|
|
printf("%s: Pipe name mismatch for pipe #%d ([%s] instead of [%s])\n",
|
|
__FUNCTION__, i, p->name, lpszPipeNameSt);
|
|
goto out;
|
|
}
|
|
|
|
if (p->clientfd != -1)
|
|
{
|
|
printf("%s: Unexpected client fd value for pipe #%d (%d instead of -1)\n",
|
|
__FUNCTION__, i, p->clientfd);
|
|
goto out;
|
|
}
|
|
|
|
if (p->serverfd < 1)
|
|
{
|
|
printf("%s: Unexpected server fd value for pipe #%d (%d is not > 0)\n",
|
|
__FUNCTION__, i, p->serverfd);
|
|
goto out;
|
|
}
|
|
|
|
if (p->ServerMode == FALSE)
|
|
{
|
|
printf("%s: Unexpected ServerMode value for pipe #%d (0 instead of 1)\n",
|
|
__FUNCTION__, i);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
for (i = 0; i < numPipes; i++)
|
|
{
|
|
if ((clients[i] = CreateFile(lpszPipeNameSt, GENERIC_READ | GENERIC_WRITE,
|
|
0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
|
|
{
|
|
printf("%s: CreateFile #%d failed\n", __FUNCTION__, i);
|
|
goto out;
|
|
}
|
|
|
|
if (!ConnectNamedPipe(servers[i], NULL))
|
|
{
|
|
printf("%s: ConnectNamedPipe #%d failed\n", __FUNCTION__, i);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
|
|
for (i = 0; i < numPipes; i++)
|
|
{
|
|
p = servers[i];
|
|
|
|
if (p->clientfd < 1)
|
|
{
|
|
printf("%s: Unexpected client fd value for pipe #%d (%d is not > 0)\n",
|
|
__FUNCTION__, i, p->clientfd);
|
|
goto out;
|
|
}
|
|
|
|
if (p->ServerMode)
|
|
{
|
|
printf("%s: Unexpected ServerMode value for pipe #%d (1 instead of 0)\n",
|
|
__FUNCTION__, i);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < numPipes; i++)
|
|
{
|
|
/* Test writing from clients to servers */
|
|
ZeroMemory(sndbuf, sizeof(sndbuf));
|
|
ZeroMemory(rcvbuf, sizeof(rcvbuf));
|
|
sprintf_s(sndbuf, sizeof(sndbuf), "CLIENT->SERVER ON PIPE #%05d", i);
|
|
p = servers[i];
|
|
|
|
if (!WriteFile(clients[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL) ||
|
|
dwWritten != sizeof(sndbuf))
|
|
{
|
|
printf("%s: Error writing to client end of pipe #%d\n", __FUNCTION__, i);
|
|
goto out;
|
|
}
|
|
|
|
if (!ReadFile(servers[i], rcvbuf, dwWritten, &dwRead, NULL) ||
|
|
dwRead != dwWritten)
|
|
{
|
|
printf("%s: Error reading on server end of pipe #%d\n", __FUNCTION__, i);
|
|
goto out;
|
|
}
|
|
|
|
if (memcmp(sndbuf, rcvbuf, sizeof(sndbuf)))
|
|
{
|
|
printf("%s: Error data read on server end of pipe #%d is corrupted\n",
|
|
__FUNCTION__, i);
|
|
goto out;
|
|
}
|
|
|
|
/* Test writing from servers to clients */
|
|
ZeroMemory(sndbuf, sizeof(sndbuf));
|
|
ZeroMemory(rcvbuf, sizeof(rcvbuf));
|
|
sprintf_s(sndbuf, sizeof(sndbuf), "SERVER->CLIENT ON PIPE #%05d", i);
|
|
p = servers[i];
|
|
|
|
if (!WriteFile(servers[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL) ||
|
|
dwWritten != sizeof(sndbuf))
|
|
{
|
|
printf("%s: Error writing to server end of pipe #%d\n", __FUNCTION__, i);
|
|
goto out;
|
|
}
|
|
|
|
if (!ReadFile(clients[i], rcvbuf, dwWritten, &dwRead, NULL) ||
|
|
dwRead != dwWritten)
|
|
{
|
|
printf("%s: Error reading on client end of pipe #%d\n", __FUNCTION__, i);
|
|
goto out;
|
|
}
|
|
|
|
if (memcmp(sndbuf, rcvbuf, sizeof(sndbuf)))
|
|
{
|
|
printf("%s: Error data read on client end of pipe #%d is corrupted\n",
|
|
__FUNCTION__, i);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
/**
|
|
* After DisconnectNamedPipe on server end
|
|
* ReadFile/WriteFile must fail on client end
|
|
*/
|
|
i = numPipes - 1;
|
|
DisconnectNamedPipe(servers[i]);
|
|
|
|
if (ReadFile(clients[i], rcvbuf, sizeof(rcvbuf), &dwRead, NULL))
|
|
{
|
|
printf("%s: Error ReadFile on client should have failed after DisconnectNamedPipe on server\n", __FUNCTION__);
|
|
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", __FUNCTION__);
|
|
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]);
|
|
|
|
if (ReadFile(clients[i], rcvbuf, sizeof(rcvbuf), &dwRead, NULL))
|
|
{
|
|
printf("%s: Error ReadFile on client end should have failed after CloseHandle on server\n", __FUNCTION__);
|
|
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", __FUNCTION__);
|
|
goto out;
|
|
}
|
|
|
|
CloseHandle(clients[i]);
|
|
numPipes--;
|
|
/**
|
|
* After CloseHandle on client end
|
|
* ReadFile/WriteFile must fail on server end
|
|
*/
|
|
i = numPipes - 1;
|
|
CloseHandle(clients[i]);
|
|
|
|
if (ReadFile(servers[i], rcvbuf, sizeof(rcvbuf), &dwRead, NULL))
|
|
{
|
|
printf("%s: Error ReadFile on server end should have failed after CloseHandle on client\n", __FUNCTION__);
|
|
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", __FUNCTION__);
|
|
goto out;
|
|
}
|
|
|
|
DisconnectNamedPipe(servers[i]);
|
|
CloseHandle(servers[i]);
|
|
numPipes--;
|
|
|
|
/* Close all remaining pipes */
|
|
for (i = 0; i < numPipes; i++)
|
|
{
|
|
DisconnectNamedPipe(servers[i]);
|
|
CloseHandle(servers[i]);
|
|
CloseHandle(clients[i]);
|
|
}
|
|
|
|
numPipes = 0;
|
|
bSuccess = TRUE;
|
|
out:
|
|
|
|
if (!bSuccess)
|
|
testFailed = TRUE;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
int TestPipeCreateNamedPipe(int argc, char* argv[])
|
|
{
|
|
HANDLE SingleThread;
|
|
HANDLE ClientThread;
|
|
HANDLE ServerThread;
|
|
#ifndef _WIN32
|
|
signal(SIGPIPE, SIG_IGN);
|
|
#endif
|
|
if (!(ReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
|
{
|
|
printf("CreateEvent failure: (%d)\n", GetLastError());
|
|
return -1;
|
|
}
|
|
if (!(SingleThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_single_thread, NULL, 0, NULL)))
|
|
{
|
|
printf("CreateThread (SingleThread) failure: (%d)\n", GetLastError());
|
|
return -1;
|
|
}
|
|
if (!(ClientThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_client_thread, NULL, 0, NULL)))
|
|
{
|
|
printf("CreateThread (ClientThread) failure: (%d)\n", GetLastError());
|
|
return -1;
|
|
}
|
|
if (!(ServerThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_server_thread, NULL, 0, NULL)))
|
|
{
|
|
printf("CreateThread (ServerThread) failure: (%d)\n", GetLastError());
|
|
return -1;
|
|
}
|
|
WaitForSingleObject(SingleThread, INFINITE);
|
|
WaitForSingleObject(ClientThread, INFINITE);
|
|
WaitForSingleObject(ServerThread, INFINITE);
|
|
CloseHandle(SingleThread);
|
|
CloseHandle(ClientThread);
|
|
CloseHandle(ServerThread);
|
|
return testFailed;
|
|
}
|
|
|