From 65bc944def059e175323b3f334227a5259cf8298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 22 Jul 2013 22:53:44 -0400 Subject: [PATCH] libwinpr-pipe: implement of more named pipes --- winpr/include/winpr/pipe.h | 8 ++ winpr/libwinpr/file/file.c | 71 +++++++++- winpr/libwinpr/pipe/pipe.c | 134 ++++++++++++++++-- winpr/libwinpr/pipe/pipe.h | 4 +- .../pipe/test/TestPipeCreateNamedPipe.c | 76 +++++++++- 5 files changed, 276 insertions(+), 17 deletions(-) diff --git a/winpr/include/winpr/pipe.h b/winpr/include/winpr/pipe.h index f5e8ecf16..188adf859 100644 --- a/winpr/include/winpr/pipe.h +++ b/winpr/include/winpr/pipe.h @@ -106,6 +106,14 @@ WINPR_API BOOL GetNamedPipeClientComputerNameW(HANDLE Pipe, LPCWSTR ClientComput #define GetNamedPipeClientComputerName GetNamedPipeClientComputerNameA #endif +/** + * Extended API + */ + +WINPR_API char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName); +WINPR_API char* GetNamedPipeUnixDomainSocketBaseFilePathA(); +WINPR_API char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName); + #ifdef __cplusplus } #endif diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index 13e1858cb..a5cbce27e 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -125,13 +125,21 @@ #ifndef _WIN32 +#ifdef HAVE_UNISTD_H +#include +#endif + #include #include #include #include #include #include + +#include +#include #include +#include #ifdef ANDROID #include @@ -146,15 +154,28 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { + char* name; + int status; HANDLE hNamedPipe; + unsigned long flags; + struct sockaddr_un s; WINPR_NAMED_PIPE* pNamedPipe; if (!lpFileName) return INVALID_HANDLE_VALUE; + name = GetNamedPipeNameWithoutPrefixA(lpFileName); + + if (!name) + return INVALID_HANDLE_VALUE; + + free(name); + pNamedPipe = (WINPR_NAMED_PIPE*) malloc(sizeof(WINPR_NAMED_PIPE)); hNamedPipe = (HANDLE) pNamedPipe; + WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE); + pNamedPipe->name = _strdup(lpFileName); pNamedPipe->dwOpenMode = 0; pNamedPipe->dwPipeMode = 0; @@ -163,9 +184,32 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, pNamedPipe->nInBufferSize = 0; pNamedPipe->nDefaultTimeOut = 0; - WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE); + pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName); + pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName); - return INVALID_HANDLE_VALUE; + pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0); + pNamedPipe->serverfd = -1; + + if (0) + { + flags = fcntl(pNamedPipe->clientfd, F_GETFL); + flags = flags | O_NONBLOCK; + fcntl(pNamedPipe->clientfd, F_SETFL, flags); + } + + ZeroMemory(&s, sizeof(struct sockaddr_un)); + s.sun_family = AF_UNIX; + strcpy(s.sun_path, pNamedPipe->lpFilePath); + + status = connect(pNamedPipe->clientfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un)); + + if (status != 0) + { + printf("connect: %d\n", status); + return INVALID_HANDLE_VALUE; + } + + return hNamedPipe; } HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, @@ -215,6 +259,17 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, status = nNumberOfBytesToRead; + if (pipe->clientfd != -1) + status = read(pipe->clientfd, lpBuffer, nNumberOfBytesToRead); + else + return FALSE; + + if (status < 0) + { + *lpNumberOfBytesRead = 0; + return FALSE; + } + *lpNumberOfBytesRead = status; return TRUE; @@ -240,7 +295,6 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, { ULONG Type; PVOID Object; - WINPR_PIPE* pipe; if (!winpr_Handle_GetInfo(hFile, &Type, &Object)) return FALSE; @@ -267,6 +321,17 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, status = nNumberOfBytesToWrite; + if (pipe->clientfd != -1) + status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite); + else + return FALSE; + + if (status < 0) + { + *lpNumberOfBytesWritten = 0; + return FALSE; + } + *lpNumberOfBytesWritten = status; return TRUE; diff --git a/winpr/libwinpr/pipe/pipe.c b/winpr/libwinpr/pipe/pipe.c index 5b3076f08..283fa04b4 100644 --- a/winpr/libwinpr/pipe/pipe.c +++ b/winpr/libwinpr/pipe/pipe.c @@ -35,6 +35,11 @@ #include "../handle/handle.h" +#include +#include +#include +#include + #include "pipe.h" /* @@ -80,20 +85,84 @@ BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpP #define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\" +char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName) +{ + char* lpFileName; + + if (!lpName) + return NULL; + + if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0) + return NULL; + + lpFileName = _strdup(&lpName[strlen(NAMED_PIPE_PREFIX_PATH)]); + + return lpFileName; +} + +char* GetNamedPipeUnixDomainSocketBaseFilePathA() +{ + char* lpTempPath; + char* lpPipePath; + + lpTempPath = GetKnownPath(KNOWN_PATH_TEMP); + lpPipePath = GetCombinedPath(lpTempPath, ".pipe"); + + free(lpTempPath); + + return lpPipePath; +} + +char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName) +{ + char* lpPipePath; + char* lpFileName; + char* lpFilePath; + + lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA(); + + lpFileName = GetNamedPipeNameWithoutPrefixA(lpName); + lpFilePath = GetCombinedPath(lpPipePath, (char*) lpFileName); + + free(lpPipePath); + free(lpFileName); + + return lpFilePath; +} + +int UnixChangeMode(const char* filename, int flags) +{ + mode_t fl = 0; + + fl |= (flags & 0x4000) ? S_ISUID : 0; + fl |= (flags & 0x2000) ? S_ISGID : 0; + fl |= (flags & 0x1000) ? S_ISVTX : 0; + fl |= (flags & 0x0400) ? S_IRUSR : 0; + fl |= (flags & 0x0200) ? S_IWUSR : 0; + fl |= (flags & 0x0100) ? S_IXUSR : 0; + fl |= (flags & 0x0040) ? S_IRGRP : 0; + fl |= (flags & 0x0020) ? S_IWGRP : 0; + fl |= (flags & 0x0010) ? S_IXGRP : 0; + fl |= (flags & 0x0004) ? S_IROTH : 0; + fl |= (flags & 0x0002) ? S_IWOTH : 0; + fl |= (flags & 0x0001) ? S_IXOTH : 0; + + return chmod(filename, fl); +} + HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes) { + int status; HANDLE hNamedPipe; - char* lpTempPath; char* lpPipePath; + unsigned long flags; + struct sockaddr_un s; WINPR_NAMED_PIPE* pNamedPipe; if (!lpName) return INVALID_HANDLE_VALUE; - if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0) - return INVALID_HANDLE_VALUE; - pNamedPipe = (WINPR_NAMED_PIPE*) malloc(sizeof(WINPR_NAMED_PIPE)); hNamedPipe = (HANDLE) pNamedPipe; @@ -107,16 +176,42 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD pNamedPipe->nInBufferSize = nInBufferSize; pNamedPipe->nDefaultTimeOut = nDefaultTimeOut; - lpTempPath = GetKnownPath(KNOWN_PATH_TEMP); - lpPipePath = GetCombinedPath(lpTempPath, ".pipe"); + pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName); + pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName); - pNamedPipe->lpFileName = _strdup(&lpName[strlen(NAMED_PIPE_PREFIX_PATH)]); - pNamedPipe->lpFilePath = GetCombinedPath(lpPipePath, (char*) pNamedPipe->lpFileName); + lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA(); + + if (!PathFileExistsA(lpPipePath)) + CreateDirectoryA(lpPipePath, 0); - free(lpTempPath); free(lpPipePath); - printf("CreateNamedPipe: %s\n", pNamedPipe->lpFilePath); + pNamedPipe->clientfd = -1; + pNamedPipe->serverfd = socket(PF_LOCAL, SOCK_STREAM, 0); + + if (0) + { + flags = fcntl(pNamedPipe->serverfd, F_GETFL); + flags = flags | O_NONBLOCK; + fcntl(pNamedPipe->serverfd, F_SETFL, flags); + } + + ZeroMemory(&s, sizeof(struct sockaddr_un)); + s.sun_family = AF_UNIX; + strcpy(s.sun_path, pNamedPipe->lpFilePath); + unlink(s.sun_path); + + status = bind(pNamedPipe->serverfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un)); + + if (status == 0) + { + status = listen(pNamedPipe->serverfd, 2); + + if (status == 0) + { + UnixChangeMode(pNamedPipe->lpFilePath, 0xFFFF); + } + } return hNamedPipe; } @@ -129,10 +224,29 @@ HANDLE CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWOR BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped) { + int status; + socklen_t length; + struct sockaddr_un s; WINPR_NAMED_PIPE* pNamedPipe; + if (!hNamedPipe) + return FALSE; + pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe; + length = sizeof(struct sockaddr_un); + ZeroMemory(&s, sizeof(struct sockaddr_un)); + + status = accept(pNamedPipe->serverfd, (struct sockaddr*) &s, &length); + + if (status < 0) + { + printf("accept: %d\n", status); + return FALSE; + } + + pNamedPipe->clientfd = status; + return TRUE; } diff --git a/winpr/libwinpr/pipe/pipe.h b/winpr/libwinpr/pipe/pipe.h index 87880f3b7..2c326a771 100644 --- a/winpr/libwinpr/pipe/pipe.h +++ b/winpr/libwinpr/pipe/pipe.h @@ -38,7 +38,9 @@ struct winpr_named_pipe { WINPR_HANDLE_DEF(); - int fd; + int clientfd; + int serverfd; + const char* name; const char* lpFileName; const char* lpFilePath; diff --git a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c index 93b1df00a..3ecb13eed 100644 --- a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c +++ b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c @@ -5,19 +5,78 @@ #include #include #include +#include #include #include #define PIPE_BUFFER_SIZE 32 +static HANDLE ReadyEvent; + static LPTSTR lpszPipeName = _T("\\\\.\\pipe\\winpr_test_pipe"); static void* named_pipe_client_thread(void* arg) { HANDLE hNamedPipe; + BYTE* lpReadBuffer; + BYTE* lpWriteBuffer; + BOOL fSuccess = FALSE; + DWORD nNumberOfBytesToRead; + DWORD nNumberOfBytesToWrite; + DWORD lpNumberOfBytesRead; + DWORD lpNumberOfBytesWritten; + + WaitForSingleObject(ReadyEvent, INFINITE); hNamedPipe = CreateFile(lpszPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (!hNamedPipe) + { + printf("Named Pipe CreateFile failure: NULL handle\n"); + return NULL; + } + + if (hNamedPipe == INVALID_HANDLE_VALUE) + { + printf("Named Pipe CreateFile failure: INVALID_HANDLE_VALUE\n"); + return NULL; + } + + lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + + lpNumberOfBytesWritten = 0; + nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; + + FillMemory(lpWriteBuffer, 0xAB, PIPE_BUFFER_SIZE); + + fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL); + + if (!fSuccess || (lpNumberOfBytesWritten == 0)) + { + printf("Client NamedPipe WriteFile failure\n"); + return NULL; + } + + lpNumberOfBytesRead = 0; + nNumberOfBytesToRead = PIPE_BUFFER_SIZE; + + ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); + + fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL); + + if (!fSuccess || (lpNumberOfBytesRead == 0)) + { + printf("Client NamedPipe ReadFile failure\n"); + return NULL; + } + + printf("Client ReadFile (%d):\n", lpNumberOfBytesRead); + winpr_HexDump(lpReadBuffer, lpNumberOfBytesRead); + + free(lpReadBuffer); + free(lpWriteBuffer); + return NULL; } @@ -49,6 +108,8 @@ static void* named_pipe_server_thread(void* arg) return NULL; } + SetEvent(ReadyEvent); + fConnected = ConnectNamedPipe(hNamedPipe, NULL); if (!fConnected) @@ -66,22 +127,29 @@ static void* named_pipe_server_thread(void* arg) lpNumberOfBytesRead = 0; nNumberOfBytesToRead = PIPE_BUFFER_SIZE; + ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); + fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL); if (!fSuccess || (lpNumberOfBytesRead == 0)) { - printf("NamedPipe ReadFile failure\n"); + printf("Server NamedPipe ReadFile failure\n"); return NULL; } + printf("Server ReadFile (%d):\n", lpNumberOfBytesRead); + winpr_HexDump(lpReadBuffer, lpNumberOfBytesRead); + lpNumberOfBytesWritten = 0; nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; + FillMemory(lpWriteBuffer, 0xCD, PIPE_BUFFER_SIZE); + fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL); - if (!fSuccess || (lpNumberOfBytesRead == 0)) + if (!fSuccess || (lpNumberOfBytesWritten == 0)) { - printf("NamedPipe WriteFile failure\n"); + printf("Server NamedPipe WriteFile failure\n"); return NULL; } @@ -96,6 +164,8 @@ int TestPipeCreateNamedPipe(int argc, char* argv[]) HANDLE ClientThread; HANDLE ServerThread; + ReadyEvent = CreateEvent(NULL, TRUE, FALSE, 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);