winpr: rewrite named pipe sharing
Since commit 5e09e37d42
was basically unfixable,
here is a slightly different approach that should hopefully solve all
discovered issues and race conditions.
This commit is contained in:
parent
ea0a2a32ad
commit
aa2efaf573
@ -361,8 +361,6 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
|
||||
if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
|
||||
{
|
||||
io_status = nNumberOfBytesToRead;
|
||||
|
||||
if (pipe->clientfd == -1)
|
||||
return FALSE;
|
||||
|
||||
@ -374,9 +372,9 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
{
|
||||
case ECONNRESET:
|
||||
SetLastError(ERROR_BROKEN_PIPE);
|
||||
io_status = 0;
|
||||
break;
|
||||
}
|
||||
status = FALSE;
|
||||
}
|
||||
else if (io_status < 0)
|
||||
{
|
||||
|
@ -165,37 +165,7 @@ BOOL CloseHandle(HANDLE hObject)
|
||||
}
|
||||
else if (Type == HANDLE_TYPE_NAMED_PIPE)
|
||||
{
|
||||
WINPR_NAMED_PIPE* pipe;
|
||||
|
||||
pipe = (WINPR_NAMED_PIPE*) Object;
|
||||
|
||||
if (pipe->ServerMode)
|
||||
{
|
||||
assert(pipe->dwRefCount);
|
||||
|
||||
if (--pipe->dwRefCount == 0)
|
||||
{
|
||||
pipe->pfnRemoveBaseNamedPipeFromList(pipe);
|
||||
|
||||
if (pipe->pBaseNamedPipe)
|
||||
{
|
||||
CloseHandle((HANDLE) pipe->pBaseNamedPipe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pipe->clientfd != -1)
|
||||
close(pipe->clientfd);
|
||||
|
||||
if (pipe->serverfd != -1)
|
||||
close(pipe->serverfd);
|
||||
|
||||
free((char *)pipe->lpFileName);
|
||||
free((char *)pipe->lpFilePath);
|
||||
free((char *)pipe->name);
|
||||
free(pipe);
|
||||
|
||||
return TRUE;
|
||||
return winpr_destroy_named_pipe((WINPR_NAMED_PIPE*) Object);
|
||||
}
|
||||
else if (Type == HANDLE_TYPE_ACCESS_TOKEN)
|
||||
{
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define WINPR_HANDLE_PRIVATE_H
|
||||
|
||||
#include <winpr/handle.h>
|
||||
#include <winpr/file.h>
|
||||
|
||||
#define HANDLE_TYPE_NONE 0
|
||||
#define HANDLE_TYPE_PROCESS 1
|
||||
@ -52,7 +53,7 @@ static inline BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, PVOID* pObj
|
||||
{
|
||||
WINPR_HANDLE* wHandle;
|
||||
|
||||
if (handle == NULL)
|
||||
if (handle == NULL || handle == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
wHandle = (WINPR_HANDLE*) handle;
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "pipe.h"
|
||||
|
||||
@ -48,34 +49,32 @@
|
||||
* Since the WinPR implementation of named pipes makes use of UNIX domain
|
||||
* sockets, it is not possible to bind the same name more than once (i.e.,
|
||||
* SO_REUSEADDR does not work with UNIX domain sockets). As a result, the
|
||||
* first call to CreateNamedPipe must create the UNIX domain socket and
|
||||
* subsequent calls to CreateNamedPipe will reference the first named pipe
|
||||
* handle and duplicate the socket descriptor.
|
||||
* first call to CreateNamedPipe with name n creates a "shared" UNIX domain
|
||||
* socket descriptor that gets duplicated via dup() for the first and all
|
||||
* subsequent calls to CreateNamedPipe with name n.
|
||||
*
|
||||
* The following array keeps track of the named pipe handles for the first
|
||||
* instance. If multiple instances are created, subsequent instances store
|
||||
* a pointer to the first instance and a reference count is maintained. When
|
||||
* the last instance is closed, the named pipe handle is removed from the list.
|
||||
* The following array keeps track of the references to the shared socked
|
||||
* descriptors. If an entry's reference count is zero the base socket
|
||||
* descriptor gets closed and the entry is removed from the list.
|
||||
*/
|
||||
|
||||
static wArrayList* g_BaseNamedPipeList = NULL;
|
||||
static wArrayList* g_NamedPipeServerSockets = NULL;
|
||||
|
||||
static BOOL g_Initialized = FALSE;
|
||||
typedef struct _NamedPipeServerSocketEntry
|
||||
{
|
||||
char* name;
|
||||
int serverfd;
|
||||
int references;
|
||||
} NamedPipeServerSocketEntry;
|
||||
|
||||
static void InitWinPRPipeModule()
|
||||
{
|
||||
if (g_Initialized)
|
||||
if (g_NamedPipeServerSockets)
|
||||
return;
|
||||
|
||||
g_BaseNamedPipeList = ArrayList_New(TRUE);
|
||||
|
||||
g_Initialized = TRUE;
|
||||
g_NamedPipeServerSockets = ArrayList_New(FALSE);
|
||||
}
|
||||
|
||||
void WinPR_RemoveBaseNamedPipeFromList(WINPR_NAMED_PIPE* pNamedPipe)
|
||||
{
|
||||
ArrayList_Remove(g_BaseNamedPipeList, pNamedPipe);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unnamed pipe
|
||||
@ -126,48 +125,88 @@ BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpP
|
||||
* Named pipe
|
||||
*/
|
||||
|
||||
BOOL winpr_destroy_named_pipe(WINPR_NAMED_PIPE* pNamedPipe)
|
||||
{
|
||||
if (!pNamedPipe)
|
||||
return FALSE;
|
||||
|
||||
assert(pNamedPipe->name);
|
||||
|
||||
//fprintf(stderr, "%s: %p (%s)\n", __FUNCTION__, pNamedPipe, pNamedPipe->name);
|
||||
|
||||
if (pNamedPipe->clientfd != -1) {
|
||||
//fprintf(stderr, "%s: closing clientfd %d\n", __FUNCTION__, pNamedPipe->clientfd);
|
||||
close(pNamedPipe->clientfd);
|
||||
}
|
||||
|
||||
if (pNamedPipe->serverfd != -1) {
|
||||
//fprintf(stderr, "%s: closing serverfd %d\n", __FUNCTION__, pNamedPipe->serverfd);
|
||||
close(pNamedPipe->serverfd);
|
||||
}
|
||||
|
||||
if (pNamedPipe->bDuplicatedServerDescriptor)
|
||||
{
|
||||
int index;
|
||||
NamedPipeServerSocketEntry *baseSocket;
|
||||
ArrayList_Lock(g_NamedPipeServerSockets);
|
||||
for (index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
|
||||
{
|
||||
baseSocket = (NamedPipeServerSocketEntry*) ArrayList_GetItem(
|
||||
g_NamedPipeServerSockets, index);
|
||||
assert(baseSocket->name);
|
||||
if (!strcmp(baseSocket->name, pNamedPipe->name))
|
||||
{
|
||||
assert(baseSocket->references > 0);
|
||||
assert(baseSocket->serverfd != -1);
|
||||
if (--baseSocket->references == 0)
|
||||
{
|
||||
//fprintf(stderr, "%s: removing shared server socked resource\n", __FUNCTION__);
|
||||
//fprintf(stderr, "%s: closing shared serverfd %d\n", __FUNCTION__, baseSocket->serverfd);
|
||||
ArrayList_Remove(g_NamedPipeServerSockets, baseSocket);
|
||||
close(baseSocket->serverfd);
|
||||
free(baseSocket->name);
|
||||
free(baseSocket);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ArrayList_Unlock(g_NamedPipeServerSockets);
|
||||
}
|
||||
|
||||
free((void*)pNamedPipe->lpFileName);
|
||||
free((void*)pNamedPipe->lpFilePath);
|
||||
free((void*)pNamedPipe->name);
|
||||
free(pNamedPipe);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
|
||||
DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
||||
{
|
||||
int index;
|
||||
int status;
|
||||
HANDLE hNamedPipe;
|
||||
HANDLE hNamedPipe = INVALID_HANDLE_VALUE;
|
||||
char* lpPipePath;
|
||||
struct sockaddr_un s;
|
||||
WINPR_NAMED_PIPE* pNamedPipe;
|
||||
WINPR_NAMED_PIPE* pBaseNamedPipe;
|
||||
WINPR_NAMED_PIPE* pNamedPipe = NULL;
|
||||
int serverfd = -1;
|
||||
NamedPipeServerSocketEntry *baseSocket = NULL;
|
||||
|
||||
if (!lpName)
|
||||
return INVALID_HANDLE_VALUE;
|
||||
|
||||
InitWinPRPipeModule();
|
||||
|
||||
/* Find the base named pipe instance (i.e., the first instance). */
|
||||
pBaseNamedPipe = NULL;
|
||||
|
||||
ArrayList_Lock(g_BaseNamedPipeList);
|
||||
|
||||
for (index = 0; index < ArrayList_Count(g_BaseNamedPipeList); index++)
|
||||
{
|
||||
WINPR_NAMED_PIPE* p = (WINPR_NAMED_PIPE*) ArrayList_GetItem(g_BaseNamedPipeList, index);
|
||||
|
||||
if (strcmp(p->name, lpName) == 0)
|
||||
{
|
||||
pBaseNamedPipe = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList_Unlock(g_BaseNamedPipeList);
|
||||
|
||||
pNamedPipe = (WINPR_NAMED_PIPE*) malloc(sizeof(WINPR_NAMED_PIPE));
|
||||
hNamedPipe = (HANDLE) pNamedPipe;
|
||||
pNamedPipe = (WINPR_NAMED_PIPE*) calloc(1, sizeof(WINPR_NAMED_PIPE));
|
||||
|
||||
WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE);
|
||||
|
||||
pNamedPipe->pfnRemoveBaseNamedPipeFromList = WinPR_RemoveBaseNamedPipeFromList;
|
||||
|
||||
pNamedPipe->name = _strdup(lpName);
|
||||
if (!(pNamedPipe->name = _strdup(lpName)))
|
||||
goto out;
|
||||
if (!(pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName)))
|
||||
goto out;
|
||||
if (!(pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName)))
|
||||
goto out;
|
||||
pNamedPipe->dwOpenMode = dwOpenMode;
|
||||
pNamedPipe->dwPipeMode = dwPipeMode;
|
||||
pNamedPipe->nMaxInstances = nMaxInstances;
|
||||
@ -176,20 +215,29 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD
|
||||
pNamedPipe->nDefaultTimeOut = nDefaultTimeOut;
|
||||
pNamedPipe->dwFlagsAndAttributes = dwOpenMode;
|
||||
|
||||
pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
|
||||
pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName);
|
||||
|
||||
pNamedPipe->clientfd = -1;
|
||||
pNamedPipe->ServerMode = TRUE;
|
||||
|
||||
pNamedPipe->pBaseNamedPipe = pBaseNamedPipe;
|
||||
pNamedPipe->dwRefCount = 1;
|
||||
ArrayList_Lock(g_NamedPipeServerSockets);
|
||||
|
||||
for (index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
|
||||
{
|
||||
baseSocket = (NamedPipeServerSocketEntry*) ArrayList_GetItem(
|
||||
g_NamedPipeServerSockets, index);
|
||||
if (!strcmp(baseSocket->name, lpName))
|
||||
{
|
||||
serverfd = baseSocket->serverfd;
|
||||
//fprintf(stderr, "using shared socked resource for pipe %p (%s)\n", pNamedPipe, lpName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is the first instance of the named pipe... */
|
||||
if (pBaseNamedPipe == NULL)
|
||||
if (serverfd == -1)
|
||||
{
|
||||
/* Create the UNIX domain socket and start listening. */
|
||||
lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
|
||||
if (!(lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA()))
|
||||
goto out;
|
||||
|
||||
if (!PathFileExistsA(lpPipePath))
|
||||
{
|
||||
@ -204,48 +252,50 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD
|
||||
DeleteFileA(pNamedPipe->lpFilePath);
|
||||
}
|
||||
|
||||
pNamedPipe->serverfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (pNamedPipe->serverfd == -1)
|
||||
if ((serverfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||
{
|
||||
fprintf(stderr, "CreateNamedPipeA: socket error, %s\n", strerror(errno));
|
||||
goto err_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ZeroMemory(&s, sizeof(struct sockaddr_un));
|
||||
s.sun_family = AF_UNIX;
|
||||
strcpy(s.sun_path, pNamedPipe->lpFilePath);
|
||||
|
||||
status = bind(pNamedPipe->serverfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un));
|
||||
|
||||
if (status != 0)
|
||||
if (bind(serverfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un)) == -1)
|
||||
{
|
||||
fprintf(stderr, "CreateNamedPipeA: bind error, %s\n", strerror(errno));
|
||||
goto err_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = listen(pNamedPipe->serverfd, 2);
|
||||
|
||||
if (status != 0)
|
||||
if (listen(serverfd, 2) == -1)
|
||||
{
|
||||
fprintf(stderr, "CreateNamedPipeA: listen error, %s\n", strerror(errno));
|
||||
goto err_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF);
|
||||
|
||||
/* Add the named pipe to the list of base named pipe instances. */
|
||||
ArrayList_Add(g_BaseNamedPipeList, pNamedPipe);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Duplicate the file handle for the UNIX domain socket in the first instance. */
|
||||
pNamedPipe->serverfd = dup(pBaseNamedPipe->serverfd);
|
||||
if (!(baseSocket = (NamedPipeServerSocketEntry *) malloc(sizeof(NamedPipeServerSocketEntry))))
|
||||
goto out;
|
||||
if (!(baseSocket->name = _strdup(lpName)))
|
||||
{
|
||||
free(baseSocket);
|
||||
goto out;
|
||||
}
|
||||
baseSocket->serverfd = serverfd;
|
||||
baseSocket->references = 0;
|
||||
ArrayList_Add(g_NamedPipeServerSockets, baseSocket);
|
||||
//fprintf(stderr, "created shared socked resource for pipe %p (%s). base serverfd = %d\n", pNamedPipe, lpName, serverfd);
|
||||
|
||||
/* Update the reference count in the base named pipe instance. */
|
||||
pBaseNamedPipe->dwRefCount++;
|
||||
}
|
||||
|
||||
pNamedPipe->serverfd = dup(baseSocket->serverfd);
|
||||
//fprintf(stderr, "using serverfd %d (duplicated from %d)\n", pNamedPipe->serverfd, baseSocket->serverfd);
|
||||
|
||||
pNamedPipe->bDuplicatedServerDescriptor = TRUE;
|
||||
baseSocket->references++;
|
||||
|
||||
if (dwOpenMode & FILE_FLAG_OVERLAPPED)
|
||||
{
|
||||
#if 0
|
||||
@ -256,15 +306,23 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD
|
||||
#endif
|
||||
}
|
||||
|
||||
return hNamedPipe;
|
||||
hNamedPipe = (HANDLE) pNamedPipe;
|
||||
|
||||
err_out:
|
||||
if (pNamedPipe) {
|
||||
if (pNamedPipe->serverfd != -1)
|
||||
close(pNamedPipe->serverfd);
|
||||
free(pNamedPipe);
|
||||
out:
|
||||
if (hNamedPipe == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (pNamedPipe)
|
||||
{
|
||||
free((void*)pNamedPipe->name);
|
||||
free((void*)pNamedPipe->lpFileName);
|
||||
free((void*)pNamedPipe->lpFilePath);
|
||||
free(pNamedPipe);
|
||||
}
|
||||
if (serverfd != -1)
|
||||
close(serverfd);
|
||||
}
|
||||
return INVALID_HANDLE_VALUE;
|
||||
ArrayList_Unlock(g_NamedPipeServerSockets);
|
||||
return hNamedPipe;
|
||||
}
|
||||
|
||||
HANDLE CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
|
||||
|
@ -37,8 +37,6 @@ typedef struct winpr_pipe WINPR_PIPE;
|
||||
|
||||
typedef struct winpr_named_pipe WINPR_NAMED_PIPE;
|
||||
|
||||
typedef void ( * fnRemoveBaseNamedPipeFromList)(WINPR_NAMED_PIPE* pNamedPipe);
|
||||
|
||||
struct winpr_named_pipe
|
||||
{
|
||||
WINPR_HANDLE_DEF();
|
||||
@ -60,13 +58,11 @@ struct winpr_named_pipe
|
||||
DWORD dwFlagsAndAttributes;
|
||||
LPOVERLAPPED lpOverlapped;
|
||||
|
||||
fnRemoveBaseNamedPipeFromList pfnRemoveBaseNamedPipeFromList;
|
||||
|
||||
WINPR_NAMED_PIPE* pBaseNamedPipe;
|
||||
DWORD dwRefCount;
|
||||
|
||||
BOOL bDuplicatedServerDescriptor;
|
||||
};
|
||||
|
||||
BOOL winpr_destroy_named_pipe(WINPR_NAMED_PIPE* pNamedPipe);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_PIPE_PRIVATE_H */
|
||||
|
@ -8,18 +8,25 @@
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#ifndef _WIN32
|
||||
#include <signal.h>
|
||||
#endif
|
||||
#include "../pipe.h"
|
||||
|
||||
#define PIPE_BUFFER_SIZE 32
|
||||
|
||||
static HANDLE ReadyEvent;
|
||||
|
||||
static LPTSTR lpszPipeName = _T("\\\\.\\pipe\\winpr_test_pipe");
|
||||
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;
|
||||
BYTE* lpReadBuffer;
|
||||
BYTE* lpWriteBuffer;
|
||||
HANDLE hNamedPipe = NULL;
|
||||
BYTE* lpReadBuffer = NULL;
|
||||
BYTE* lpWriteBuffer = NULL;
|
||||
BOOL fSuccess = FALSE;
|
||||
DWORD nNumberOfBytesToRead;
|
||||
DWORD nNumberOfBytesToWrite;
|
||||
@ -28,39 +35,42 @@ static void* named_pipe_client_thread(void* arg)
|
||||
|
||||
WaitForSingleObject(ReadyEvent, INFINITE);
|
||||
|
||||
hNamedPipe = CreateFile(lpszPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
hNamedPipe = CreateFile(lpszPipeNameMt, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if (!hNamedPipe)
|
||||
{
|
||||
printf("Named Pipe CreateFile failure: NULL handle\n");
|
||||
return NULL;
|
||||
printf("%s:Named Pipe CreateFile failure: NULL handle\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hNamedPipe == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
printf("Named Pipe CreateFile failure: INVALID_HANDLE_VALUE\n");
|
||||
return NULL;
|
||||
printf("%s: Named Pipe CreateFile failure: INVALID_HANDLE_VALUE\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE);
|
||||
lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE);
|
||||
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);
|
||||
|
||||
fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL);
|
||||
|
||||
if (!fSuccess || (lpNumberOfBytesWritten == 0))
|
||||
if (!WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL) ||
|
||||
lpNumberOfBytesWritten != nNumberOfBytesToWrite)
|
||||
{
|
||||
printf("Client NamedPipe WriteFile failure\n");
|
||||
|
||||
free(lpReadBuffer);
|
||||
free(lpWriteBuffer);
|
||||
|
||||
CloseHandle(hNamedPipe);
|
||||
return NULL;
|
||||
printf("%s: Client NamedPipe WriteFile failure\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lpNumberOfBytesRead = 0;
|
||||
@ -68,34 +78,31 @@ static void* named_pipe_client_thread(void* arg)
|
||||
|
||||
ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE);
|
||||
|
||||
fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL);
|
||||
|
||||
if (!fSuccess || (lpNumberOfBytesRead == 0))
|
||||
if (!ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL) ||
|
||||
lpNumberOfBytesRead != nNumberOfBytesToRead)
|
||||
{
|
||||
printf("Client NamedPipe ReadFile failure\n");
|
||||
free(lpReadBuffer);
|
||||
free(lpWriteBuffer);
|
||||
|
||||
CloseHandle(hNamedPipe);
|
||||
return NULL;
|
||||
printf("%s: Client NamedPipe ReadFile failure\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Client ReadFile (%d):\n", lpNumberOfBytesRead);
|
||||
winpr_HexDump(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;
|
||||
BYTE* lpReadBuffer;
|
||||
BYTE* lpWriteBuffer;
|
||||
HANDLE hNamedPipe = NULL;
|
||||
BYTE* lpReadBuffer = NULL;
|
||||
BYTE* lpWriteBuffer = NULL;
|
||||
BOOL fSuccess = FALSE;
|
||||
BOOL fConnected = FALSE;
|
||||
DWORD nNumberOfBytesToRead;
|
||||
@ -103,20 +110,20 @@ static void* named_pipe_server_thread(void* arg)
|
||||
DWORD lpNumberOfBytesRead;
|
||||
DWORD lpNumberOfBytesWritten;
|
||||
|
||||
hNamedPipe = CreateNamedPipe(lpszPipeName,
|
||||
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("CreateNamedPipe failure: NULL handle\n");
|
||||
return NULL;
|
||||
printf("%s: CreateNamedPipe failure: NULL handle\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hNamedPipe == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
printf("CreateNamedPipe failure: INVALID_HANDLE_VALUE\n");
|
||||
return NULL;
|
||||
printf("%s: CreateNamedPipe failure: INVALID_HANDLE_VALUE\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
SetEvent(ReadyEvent);
|
||||
@ -128,30 +135,32 @@ static void* named_pipe_server_thread(void* arg)
|
||||
|
||||
if (!fConnected)
|
||||
{
|
||||
printf("ConnectNamedPipe failure\n");
|
||||
|
||||
CloseHandle(hNamedPipe);
|
||||
return NULL;
|
||||
printf("%s: ConnectNamedPipe failure\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE);
|
||||
lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE);
|
||||
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;
|
||||
}
|
||||
|
||||
lpNumberOfBytesRead = 0;
|
||||
nNumberOfBytesToRead = PIPE_BUFFER_SIZE;
|
||||
|
||||
ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE);
|
||||
|
||||
fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL);
|
||||
|
||||
if (!fSuccess || (lpNumberOfBytesRead == 0))
|
||||
if (!ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL) ||
|
||||
lpNumberOfBytesRead != nNumberOfBytesToRead)
|
||||
{
|
||||
printf("Server NamedPipe ReadFile failure\n");
|
||||
free(lpReadBuffer);
|
||||
free(lpWriteBuffer);
|
||||
|
||||
CloseHandle(hNamedPipe);
|
||||
return NULL;
|
||||
printf("%s: Server NamedPipe ReadFile failure\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Server ReadFile (%d):\n", lpNumberOfBytesRead);
|
||||
@ -162,42 +171,299 @@ static void* named_pipe_server_thread(void* arg)
|
||||
|
||||
FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x45);
|
||||
|
||||
fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL);
|
||||
|
||||
if (!fSuccess || (lpNumberOfBytesWritten == 0))
|
||||
if (!WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL) ||
|
||||
lpNumberOfBytesWritten != nNumberOfBytesToWrite)
|
||||
{
|
||||
printf("Server NamedPipe WriteFile failure\n");
|
||||
free(lpReadBuffer);
|
||||
free(lpWriteBuffer);
|
||||
|
||||
CloseHandle(hNamedPipe);
|
||||
return NULL;
|
||||
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];
|
||||
WINPR_NAMED_PIPE* p;
|
||||
char sndbuf[PIPE_BUFFER_SIZE];
|
||||
char rcvbuf[PIPE_BUFFER_SIZE];
|
||||
DWORD dwRead;
|
||||
DWORD dwWritten;
|
||||
int i;
|
||||
int numPipes;
|
||||
BOOL bSuccess = FALSE;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < numPipes; i++)
|
||||
{
|
||||
if (!(clients[i] = CreateFile(lpszPipeNameSt, GENERIC_READ | GENERIC_WRITE,
|
||||
0, NULL, OPEN_EXISTING, 0, NULL)))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 == TRUE)
|
||||
{
|
||||
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 */
|
||||
|
||||
memset(sndbuf, 0, sizeof(sndbuf));
|
||||
memset(rcvbuf, 0, sizeof(rcvbuf));
|
||||
snprintf(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 */
|
||||
|
||||
memset(sndbuf, 0, sizeof(sndbuf));
|
||||
memset(rcvbuf, 0, sizeof(rcvbuf));
|
||||
snprintf(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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(clients[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
|
||||
|
||||
ReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
SingleThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_single_thread, NULL, 0, NULL);
|
||||
ClientThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_client_thread, NULL, 0, NULL);
|
||||
ServerThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_server_thread, NULL, 0, NULL);
|
||||
|
||||
WaitForSingleObject(SingleThread, INFINITE);
|
||||
WaitForSingleObject(ClientThread, INFINITE);
|
||||
WaitForSingleObject(ServerThread, INFINITE);
|
||||
|
||||
CloseHandle(SingleThread);
|
||||
CloseHandle(ClientThread);
|
||||
CloseHandle(ServerThread);
|
||||
|
||||
return 0;
|
||||
return testFailed;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user