winpr-comm: CommReadFile and CommWriteFile are now protected by a mutex
winpr-comm: implemented IOCTL_SERIAL_IMMEDIATE_CHAR
This commit is contained in:
parent
34c3654faf
commit
9fc0e6eccc
@ -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;
|
||||
|
@ -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"},
|
||||
|
@ -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.
|
||||
|
@ -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).
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)"),
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user