winpr-comm: completed _purge() supporting SERIAL_PURGE_RXABORT

winpr-comm: CommReadFile, support of FREERDP_PURGE_RXABORT sent by _purge()
This commit is contained in:
Emmanuel Ledoux 2014-05-28 18:42:23 +02:00 committed by Emmanuel Ledoux
parent cdbba47eee
commit 85343a435a
5 changed files with 150 additions and 46 deletions

View File

@ -1124,15 +1124,21 @@ HANDLE CommCreateFileA(LPCSTR lpDeviceName, DWORD dwDesiredAccess, DWORD dwShare
goto error_handle;
}
/* TMP: won't be required once fd_read, fd_read_event implemented */
/* Restore the blocking mode for upcoming read/write operations */
if (fcntl(pComm->fd, F_SETFL, fcntl(pComm->fd, F_GETFL) & ~O_NONBLOCK) < 0)
pComm->fd_read = open(devicePath, O_RDONLY | O_NOCTTY | O_NONBLOCK);
if (pComm->fd_read < 0)
{
DEBUG_WARN("failed to open device %s, could not restore the O_NONBLOCK flag", devicePath);
DEBUG_WARN("failed to open fd_read, device: %s", devicePath);
SetLastError(ERROR_BAD_DEVICE);
goto error_handle;
}
pComm->fd_read_event = eventfd(0, EFD_NONBLOCK); /* EFD_NONBLOCK required because a read() is not always expected */
if (pComm->fd_read_event < 0)
{
DEBUG_WARN("failed to open fd_read_event, device: %s", devicePath);
SetLastError(ERROR_BAD_DEVICE);
goto error_handle;
}
pComm->fd_write = open(devicePath, O_WRONLY | O_NOCTTY | O_NONBLOCK);
if (pComm->fd_write < 0)

View File

@ -47,6 +47,9 @@ struct winpr_comm
WINPR_HANDLE_DEF();
int fd;
int fd_read;
int fd_read_event; /* as of today, only used by _purge() */
int fd_write;
int fd_write_event; /* as of today, only used by _purge() */

View File

@ -45,7 +45,7 @@ BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive)
return FALSE;
}
if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd )
if (!pComm || pComm->Type != HANDLE_TYPE_COMM)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
@ -89,6 +89,9 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
WINPR_COMM* pComm = (WINPR_COMM*) hDevice;
int biggestFd = -1;
fd_set read_set;
int nbFds;
ssize_t nbRead = 0;
COMMTIMEOUTS *pTimeouts;
UCHAR vmin = 0;
@ -101,7 +104,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
return FALSE;
}
if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd )
if (!pComm || pComm->Type != HANDLE_TYPE_COMM)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
@ -143,7 +146,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439614%28v=vs.85%29.aspx
*
* ReadIntervalTimeout | ReadTotalTimeoutMultiplier | ReadTotalTimeoutConstant | VMIN | VTIME | TMAX |
* 0 | 0 | 0 | N | 0 | 0 | Blocks for N bytes available. FIXME: reduce N to 1?
* 0 | 0 | 0 | N | 0 | 0 | Blocks for N bytes available.
* 0< Ti <MAXULONG | 0 | 0 | N | Ti | 0 | Block on first byte, then use Ti between bytes.
* MAXULONG | 0 | 0 | 0 | 0 | 0 | Returns immediately with bytes available (don't block)
* MAXULONG | MAXULONG | 0< Tc <MAXULONG | 0 | Tc | 0 | Blocks on first byte during Tc or returns immediately whith bytes available
@ -208,7 +211,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
currentTermios.c_cc[VTIME] = vtime;
// TMP:
DEBUG_MSG("Applying timeout VMIN=%u, VTIME=%u", vmin, vtime);
fprintf(stderr, "Applying timeout VMIN=%u, VTIME=%u", vmin, vtime);
if (tcsetattr(pComm->fd, TCSANOW, &currentTermios) < 0)
{
@ -218,37 +221,116 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
}
}
nbRead = read(pComm->fd, lpBuffer, nNumberOfBytesToRead);
if (nbRead < 0)
biggestFd = pComm->fd_read;
if (pComm->fd_read_event > biggestFd)
biggestFd = pComm->fd_read_event;
FD_ZERO(&read_set);
assert(pComm->fd_read_event < FD_SETSIZE);
assert(pComm->fd_read < FD_SETSIZE);
FD_SET(pComm->fd_read_event, &read_set);
FD_SET(pComm->fd_read, &read_set);
nbFds = select(biggestFd+1, &read_set, NULL, NULL, NULL /* TMP: TODO:*/);
if (nbFds < 0)
{
DEBUG_WARN("CommReadFile failed, ReadIntervalTimeout=%lu, ReadTotalTimeoutMultiplier=%lu, ReadTotalTimeoutConstant=%lu VMIN=%u, VTIME=%u",
pTimeouts->ReadIntervalTimeout, pTimeouts->ReadTotalTimeoutMultiplier, pTimeouts->ReadTotalTimeoutConstant,
currentTermios.c_cc[VMIN], currentTermios.c_cc[VTIME]);
DEBUG_WARN("CommReadFile failed, nNumberOfBytesToRead=%lu, errno=[%d] %s", nNumberOfBytesToRead, errno, strerror(errno));
switch (errno)
{
// TMP: TODO:
case EAGAIN: /* EWOULDBLOCK */
nbRead = 0;
break;
case EBADF:
SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */
return FALSE;
default:
return FALSE;
}
DEBUG_WARN("select() failure, errno=[%d] %s\n", errno, strerror(errno));
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
if (nbFds == 0)
{
/* timeout */
SetLastError(ERROR_TIMEOUT);
return FALSE;
}
// TODO:
// SetLastError(ERROR_TIMEOUT)
*lpNumberOfBytesRead = nbRead;
return TRUE;
/* read_set */
if (FD_ISSET(pComm->fd_read_event, &read_set))
{
eventfd_t event = 0;
int nbRead;
nbRead = eventfd_read(pComm->fd_read_event, &event);
if (nbRead < 0)
{
if (errno == EAGAIN)
{
assert(FALSE); /* not quite sure this should ever happen */
/* keep on */
}
else
{
DEBUG_WARN("unexpected error on reading fd_write_event, errno=[%d] %s\n", errno, strerror(errno));
/* FIXME: return FALSE ? */
}
assert(errno == EAGAIN);
}
assert(nbRead == sizeof(eventfd_t));
if (event == FREERDP_PURGE_RXABORT)
{
SetLastError(ERROR_CANCELLED);
return FALSE;
}
assert(event == FREERDP_PURGE_RXABORT); /* no other expected event so far */
}
if (FD_ISSET(pComm->fd_read, &read_set))
{
nbRead = read(pComm->fd_read, lpBuffer, nNumberOfBytesToRead);
if (nbRead < 0)
{
DEBUG_WARN("CommReadFile failed, ReadIntervalTimeout=%lu, ReadTotalTimeoutMultiplier=%lu, ReadTotalTimeoutConstant=%lu VMIN=%u, VTIME=%u",
pTimeouts->ReadIntervalTimeout, pTimeouts->ReadTotalTimeoutMultiplier, pTimeouts->ReadTotalTimeoutConstant,
currentTermios.c_cc[VMIN], currentTermios.c_cc[VTIME]);
DEBUG_WARN("CommReadFile failed, nNumberOfBytesToRead=%lu, errno=[%d] %s", nNumberOfBytesToRead, errno, strerror(errno));
if (errno == EAGAIN)
{
/* keep on */
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;
}
else
{
assert(FALSE);
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
}
if (nbRead == 0)
{
/* termios timeout */
SetLastError(ERROR_TIMEOUT);
return FALSE;
}
*lpNumberOfBytesRead = nbRead;
return TRUE;
}
assert(FALSE);
*lpNumberOfBytesRead = 0;
return FALSE;
}
@ -271,7 +353,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite
return FALSE;
}
if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd )
if (!pComm || pComm->Type != HANDLE_TYPE_COMM)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
@ -363,6 +445,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite
if (errno == EAGAIN)
{
assert(FALSE); /* not quite sure this should ever happen */
/* keep on */
}
else
{
@ -381,7 +464,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite
return FALSE;
}
assert(event == FREERDP_PURGE_TXABORT); /* no other event known so far */
assert(event == FREERDP_PURGE_TXABORT); /* no other expected event so far */
}
@ -409,6 +492,12 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite
SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */
return FALSE;
}
else
{
assert(FALSE);
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
}
*lpNumberOfBytesWritten += nbWritten;
@ -425,7 +514,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite
* Write operation. The serial port was oppened with:
* DesiredAccess=0x0012019F. The printer worked fine with
* mstsc. */
tcdrain(pComm->fd);
tcdrain(pComm->fd_write);
return TRUE;

View File

@ -1142,19 +1142,19 @@ static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask)
{
/* Purges all read (IRP_MJ_READ) requests. */
/* int nbWritten; */
int nbWritten;
/* if ((nbWritten = eventfd_write(pComm->fd_read_event, FREERDP_PURGE_RXABORT)) < 0) */
/* { */
/* if (errno != EAGAIN) */
/* { */
/* DEBUG_WARN("eventfd_write failed, errno=[%d] %s", errno, strerror(errno)); */
/* } */
if ((nbWritten = eventfd_write(pComm->fd_read_event, FREERDP_PURGE_RXABORT)) < 0)
{
if (errno != EAGAIN)
{
DEBUG_WARN("eventfd_write failed, errno=[%d] %s", errno, strerror(errno));
}
/* assert(errno == EAGAIN); /\* no reader <=> no pending IRP_MJ_READ *\/ */
/* } */
assert(errno == EAGAIN); /* no reader <=> no pending IRP_MJ_READ */
}
/* assert(nbWritten == 8); */
assert(nbWritten == sizeof(eventfd_t));
}
if (*pPurgeMask & SERIAL_PURGE_TXCLEAR)

View File

@ -222,6 +222,12 @@ BOOL CloseHandle(HANDLE hObject)
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;