winpr-comm: CommReadFile and CommWriteFile are now protected by a mutex

winpr-comm: implemented IOCTL_SERIAL_IMMEDIATE_CHAR
This commit is contained in:
Emmanuel Ledoux 2014-06-17 16:34:20 +02:00 committed by Emmanuel Ledoux
parent 34c3654faf
commit 9fc0e6eccc
11 changed files with 96 additions and 31 deletions

View File

@ -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;

View File

@ -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"},

View File

@ -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.

View File

@ -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).
*

View File

@ -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, &currentTermios) < 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;
}

View File

@ -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)"),

View File

@ -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;

View File

@ -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 */
};

View File

@ -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;
}

View File

@ -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,
};

View File

@ -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)