libwinpr-pipe: implement of more named pipes
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Tue, 23 Jul 2013 02:53:44 +0000 (22:53 -0400)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Tue, 23 Jul 2013 02:53:44 +0000 (22:53 -0400)
winpr/include/winpr/pipe.h
winpr/libwinpr/file/file.c
winpr/libwinpr/pipe/pipe.c
winpr/libwinpr/pipe/pipe.h
winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c

index f5e8ecf..188adf8 100644 (file)
@@ -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
index 13e1858..a5cbce2 100644 (file)
 
 #ifndef _WIN32
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 #include <time.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <dirent.h>
+
+#include <fcntl.h>
+#include <sys/un.h>
 #include <sys/stat.h>
+#include <sys/socket.h>
 
 #ifdef ANDROID
 #include <sys/vfs.h>
 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;
index 5b3076f..283fa04 100644 (file)
 
 #include "../handle/handle.h"
 
+#include <fcntl.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
 #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;
 }
 
index 87880f3..2c326a7 100644 (file)
@@ -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;
index 93b1df0..3ecb13e 100644 (file)
@@ -5,19 +5,78 @@
 #include <winpr/file.h>
 #include <winpr/tchar.h>
 #include <winpr/winpr.h>
+#include <winpr/print.h>
 #include <winpr/synch.h>
 #include <winpr/thread.h>
 
 #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);