Modified named pipes to support multiple instances (i.e., multiple calls to CreateNamedPipe with the same pipe name).

This commit is contained in:
Mike McDonald 2014-04-18 13:16:42 -04:00
parent 38c7a38141
commit 5e09e37d42
3 changed files with 135 additions and 47 deletions

View File

@ -22,6 +22,7 @@
#endif
#include <winpr/handle.h>
#include <winpr/collections.h>
#ifndef _WIN32
@ -36,6 +37,8 @@
#include "../handle/handle.h"
extern wArrayList* WinPR_NamedPipeBaseInstances;
BOOL CloseHandle(HANDLE hObject)
{
ULONG Type;
@ -167,16 +170,28 @@ BOOL CloseHandle(HANDLE hObject)
pipe = (WINPR_NAMED_PIPE*) Object;
if (pipe->clientfd != -1)
close(pipe->clientfd);
if (--pipe->dwRefCount == 0)
{
ArrayList_Lock(WinPR_NamedPipeBaseInstances);
ArrayList_Remove(WinPR_NamedPipeBaseInstances, pipe);
ArrayList_Unlock(WinPR_NamedPipeBaseInstances);
if (pipe->serverfd != -1)
close(pipe->serverfd);
if (pipe->pBaseNamedPipe)
{
CloseHandle((HANDLE) pipe->pBaseNamedPipe);
}
free((char *)pipe->lpFileName);
free((char *)pipe->lpFilePath);
free((char *)pipe->name);
free(pipe);
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;
}

View File

@ -25,6 +25,7 @@
#include <winpr/path.h>
#include <winpr/synch.h>
#include <winpr/handle.h>
#include <winpr/collections.h>
#include <winpr/pipe.h>
@ -44,6 +45,34 @@
#include "pipe.h"
/*
* 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.
*
* 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.
*/
wArrayList* WinPR_NamedPipeBaseInstances;
static void InitWinPRPipeModule()
{
static BOOL bInitialized = FALSE;
if (bInitialized) return;
WinPR_NamedPipeBaseInstances = ArrayList_New(TRUE);
bInitialized = TRUE;
}
/*
* Unnamed pipe
*/
@ -96,15 +125,34 @@ BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpP
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;
char* lpPipePath;
struct sockaddr_un s;
WINPR_NAMED_PIPE* pNamedPipe;
WINPR_NAMED_PIPE* pBaseNamedPipe;
if (!lpName)
return INVALID_HANDLE_VALUE;
InitWinPRPipeModule();
/* Find the base named pipe instance (i.e., the first instance). */
pBaseNamedPipe = NULL;
ArrayList_Lock(WinPR_NamedPipeBaseInstances);
for (index = 0; index < ArrayList_Count(WinPR_NamedPipeBaseInstances); index++)
{
WINPR_NAMED_PIPE* p = (WINPR_NAMED_PIPE*) ArrayList_GetItem(WinPR_NamedPipeBaseInstances, index);
if (strcmp(p->name, lpName) == 0)
{
pBaseNamedPipe = p;
break;
}
}
ArrayList_Unlock(WinPR_NamedPipeBaseInstances);
pNamedPipe = (WINPR_NAMED_PIPE*) malloc(sizeof(WINPR_NAMED_PIPE));
hNamedPipe = (HANDLE) pNamedPipe;
@ -122,54 +170,75 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD
pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName);
lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
if (!PathFileExistsA(lpPipePath))
{
CreateDirectoryA(lpPipePath, 0);
UnixChangeFileMode(lpPipePath, 0xFFFF);
}
free(lpPipePath);
if (PathFileExistsA(pNamedPipe->lpFilePath))
{
DeleteFileA(pNamedPipe->lpFilePath);
}
pNamedPipe->clientfd = -1;
pNamedPipe->ServerMode = TRUE;
pNamedPipe->serverfd = socket(AF_UNIX, SOCK_STREAM, 0);
pNamedPipe->pBaseNamedPipe = pBaseNamedPipe;
pNamedPipe->dwRefCount = 1;
if (pNamedPipe->serverfd == -1)
/* If this is the first instance of the named pipe... */
if (pBaseNamedPipe == NULL)
{
fprintf(stderr, "CreateNamedPipeA: socket error, %s\n", strerror(errno));
return INVALID_HANDLE_VALUE;
/* Create the UNIX domain socket and start listening. */
lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
if (!PathFileExistsA(lpPipePath))
{
CreateDirectoryA(lpPipePath, 0);
UnixChangeFileMode(lpPipePath, 0xFFFF);
}
free(lpPipePath);
if (PathFileExistsA(pNamedPipe->lpFilePath))
{
DeleteFileA(pNamedPipe->lpFilePath);
}
pNamedPipe->serverfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (pNamedPipe->serverfd == -1)
{
fprintf(stderr, "CreateNamedPipeA: socket error, %s\n", strerror(errno));
return INVALID_HANDLE_VALUE;
}
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)
{
fprintf(stderr, "CreateNamedPipeA: bind error, %s\n", strerror(errno));
return INVALID_HANDLE_VALUE;
}
status = listen(pNamedPipe->serverfd, 2);
if (status != 0)
{
fprintf(stderr, "CreateNamedPipeA: listen error, %s\n", strerror(errno));
return INVALID_HANDLE_VALUE;
}
UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF);
/* Add the named pipe to the list of base named pipe instances. */
ArrayList_Lock(WinPR_NamedPipeBaseInstances);
ArrayList_Add(WinPR_NamedPipeBaseInstances, pNamedPipe);
ArrayList_Unlock(WinPR_NamedPipeBaseInstances);
}
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)
else
{
fprintf(stderr, "CreateNamedPipeA: bind error, %s\n", strerror(errno));
return INVALID_HANDLE_VALUE;
/* Duplicate the file handle for the UNIX domain socket in the first instance. */
pNamedPipe->serverfd = dup(pBaseNamedPipe->serverfd);
/* Update the reference count in the base named pipe instance. */
pBaseNamedPipe->dwRefCount++;
}
status = listen(pNamedPipe->serverfd, 2);
if (status != 0)
{
fprintf(stderr, "CreateNamedPipeA: listen error, %s\n", strerror(errno));
return INVALID_HANDLE_VALUE;
}
UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF);
if (dwOpenMode & FILE_FLAG_OVERLAPPED)
{
#if 0

View File

@ -38,6 +38,10 @@ struct winpr_named_pipe
{
WINPR_HANDLE_DEF();
struct winpr_named_pipe* pBaseNamedPipe;
DWORD dwRefCount;
int clientfd;
int serverfd;