From 50efce67f538212a04273ad447b453f6210a11db Mon Sep 17 00:00:00 2001 From: Emmanuel Ledoux Date: Wed, 28 May 2014 22:11:19 +0200 Subject: [PATCH] winpr-comm: completed support of Read*Timeout --- channels/serial/client/serial_main.c | 19 ++--- winpr/libwinpr/comm/comm_io.c | 114 +++++++++++++++------------ 2 files changed, 67 insertions(+), 66 deletions(-) diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 90b8fe9be..fe9a4d515 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -163,15 +163,6 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) /* dcb.fBinary = TRUE; */ /* SetCommState(serial->hComm, &dcb); */ - // TMP: - COMMTIMEOUTS timeouts; - timeouts.ReadIntervalTimeout = MAXULONG; /* ensures a non blocking state */ - timeouts.ReadTotalTimeoutMultiplier = 0; - timeouts.ReadTotalTimeoutConstant = 0; - timeouts.WriteTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = 0; - SetCommTimeouts(serial->hComm, &timeouts); - assert(irp->FileId == 0); irp->FileId = irp->devman->id_sequence++; /* FIXME: why not ((WINPR_COMM*)hComm)->fd? */ @@ -238,7 +229,7 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) } else { - DEBUG_SVC("read failure to %s, nbRead=%d, last-error: 0x%0.8x", serial->device.name, nbRead, GetLastError()); + DEBUG_SVC("read failure to %s, nbRead=%d, last-error: 0x%0.8X", serial->device.name, nbRead, GetLastError()); switch(GetLastError()) { @@ -319,7 +310,7 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) } else { - DEBUG_SVC("write failure to %s, nbWritten=%d, last-error: 0x%0.8x", serial->device.name, nbWritten, GetLastError()); + DEBUG_SVC("write failure to %s, nbWritten=%d, last-error: 0x%0.8X", serial->device.name, nbWritten, GetLastError()); switch(GetLastError()) { case ERROR_INVALID_HANDLE: @@ -351,7 +342,7 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) break; default: - DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); + DEBUG_SVC("unexpected last-error: 0x%X", GetLastError()); irp->IoStatus = STATUS_UNSUCCESSFUL; break; } @@ -405,7 +396,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) } else { - DEBUG_SVC("CommDeviceIoControl failure: IoControlCode=[0x%0.8x] %s, last-error: 0x%x", + DEBUG_SVC("CommDeviceIoControl failure: IoControlCode=[0x%0.8x] %s, last-error: 0x%X", IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError()); // TMP: TODO: Status codes to be reviewed according: http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests @@ -445,7 +436,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) break; default: - DEBUG_SVC("unexpected last-error: 0x%x", GetLastError()); + DEBUG_SVC("unexpected last-error: 0x%X", GetLastError()); irp->IoStatus = STATUS_UNSUCCESSFUL; break; } diff --git a/winpr/libwinpr/comm/comm_io.c b/winpr/libwinpr/comm/comm_io.c index cf965d5a1..27719c923 100644 --- a/winpr/libwinpr/comm/comm_io.c +++ b/winpr/libwinpr/comm/comm_io.c @@ -56,23 +56,19 @@ BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive) } -/* Computes Tmax in deciseconds (m and Tcare in milliseconds) */ -static UCHAR _tmax(DWORD N, ULONG m, ULONG Tc) +/* Computes VMIN in deciseconds from Ti in milliseconds */ +static UCHAR _vtime(ULONG Ti) { - /* Tmax = N * m + Tc */ - - ULONGLONG Tmax = N * m + Tc; - /* FIXME: look for an equivalent math function otherwise let * do the compiler do the optimization */ - if (Tmax == 0) + if (Ti == 0) return 0; - else if (Tmax < 100) + else if (Ti < 100) return 1; - else if (Tmax > 25500) + else if (Ti > 25500) return 255; /* 0xFF */ else - return Tmax/100; + return Ti/100; } @@ -95,6 +91,8 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, COMMTIMEOUTS *pTimeouts; UCHAR vmin = 0; UCHAR vtime = 0; + ULONGLONG Tmax = 0; + struct timeval tmaxTimeout, *pTmaxTimeout; struct termios currentTermios; if (hDevice == INVALID_HANDLE_VALUE) @@ -144,24 +142,19 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, /* http://msdn.microsoft.com/en-us/library/hh439614%28v=vs.85%29.aspx * 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. - * 0< Ti fd, O_NONBLOCK) doesn't conflict with above use cases - */ + /* FIXME: double check whether open(pComm->fd_read_event, O_NONBLOCK) doesn't conflict with above use cases */ pTimeouts = &(pComm->timeouts); @@ -174,44 +167,49 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, /* VMIN */ - if ((pTimeouts->ReadIntervalTimeout < MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == 0) && (pTimeouts->ReadTotalTimeoutConstant == 0)) + if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == 0) && (pTimeouts->ReadTotalTimeoutConstant == 0)) { - /* should only match the two first cases above */ - vmin = nNumberOfBytesToRead < 256 ? nNumberOfBytesToRead : 255; /* 0xFF */ + vmin = 0; + } + else + { + /* N */ + /* vmin = nNumberOfBytesToRead < 256 ? nNumberOfBytesToRead : 255;*/ /* 0xFF */ + + /* NB: we might wait endlessly with vmin=N, prefer to + * force vmin=1 and return with bytes + * available. FIXME: is a feature disarded here? */ + vmin = 1; } /* VTIME */ - if ((pTimeouts->ReadIntervalTimeout > 0) && (pTimeouts->ReadTotalTimeoutMultiplier == 0) && (pTimeouts->ReadTotalTimeoutConstant == 0)) + if ((pTimeouts->ReadIntervalTimeout > 0) && (pTimeouts->ReadIntervalTimeout < MAXULONG)) { /* Ti */ - - vtime = _tmax(0, 0, pTimeouts->ReadIntervalTimeout); - + vtime = _vtime(pTimeouts->ReadIntervalTimeout); } - else if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) && (pTimeouts->ReadTotalTimeoutConstant < MAXULONG)) + + + /* TMAX */ + + if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == MAXULONG)) { /* Tc */ - - vtime = _tmax(0, 0, pTimeouts->ReadTotalTimeoutConstant); + Tmax = pTimeouts->ReadTotalTimeoutConstant; } - else if ((pTimeouts->ReadTotalTimeoutMultiplier > 0) || (pTimeouts->ReadTotalTimeoutConstant > 0)) /* <=> Tmax > 0 */ + else { - /* Tmax and Tmax(1) */ - - vtime = _tmax(nNumberOfBytesToRead, pTimeouts->ReadTotalTimeoutMultiplier, pTimeouts->ReadTotalTimeoutConstant); + /* Tmax */ + Tmax = nNumberOfBytesToRead * pTimeouts->ReadTotalTimeoutMultiplier + pTimeouts->ReadTotalTimeoutConstant; } - if ((currentTermios.c_cc[VMIN] != vmin) || (currentTermios.c_cc[VTIME] != vtime)) { currentTermios.c_cc[VMIN] = vmin; currentTermios.c_cc[VTIME] = vtime; - // TMP: - fprintf(stderr, "MANU: Applying timeout VMIN=%u, VTIME=%u\n", vmin, vtime); - if (tcsetattr(pComm->fd, TCSANOW, ¤tTermios) < 0) { DEBUG_WARN("CommReadFile failure, could not apply new timeout values: VMIN=%u, VTIME=%u", vmin, vtime); @@ -220,6 +218,18 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, } } + pTmaxTimeout = NULL; /* no timeout if Tmax == 0 */ + if (Tmax > 0) + { + ZeroMemory(&tmaxTimeout, sizeof(struct timeval)); + + tmaxTimeout.tv_sec = Tmax / 1000; /* s */ + tmaxTimeout.tv_usec = (Tmax % 1000) * 1000; /* us */ + + pTmaxTimeout = &tmaxTimeout; + } + + /* FIXME: had expected eventfd_write() to return EAGAIN when * there is no eventfd_read() but this not the case. */ /* discard a possible and no more relevant event */ @@ -237,7 +247,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, 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:*/); + nbFds = select(biggestFd+1, &read_set, NULL, NULL, pTmaxTimeout); if (nbFds < 0) { DEBUG_WARN("select() failure, errno=[%d] %s\n", errno, strerror(errno)); @@ -321,7 +331,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, SetLastError(ERROR_TIMEOUT); return FALSE; } - + *lpNumberOfBytesRead = nbRead; return TRUE; } @@ -343,7 +353,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { WINPR_COMM* pComm = (WINPR_COMM*) hDevice; - struct timeval timeout, *pTimeout; + struct timeval tmaxTimeout, *pTmaxTimeout; if (hDevice == INVALID_HANDLE_VALUE) { @@ -389,15 +399,15 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite * how much time was left. Keep the timeout variable out of * the while() */ - pTimeout = NULL; /* no timeout if Tmax == 0 */ + pTmaxTimeout = NULL; /* no timeout if Tmax == 0 */ if (Tmax > 0) { - ZeroMemory(&timeout, sizeof(struct timeval)); + ZeroMemory(&tmaxTimeout, sizeof(struct timeval)); - timeout.tv_sec = Tmax / 1000; /* s */ - timeout.tv_usec = (Tmax % 1000) * 1000; /* us */ + tmaxTimeout.tv_sec = Tmax / 1000; /* s */ + tmaxTimeout.tv_usec = (Tmax % 1000) * 1000; /* us */ - pTimeout = &timeout; + pTmaxTimeout = &tmaxTimeout; } while (*lpNumberOfBytesWritten < nNumberOfBytesToWrite) @@ -419,7 +429,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite FD_SET(pComm->fd_write_event, &event_set); FD_SET(pComm->fd_write, &write_set); - nbFds = select(biggestFd+1, &event_set, &write_set, NULL, pTimeout); + nbFds = select(biggestFd+1, &event_set, &write_set, NULL, pTmaxTimeout); if (nbFds < 0) { DEBUG_WARN("select() failure, errno=[%d] %s\n", errno, strerror(errno));