diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 0d0d9a2dc..5b99996a6 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -774,6 +774,7 @@ static void serial_irp_request(DEVICE* device, IRP* irp) MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL); } + static void serial_free(DEVICE* device) { SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index bbbe78f86..3b1e34b92 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -428,7 +428,7 @@ WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD #define IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040 #define IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044 #define IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 -/* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */ +#define IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 #define IOCTL_SERIAL_PURGE 0x001B004C #define IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 #define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 @@ -494,7 +494,7 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = {IOCTL_SERIAL_GET_WAIT_MASK, "IOCTL_SERIAL_GET_WAIT_MASK"}, {IOCTL_SERIAL_SET_WAIT_MASK, "IOCTL_SERIAL_SET_WAIT_MASK"}, {IOCTL_SERIAL_WAIT_ON_MASK, "IOCTL_SERIAL_WAIT_ON_MASK"}, - // {IOCTL_SERIAL_IMMEDIATE_CHAR, "IOCTL_SERIAL_IMMEDIATE_CHAR"}, + {IOCTL_SERIAL_IMMEDIATE_CHAR, "IOCTL_SERIAL_IMMEDIATE_CHAR"}, {IOCTL_SERIAL_PURGE, "IOCTL_SERIAL_PURGE"}, {IOCTL_SERIAL_GET_HANDFLOW, "IOCTL_SERIAL_GET_HANDFLOW"}, {IOCTL_SERIAL_SET_HANDFLOW, "IOCTL_SERIAL_SET_HANDFLOW"}, diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index cbff32d55..0fe1ba1ef 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -1140,6 +1140,8 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare goto error_handle; } + InitializeCriticalSection(&pComm->ReadLock); + pComm->fd_write = open(devicePath, O_WRONLY | O_NOCTTY | O_NONBLOCK); if (pComm->fd_write < 0) { @@ -1156,6 +1158,9 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare goto error_handle; } + InitializeCriticalSection(&pComm->WriteLock); + + /* TMP: TODO: FIXME: this information is at least needed for * get/set baud functions. Is it possible to pull this * information? Could be a command line argument. diff --git a/winpr/libwinpr/comm/comm.h b/winpr/libwinpr/comm/comm.h index 950ef19a1..5cfb3f2d2 100644 --- a/winpr/libwinpr/comm/comm.h +++ b/winpr/libwinpr/comm/comm.h @@ -50,9 +50,11 @@ struct winpr_comm int fd_read; int fd_read_event; /* as of today, only used by _purge() */ + CRITICAL_SECTION ReadLock; int fd_write; int fd_write_event; /* as of today, only used by _purge() */ + CRITICAL_SECTION WriteLock; /* permissive mode on errors if TRUE (default is FALSE). * diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c index bfce8d3e5..53fe67135 100644 --- a/winpr/libwinpr/comm/comm_io.c +++ b/winpr/libwinpr/comm/comm_io.c @@ -95,48 +95,50 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, struct timeval tmaxTimeout, *pTmaxTimeout; struct termios currentTermios; + EnterCriticalSection(&pComm->ReadLock); /* KISSer by the function's beginning */ + if (hDevice == INVALID_HANDLE_VALUE) { SetLastError(ERROR_INVALID_HANDLE); - return FALSE; + goto return_false; } if (!pComm || pComm->Type != HANDLE_TYPE_COMM) { SetLastError(ERROR_INVALID_HANDLE); - return FALSE; + goto return_false; } if (lpOverlapped != NULL) { SetLastError(ERROR_NOT_SUPPORTED); - return FALSE; + goto return_false; } if (lpNumberOfBytesRead == NULL) { SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */ - return FALSE; + goto return_false; } *lpNumberOfBytesRead = 0; /* will be ajusted if required ... */ if (nNumberOfBytesToRead <= 0) /* N */ { - return TRUE; /* FIXME: or FALSE? */ + goto return_true; /* FIXME: or FALSE? */ } if (tcgetattr(pComm->fd, ¤tTermios) < 0) { SetLastError(ERROR_IO_DEVICE); - return FALSE; + goto return_false; } if (currentTermios.c_lflag & ICANON) { DEBUG_WARN("Canonical mode not supported"); /* the timeout could not be set */ SetLastError(ERROR_NOT_SUPPORTED); - return FALSE; + goto return_false; } /* http://msdn.microsoft.com/en-us/library/hh439614%28v=vs.85%29.aspx @@ -162,7 +164,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, { DEBUG_WARN("ReadIntervalTimeout and ReadTotalTimeoutConstant cannot be both set to MAXULONG"); SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; + goto return_false; } /* VMIN */ @@ -214,7 +216,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, { DEBUG_WARN("CommReadFile failure, could not apply new timeout values: VMIN=%u, VTIME=%u", vmin, vtime); SetLastError(ERROR_IO_DEVICE); - return FALSE; + goto return_false; } } @@ -252,7 +254,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, { DEBUG_WARN("select() failure, errno=[%d] %s\n", errno, strerror(errno)); SetLastError(ERROR_IO_DEVICE); - return FALSE; + goto return_false; } if (nbFds == 0) @@ -260,7 +262,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, /* timeout */ SetLastError(ERROR_TIMEOUT); - return FALSE; + goto return_false; } @@ -280,7 +282,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, else { DEBUG_WARN("unexpected error on reading fd_read_event, errno=[%d] %s\n", errno, strerror(errno)); - /* FIXME: return FALSE ? */ + /* FIXME: goto return_false ? */ } assert(errno == EAGAIN); @@ -289,7 +291,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, if (event == FREERDP_PURGE_RXABORT) { SetLastError(ERROR_CANCELLED); - return FALSE; + goto return_false; } assert(event == FREERDP_PURGE_RXABORT); /* no other expected event so far */ @@ -310,18 +312,18 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, if (errno == EAGAIN) { /* keep on */ - return TRUE; /* expect a read-loop to be implemented on the server side */ + goto return_true; /* expect a read-loop to be implemented on the server side */ } else if (errno == EBADF) { SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */ - return FALSE; + goto return_false; } else { assert(FALSE); SetLastError(ERROR_IO_DEVICE); - return FALSE; + goto return_false; } } @@ -329,16 +331,23 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, { /* termios timeout */ SetLastError(ERROR_TIMEOUT); - return FALSE; + goto return_false; } *lpNumberOfBytesRead = nbRead; - return TRUE; + goto return_true; } assert(FALSE); *lpNumberOfBytesRead = 0; + + return_false: + LeaveCriticalSection(&pComm->ReadLock); return FALSE; + + return_true: + LeaveCriticalSection(&pComm->ReadLock); + return TRUE; } @@ -355,35 +364,37 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite WINPR_COMM* pComm = (WINPR_COMM*) hDevice; struct timeval tmaxTimeout, *pTmaxTimeout; + EnterCriticalSection(&pComm->WriteLock); /* KISSer by the function's beginning */ + if (hDevice == INVALID_HANDLE_VALUE) { SetLastError(ERROR_INVALID_HANDLE); - return FALSE; + goto return_false; } if (!pComm || pComm->Type != HANDLE_TYPE_COMM) { SetLastError(ERROR_INVALID_HANDLE); - return FALSE; + goto return_false; } if (lpOverlapped != NULL) { SetLastError(ERROR_NOT_SUPPORTED); - return FALSE; + goto return_false; } if (lpNumberOfBytesWritten == NULL) { SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */ - return FALSE; + goto return_false; } *lpNumberOfBytesWritten = 0; /* will be ajusted if required ... */ if (nNumberOfBytesToWrite <= 0) { - return TRUE; /* FIXME: or FALSE? */ + goto return_true; /* FIXME: or FALSE? */ } /* FIXME: had expected eventfd_write() to return EAGAIN when @@ -434,7 +445,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite { DEBUG_WARN("select() failure, errno=[%d] %s\n", errno, strerror(errno)); SetLastError(ERROR_IO_DEVICE); - return FALSE; + goto return_false; } if (nbFds == 0) @@ -442,7 +453,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite /* timeout */ SetLastError(ERROR_TIMEOUT); - return FALSE; + goto return_false; } @@ -462,7 +473,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite else { DEBUG_WARN("unexpected error on reading fd_write_event, errno=[%d] %s\n", errno, strerror(errno)); - /* FIXME: return FALSE ? */ + /* FIXME: goto return_false ? */ } assert(errno == EAGAIN); @@ -471,7 +482,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite if (event == FREERDP_PURGE_TXABORT) { SetLastError(ERROR_CANCELLED); - return FALSE; + goto return_false; } assert(event == FREERDP_PURGE_TXABORT); /* no other expected event so far */ @@ -500,13 +511,13 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite else if (errno == EBADF) { SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */ - return FALSE; + goto return_false; } else { assert(FALSE); SetLastError(ERROR_IO_DEVICE); - return FALSE; + goto return_false; } } @@ -527,7 +538,13 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite tcdrain(pComm->fd_write); + return_true: + LeaveCriticalSection(&pComm->WriteLock); return TRUE; + + return_false: + LeaveCriticalSection(&pComm->WriteLock); + return FALSE; } diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c index 736110945..9c5985ea6 100644 --- a/winpr/libwinpr/comm/comm_ioctl.c +++ b/winpr/libwinpr/comm/comm_ioctl.c @@ -602,6 +602,23 @@ static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID l break; } + case IOCTL_SERIAL_IMMEDIATE_CHAR: + { + if (pRemoteSerialDriver->immediate_char) + { + UCHAR *pChar = (UCHAR*)lpInBuffer; + + assert(nInBufferSize >= sizeof(UCHAR)); + if (nInBufferSize < sizeof(UCHAR)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return pRemoteSerialDriver->immediate_char(pComm, pChar); + } + break; + } } DEBUG_WARN(_T("unsupported IoControlCode=[0x%lX] %s (remote serial driver: %s)"), diff --git a/winpr/libwinpr/comm/comm_ioctl.h b/winpr/libwinpr/comm/comm_ioctl.h index ad0628245..c3c1ee244 100644 --- a/winpr/libwinpr/comm/comm_ioctl.h +++ b/winpr/libwinpr/comm/comm_ioctl.h @@ -242,6 +242,7 @@ typedef struct _REMOTE_SERIAL_DRIVER BOOL (*set_xon)(WINPR_COMM *pComm); BOOL (*get_dtrrts)(WINPR_COMM *pComm, ULONG *pMask); BOOL (*config_size)(WINPR_COMM *pComm, ULONG *pSize); + BOOL (*immediate_char)(WINPR_COMM *pComm, const UCHAR *pChar); } REMOTE_SERIAL_DRIVER; diff --git a/winpr/libwinpr/comm/comm_sercx2_sys.c b/winpr/libwinpr/comm/comm_sercx2_sys.c index 5b685bd87..0790cd7bf 100644 --- a/winpr/libwinpr/comm/comm_sercx2_sys.c +++ b/winpr/libwinpr/comm/comm_sercx2_sys.c @@ -152,6 +152,7 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys = .set_xon = NULL, /* not supported by SerCx2.sys */ .get_dtrrts = NULL, .config_size = NULL, /* not supported by SerCx2.sys */ + .immediate_char = NULL, /* not supported by SerCx2.sys */ }; diff --git a/winpr/libwinpr/comm/comm_sercx_sys.c b/winpr/libwinpr/comm/comm_sercx_sys.c index 2ba21e6c1..b86919ce1 100644 --- a/winpr/libwinpr/comm/comm_sercx_sys.c +++ b/winpr/libwinpr/comm/comm_sercx_sys.c @@ -401,6 +401,7 @@ static REMOTE_SERIAL_DRIVER _SerCxSys = .set_xon = NULL, .get_dtrrts = NULL, .config_size = NULL, /* not supported by SerCx.sys */ + .immediate_char = NULL, }; @@ -445,6 +446,8 @@ REMOTE_SERIAL_DRIVER* SerCxSys_s() _SerCxSys.get_dtrrts = pSerialSys->get_dtrrts; + _SerCxSys.immediate_char = pSerialSys->immediate_char; + return &_SerCxSys; } diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 2621ce1f3..632eddfb5 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1491,6 +1491,21 @@ BOOL _config_size(WINPR_COMM *pComm, ULONG *pSize) } +BOOL _immediate_char(WINPR_COMM *pComm, const UCHAR *pChar) +{ + BOOL result; + DWORD nbBytesWritten = -1; + + /* FIXME: CommWriteFile uses a critical section, shall it be interrupted? */ + + result = CommWriteFile(pComm, pChar, 1, &nbBytesWritten, NULL); + + assert(nbBytesWritten == 1); + + return result; +} + + static REMOTE_SERIAL_DRIVER _SerialSys = { .id = RemoteSerialDriverSerialSys, @@ -1523,6 +1538,7 @@ static REMOTE_SERIAL_DRIVER _SerialSys = .set_xon = _set_xon, .get_dtrrts = _get_dtrrts, .config_size = _config_size, + .immediate_char = _immediate_char, }; diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index d2523e43e..0cee4b391 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -211,6 +211,8 @@ BOOL CloseHandle(HANDLE hObject) comm->PendingEvents |= SERIAL_EV_FREERDP_STOP; LeaveCriticalSection(&comm->EventsLock); + DeleteCriticalSection(&comm->ReadLock); + DeleteCriticalSection(&comm->WriteLock); DeleteCriticalSection(&comm->EventsLock); if (comm->fd > 0)