diff options
Diffstat (limited to 'winpr/libwinpr/file/namedPipeClient.c')
-rw-r--r-- | winpr/libwinpr/file/namedPipeClient.c | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/winpr/libwinpr/file/namedPipeClient.c b/winpr/libwinpr/file/namedPipeClient.c new file mode 100644 index 0000000..fbfeb35 --- /dev/null +++ b/winpr/libwinpr/file/namedPipeClient.c @@ -0,0 +1,305 @@ +/** + * WinPR: Windows Portable Runtime + * File Functions + * + * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 bernhard.miklautz@thincast.com + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <winpr/config.h> + +#include <winpr/crt.h> +#include <winpr/path.h> +#include <winpr/file.h> + +#ifdef WINPR_HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "../log.h" +#define TAG WINPR_TAG("file") + +#ifndef _WIN32 + +#ifdef ANDROID +#include <sys/vfs.h> +#else +#include <sys/statvfs.h> +#endif + +#include "../handle/handle.h" + +#include "../pipe/pipe.h" + +static HANDLE_CREATOR _NamedPipeClientHandleCreator; + +static BOOL NamedPipeClientIsHandled(HANDLE handle) +{ + return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_NAMED_PIPE, TRUE); +} + +static BOOL NamedPipeClientCloseHandle(HANDLE handle) +{ + WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)handle; + + if (!NamedPipeClientIsHandled(handle)) + return FALSE; + + if (pNamedPipe->clientfd != -1) + { + // WLOG_DBG(TAG, "closing clientfd %d", pNamedPipe->clientfd); + close(pNamedPipe->clientfd); + } + + if (pNamedPipe->serverfd != -1) + { + // WLOG_DBG(TAG, "closing serverfd %d", pNamedPipe->serverfd); + close(pNamedPipe->serverfd); + } + + if (pNamedPipe->pfnUnrefNamedPipe) + pNamedPipe->pfnUnrefNamedPipe(pNamedPipe); + + free(pNamedPipe->lpFileName); + free(pNamedPipe->lpFilePath); + free(pNamedPipe->name); + free(pNamedPipe); + return TRUE; +} + +static int NamedPipeClientGetFd(HANDLE handle) +{ + WINPR_NAMED_PIPE* file = (WINPR_NAMED_PIPE*)handle; + + if (!NamedPipeClientIsHandled(handle)) + return -1; + + if (file->ServerMode) + return file->serverfd; + else + return file->clientfd; +} + +static HANDLE_OPS ops = { + NamedPipeClientIsHandled, + NamedPipeClientCloseHandle, + NamedPipeClientGetFd, + NULL, /* CleanupHandle */ + NamedPipeRead, + NULL, /* FileReadEx */ + NULL, /* FileReadScatter */ + NamedPipeWrite, + NULL, /* FileWriteEx */ + NULL, /* FileWriteGather */ + NULL, /* FileGetFileSize */ + NULL, /* FlushFileBuffers */ + NULL, /* FileSetEndOfFile */ + NULL, /* FileSetFilePointer */ + NULL, /* SetFilePointerEx */ + NULL, /* FileLockFile */ + NULL, /* FileLockFileEx */ + NULL, /* FileUnlockFile */ + NULL, /* FileUnlockFileEx */ + NULL, /* SetFileTime */ + NULL, /* FileGetFileInformationByHandle */ +}; + +static HANDLE NamedPipeClientCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, + DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile) +{ + char* name = NULL; + int status = 0; + HANDLE hNamedPipe = NULL; + struct sockaddr_un s = { 0 }; + WINPR_NAMED_PIPE* pNamedPipe = NULL; + + if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED) + { + WLog_ERR(TAG, "WinPR does not support the FILE_FLAG_OVERLAPPED flag"); + SetLastError(ERROR_NOT_SUPPORTED); + return INVALID_HANDLE_VALUE; + } + + if (!lpFileName) + return INVALID_HANDLE_VALUE; + + if (!IsNamedPipeFileNameA(lpFileName)) + return INVALID_HANDLE_VALUE; + + name = GetNamedPipeNameWithoutPrefixA(lpFileName); + + if (!name) + return INVALID_HANDLE_VALUE; + + free(name); + pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1, sizeof(WINPR_NAMED_PIPE)); + + if (!pNamedPipe) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return INVALID_HANDLE_VALUE; + } + + hNamedPipe = (HANDLE)pNamedPipe; + WINPR_HANDLE_SET_TYPE_AND_MODE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE, WINPR_FD_READ); + pNamedPipe->name = _strdup(lpFileName); + + if (!pNamedPipe->name) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + free(pNamedPipe); + return INVALID_HANDLE_VALUE; + } + + pNamedPipe->dwOpenMode = 0; + pNamedPipe->dwPipeMode = 0; + pNamedPipe->nMaxInstances = 0; + pNamedPipe->nOutBufferSize = 0; + pNamedPipe->nInBufferSize = 0; + pNamedPipe->nDefaultTimeOut = 0; + pNamedPipe->dwFlagsAndAttributes = dwFlagsAndAttributes; + pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName); + + if (!pNamedPipe->lpFileName) + { + free((void*)pNamedPipe->name); + free(pNamedPipe); + return INVALID_HANDLE_VALUE; + } + + pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName); + + if (!pNamedPipe->lpFilePath) + { + free((void*)pNamedPipe->lpFileName); + free((void*)pNamedPipe->name); + free(pNamedPipe); + return INVALID_HANDLE_VALUE; + } + + pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0); + pNamedPipe->serverfd = -1; + pNamedPipe->ServerMode = FALSE; + s.sun_family = AF_UNIX; + sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path), "%s", pNamedPipe->lpFilePath); + status = connect(pNamedPipe->clientfd, (struct sockaddr*)&s, sizeof(struct sockaddr_un)); + pNamedPipe->common.ops = &ops; + + if (status != 0) + { + close(pNamedPipe->clientfd); + free((char*)pNamedPipe->name); + free((char*)pNamedPipe->lpFileName); + free((char*)pNamedPipe->lpFilePath); + free(pNamedPipe); + return INVALID_HANDLE_VALUE; + } + + if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED) + { +#if 0 + int flags = fcntl(pNamedPipe->clientfd, F_GETFL); + + if (flags != -1) + fcntl(pNamedPipe->clientfd, F_SETFL, flags | O_NONBLOCK); + +#endif + } + + return hNamedPipe; +} + +extern HANDLE_CREATOR* GetNamedPipeClientHandleCreator(void); +HANDLE_CREATOR* GetNamedPipeClientHandleCreator(void) +{ + _NamedPipeClientHandleCreator.IsHandled = IsNamedPipeFileNameA; + _NamedPipeClientHandleCreator.CreateFileA = NamedPipeClientCreateFileA; + return &_NamedPipeClientHandleCreator; +} + +#endif + +/* Extended API */ + +#define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\" + +BOOL IsNamedPipeFileNameA(LPCSTR lpName) +{ + if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0) + return FALSE; + + return TRUE; +} + +char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName) +{ + char* lpFileName = NULL; + + if (!lpName) + return NULL; + + if (!IsNamedPipeFileNameA(lpName)) + return NULL; + + lpFileName = _strdup(&lpName[strnlen(NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH))]); + return lpFileName; +} + +char* GetNamedPipeUnixDomainSocketBaseFilePathA(void) +{ + char* lpTempPath = NULL; + char* lpPipePath = NULL; + lpTempPath = GetKnownPath(KNOWN_PATH_TEMP); + + if (!lpTempPath) + return NULL; + + lpPipePath = GetCombinedPath(lpTempPath, ".pipe"); + free(lpTempPath); + return lpPipePath; +} + +char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName) +{ + char* lpPipePath = NULL; + char* lpFileName = NULL; + char* lpFilePath = NULL; + lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA(); + lpFileName = GetNamedPipeNameWithoutPrefixA(lpName); + lpFilePath = GetCombinedPath(lpPipePath, (char*)lpFileName); + free(lpPipePath); + free(lpFileName); + return lpFilePath; +} + +int GetNamePipeFileDescriptor(HANDLE hNamedPipe) +{ +#ifndef _WIN32 + int fd = 0; + WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe; + + if (!NamedPipeClientIsHandled(hNamedPipe)) + return -1; + + fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd; + return fd; +#else + return -1; +#endif +} |