diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index b721d4295..e2d7871c0 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -385,6 +385,9 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) error_handle: + /* FIXME: find out whether it's required or not to get + * BytesReturned == OutputBufferLength when + * CommDeviceIoControl returns FALSE */ assert(OutputBufferLength == BytesReturned); Stream_Write_UINT32(irp->output, BytesReturned); /* OutputBufferLength (4 bytes) */ diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index ef5c4dd54..b54c46e63 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -314,13 +314,13 @@ WINPR_API BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecu /* Extra Functions */ -typedef BOOL (*pcIsHandled)(LPCSTR lpFileName); +typedef BOOL (*pcIsFileHandled)(LPCSTR lpFileName); typedef HANDLE (*pcCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); typedef struct _HANDLE_CREATOR { - pcIsHandled IsHandled; + pcIsFileHandled IsHandled; pcCreateFileA CreateFileA; } HANDLE_CREATOR, *PHANDLE_CREATOR, *LPHANDLE_CREATOR; diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index b99d53255..dea659353 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -755,6 +755,7 @@ typedef struct _COMM_DEVICE static COMM_DEVICE **_CommDevices = NULL; static HANDLE_CREATOR *_CommHandleCreator = NULL; +static HANDLE_CLOSE_CB *_CommHandleCloseCb = NULL; static pthread_once_t _CommInitialized = PTHREAD_ONCE_INIT; static void _CommInit() @@ -763,6 +764,7 @@ static void _CommInit() assert(_CommDevices == NULL); assert(_CommHandleCreator == NULL); + assert(_CommHandleCloseCb == NULL); _CommDevices = (COMM_DEVICE**)calloc(COMM_DEVICE_MAX+1, sizeof(COMM_DEVICE*)); @@ -775,8 +777,18 @@ static void _CommInit() RegisterHandleCreator(_CommHandleCreator); } + _CommHandleCloseCb = (HANDLE_CLOSE_CB*)malloc(sizeof(HANDLE_CLOSE_CB)); + if (_CommHandleCloseCb) + { + _CommHandleCloseCb->IsHandled = CommIsHandled; + _CommHandleCloseCb->CloseHandle = CommCloseHandle; + + RegisterHandleCloseCb(_CommHandleCloseCb); + } + assert(_CommDevices != NULL); assert(_CommHandleCreator != NULL); + assert(_CommHandleCloseCb != NULL); } @@ -1232,4 +1244,69 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare } +BOOL CommIsHandled(HANDLE handle) +{ + WINPR_COMM *pComm; + + pComm = (WINPR_COMM*)handle; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + return TRUE; +} + + +BOOL CommCloseHandle(HANDLE handle) +{ + WINPR_COMM *pComm; + + pComm = (WINPR_COMM*)handle; + + if (!pComm || pComm->Type != HANDLE_TYPE_COMM) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (pComm->PendingEvents & SERIAL_EV_FREERDP_WAITING) + { + ULONG WaitMask = 0; + DWORD BytesReturned = 0; + + /* ensures to gracefully stop the WAIT_ON_MASK's loop */ + if (!CommDeviceIoControl(handle, IOCTL_SERIAL_SET_WAIT_MASK, &WaitMask, sizeof(ULONG), NULL, 0, &BytesReturned, NULL)) + { + DEBUG_WARN("failure to WAIT_ON_MASK's loop!"); + } + } + + DeleteCriticalSection(&pComm->ReadLock); + DeleteCriticalSection(&pComm->WriteLock); + DeleteCriticalSection(&pComm->EventsLock); + + if (pComm->fd > 0) + close(pComm->fd); + + if (pComm->fd_write > 0) + close(pComm->fd_write); + + if (pComm->fd_write_event > 0) + close(pComm->fd_write_event); + + if (pComm->fd_read > 0) + close(pComm->fd_read); + + if (pComm->fd_read_event > 0) + close(pComm->fd_read_event); + + free(pComm); + + return TRUE; +} + + #endif /* _WIN32 */ diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index b2ee8d4ac..763a566d2 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -74,6 +74,9 @@ typedef struct winpr_comm WINPR_COMM; #define FREERDP_PURGE_TXABORT 0x00000001 /* abort pending transmission */ #define FREERDP_PURGE_RXABORT 0x00000002 /* abort pending reception */ +BOOL CommIsHandled(HANDLE handle); +BOOL CommCloseHandle(HANDLE handle); + #endif /* _WIN32 */ #endif /* WINPR_COMM_PRIVATE_H */ diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 3770a6f7b..9572bbd51 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -462,7 +462,7 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l if (!pServerSerialDriver->wait_on_mask(pComm, pOutputMask)) { - *lpBytesReturned = sizeof(ULONG); /* TMP: TODO: all lpBytesReturned values to be reviewed on error */ + *lpBytesReturned = sizeof(ULONG); return FALSE; } @@ -670,6 +670,12 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe result = _CommDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); + if (lpBytesReturned && *lpBytesReturned != nOutBufferSize) + { + /* This might be a hint for a bug, especially when result==TRUE */ + DEBUG_WARN("lpBytesReturned=%d and nOutBufferSize=%d are different!", *lpBytesReturned, nOutBufferSize); + } + if (pComm->permissive) { if (!result) @@ -722,7 +728,7 @@ int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *te if (memcmp(¤tState, termios_p, sizeof(struct termios)) != 0) { DEBUG_WARN("Failure: all termios parameters are still not set on a second attempt"); - return -1; /* TMP: double-check whether some parameters can differ anyway */ + return -1; } } diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index 0cee4b391..57cf98547 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -25,6 +25,9 @@ #ifndef _WIN32 +#include +#include + #include "../synch/synch.h" #include "../thread/thread.h" #include "../pipe/pipe.h" @@ -37,14 +40,83 @@ #include "../handle/handle.h" +/* _HandleCreators is a NULL-terminated array with a maximun of HANDLE_CREATOR_MAX HANDLE_CREATOR */ +#define HANDLE_CLOSE_CB_MAX 128 +static HANDLE_CLOSE_CB **_HandleCloseCbs = NULL; + +static pthread_once_t _HandleCloseCbsInitialized = PTHREAD_ONCE_INIT; +static void _HandleCloseCbsInit() +{ + /* NB: error management to be done outside of this function */ + + assert(_HandleCloseCbs == NULL); + + _HandleCloseCbs = (HANDLE_CLOSE_CB**)calloc(HANDLE_CLOSE_CB_MAX+1, sizeof(HANDLE_CLOSE_CB*)); + + assert(_HandleCloseCbs != NULL); +} + +/** + * Returns TRUE on success, FALSE otherwise. + */ +BOOL RegisterHandleCloseCb(HANDLE_CLOSE_CB *pHandleCloseCb) +{ + int i; + + if (pthread_once(&_HandleCloseCbsInitialized, _HandleCloseCbsInit) != 0) + { + return FALSE; + } + + if (_HandleCloseCbs == NULL) + { + return FALSE; + } + + + for (i=0; iIsHandled(hObject)) + { + return close_cb->CloseHandle(hObject); + } + } + + if (Type == HANDLE_TYPE_THREAD) { WINPR_THREAD* thread; @@ -197,43 +269,6 @@ BOOL CloseHandle(HANDLE hObject) return TRUE; } - else if (Type == HANDLE_TYPE_COMM) - { - WINPR_COMM* comm; - - comm = (WINPR_COMM*) Object; - - /* NOTE: This is up to the caller of CloseHandle() to - * ensure there is no pending request. Sending - * SERIAL_EV_FREERDP_STOP anyway. Remove this code if - * you think otherwise. */ - EnterCriticalSection(&comm->EventsLock); - comm->PendingEvents |= SERIAL_EV_FREERDP_STOP; - LeaveCriticalSection(&comm->EventsLock); - - DeleteCriticalSection(&comm->ReadLock); - DeleteCriticalSection(&comm->WriteLock); - DeleteCriticalSection(&comm->EventsLock); - - if (comm->fd > 0) - close(comm->fd); - - if (comm->fd_write > 0) - close(comm->fd_write); - - if (comm->fd_write_event > 0) - close(comm->fd_write_event); - - if (comm->fd_read > 0) - close(comm->fd_read); - - if (comm->fd_read_event > 0) - close(comm->fd_read_event); - - free(comm); - - return TRUE; - } return FALSE; } diff --git a/winpr/libwinpr/handle/handle.h b/winpr/libwinpr/handle/handle.h index e5b6bae72..6a2630822 100644 --- a/winpr/libwinpr/handle/handle.h +++ b/winpr/libwinpr/handle/handle.h @@ -64,4 +64,16 @@ static inline BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, PVOID* pObj return TRUE; } + +typedef BOOL (*pcIsHandled)(HANDLE handle); +typedef BOOL (*pcCloseHandle)(HANDLE handle); + +typedef struct _HANDLE_CLOSE_CB +{ + pcIsHandled IsHandled; + pcCloseHandle CloseHandle; +} HANDLE_CLOSE_CB; + +BOOL RegisterHandleCloseCb(HANDLE_CLOSE_CB *pHandleClose); + #endif /* WINPR_HANDLE_PRIVATE_H */