20 #include <winpr/config.h>
22 #include <winpr/assert.h>
28 #include <winpr/wlog.h>
29 #include <winpr/wtypes.h>
33 BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive)
35 WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
37 if (!CommIsHandled(hDevice))
40 pComm->permissive = permissive;
45 static UCHAR svtime(ULONG Ti)
56 return (UCHAR)(Ti / 100);
68 BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
71 WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
79 struct timeval tmaxTimeout;
80 struct timeval* pTmaxTimeout = NULL;
81 struct termios currentTermios;
82 EnterCriticalSection(&pComm->ReadLock);
84 if (!CommIsHandled(hDevice))
87 if (lpOverlapped != NULL)
89 SetLastError(ERROR_NOT_SUPPORTED);
93 if (lpNumberOfBytesRead == NULL)
95 SetLastError(ERROR_INVALID_PARAMETER);
99 *lpNumberOfBytesRead = 0;
101 if (nNumberOfBytesToRead <= 0)
106 if (tcgetattr(pComm->fd, ¤tTermios) < 0)
108 SetLastError(ERROR_IO_DEVICE);
112 if (currentTermios.c_lflag & ICANON)
114 CommLog_Print(WLOG_WARN,
"Canonical mode not supported");
115 SetLastError(ERROR_NOT_SUPPORTED);
138 pTimeouts = &(pComm->timeouts);
140 if ((pTimeouts->ReadIntervalTimeout == MAXULONG) &&
141 (pTimeouts->ReadTotalTimeoutConstant == MAXULONG))
145 "ReadIntervalTimeout and ReadTotalTimeoutConstant cannot be both set to MAXULONG");
146 SetLastError(ERROR_INVALID_PARAMETER);
152 if ((pTimeouts->ReadIntervalTimeout == MAXULONG) &&
153 (pTimeouts->ReadTotalTimeoutMultiplier == 0) && (pTimeouts->ReadTotalTimeoutConstant == 0))
169 if ((pTimeouts->ReadIntervalTimeout > 0) && (pTimeouts->ReadIntervalTimeout < MAXULONG))
172 vtime = svtime(pTimeouts->ReadIntervalTimeout);
176 pTmaxTimeout = &tmaxTimeout;
178 if ((pTimeouts->ReadIntervalTimeout == MAXULONG) &&
179 (pTimeouts->ReadTotalTimeoutMultiplier == MAXULONG))
182 Tmax = pTimeouts->ReadTotalTimeoutConstant;
187 Tmax = 1ll * nNumberOfBytesToRead * pTimeouts->ReadTotalTimeoutMultiplier +
188 1ll * pTimeouts->ReadTotalTimeoutConstant;
191 if ((Tmax == 0) && (pTimeouts->ReadIntervalTimeout < MAXULONG) &&
192 (pTimeouts->ReadTotalTimeoutMultiplier == 0))
196 if ((currentTermios.c_cc[VMIN] != vmin) || (currentTermios.c_cc[VTIME] != vtime))
198 currentTermios.c_cc[VMIN] = vmin;
199 currentTermios.c_cc[VTIME] = vtime;
201 if (tcsetattr(pComm->fd, TCSANOW, ¤tTermios) < 0)
203 CommLog_Print(WLOG_WARN,
204 "CommReadFile failure, could not apply new timeout values: VMIN=%" PRIu8
205 ", VTIME=%" PRIu8
"",
207 SetLastError(ERROR_IO_DEVICE);
214 if (pTmaxTimeout != NULL)
216 ZeroMemory(pTmaxTimeout,
sizeof(
struct timeval));
220 pTmaxTimeout->tv_sec = Tmax / 1000;
221 pTmaxTimeout->tv_usec = (Tmax % 1000) * 1000;
228 #if defined(WINPR_HAVE_SYS_EVENTFD_H)
229 eventfd_read(pComm->fd_read_event, NULL);
231 biggestFd = pComm->fd_read;
233 if (pComm->fd_read_event > biggestFd)
234 biggestFd = pComm->fd_read_event;
237 WINPR_ASSERT(pComm->fd_read_event < FD_SETSIZE);
238 WINPR_ASSERT(pComm->fd_read < FD_SETSIZE);
239 FD_SET(pComm->fd_read_event, &read_set);
240 FD_SET(pComm->fd_read, &read_set);
241 nbFds = select(biggestFd + 1, &read_set, NULL, NULL, pTmaxTimeout);
245 char ebuffer[256] = { 0 };
246 CommLog_Print(WLOG_WARN,
"select() failure, errno=[%d] %s\n", errno,
247 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
248 SetLastError(ERROR_IO_DEVICE);
255 SetLastError(ERROR_TIMEOUT);
261 if (FD_ISSET(pComm->fd_read_event, &read_set))
263 #if defined(WINPR_HAVE_SYS_EVENTFD_H)
266 if (eventfd_read(pComm->fd_read_event, &event) < 0)
275 char ebuffer[256] = { 0 };
276 CommLog_Print(WLOG_WARN,
277 "unexpected error on reading fd_read_event, errno=[%d] %s\n", errno,
278 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
282 WINPR_ASSERT(errno == EAGAIN);
285 if (event == WINPR_PURGE_RXABORT)
287 SetLastError(ERROR_CANCELLED);
291 WINPR_ASSERT(event == WINPR_PURGE_RXABORT);
295 if (FD_ISSET(pComm->fd_read, &read_set))
297 ssize_t nbRead = read(pComm->fd_read, lpBuffer, nNumberOfBytesToRead);
299 if ((nbRead < 0) || (nbRead > nNumberOfBytesToRead))
301 char ebuffer[256] = { 0 };
302 CommLog_Print(WLOG_WARN,
303 "CommReadFile failed, ReadIntervalTimeout=%" PRIu32
304 ", ReadTotalTimeoutMultiplier=%" PRIu32
305 ", ReadTotalTimeoutConstant=%" PRIu32
" VMIN=%u, VTIME=%u",
306 pTimeouts->ReadIntervalTimeout, pTimeouts->ReadTotalTimeoutMultiplier,
307 pTimeouts->ReadTotalTimeoutConstant, currentTermios.c_cc[VMIN],
308 currentTermios.c_cc[VTIME]);
310 WLOG_WARN,
"CommReadFile failed, nNumberOfBytesToRead=%" PRIu32
", errno=[%d] %s",
311 nNumberOfBytesToRead, errno, winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
318 else if (errno == EBADF)
320 SetLastError(ERROR_BAD_DEVICE);
326 SetLastError(ERROR_IO_DEVICE);
334 SetLastError(ERROR_TIMEOUT);
338 *lpNumberOfBytesRead = (UINT32)nbRead;
340 EnterCriticalSection(&pComm->EventsLock);
341 if (pComm->PendingEvents & SERIAL_EV_WINPR_WAITING)
343 if (pComm->eventChar !=
'\0' && memchr(lpBuffer, pComm->eventChar, nbRead))
344 pComm->PendingEvents |= SERIAL_EV_RXCHAR;
346 LeaveCriticalSection(&pComm->EventsLock);
351 *lpNumberOfBytesRead = 0;
353 LeaveCriticalSection(&pComm->ReadLock);
356 LeaveCriticalSection(&pComm->ReadLock);
367 BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
368 LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
370 WINPR_COMM* pComm = (WINPR_COMM*)hDevice;
371 struct timeval tmaxTimeout;
372 struct timeval* pTmaxTimeout = NULL;
373 EnterCriticalSection(&pComm->WriteLock);
375 if (!CommIsHandled(hDevice))
378 if (lpOverlapped != NULL)
380 SetLastError(ERROR_NOT_SUPPORTED);
384 if (lpNumberOfBytesWritten == NULL)
386 SetLastError(ERROR_INVALID_PARAMETER);
390 *lpNumberOfBytesWritten = 0;
392 if (nNumberOfBytesToWrite <= 0)
401 #if defined(WINPR_HAVE_SYS_EVENTFD_H)
402 eventfd_read(pComm->fd_write_event, NULL);
406 LONGLONG Tmax = 1ll * nNumberOfBytesToWrite * pComm->timeouts.WriteTotalTimeoutMultiplier +
407 1ll * pComm->timeouts.WriteTotalTimeoutConstant;
411 pTmaxTimeout = &tmaxTimeout;
412 ZeroMemory(pTmaxTimeout,
sizeof(
struct timeval));
416 pTmaxTimeout->tv_sec = Tmax / 1000;
417 pTmaxTimeout->tv_usec = (Tmax % 1000) * 1000;
419 else if ((pComm->timeouts.WriteTotalTimeoutMultiplier == 0) &&
420 (pComm->timeouts.WriteTotalTimeoutConstant == 0))
427 while (*lpNumberOfBytesWritten < nNumberOfBytesToWrite)
433 biggestFd = pComm->fd_write;
435 if (pComm->fd_write_event > biggestFd)
436 biggestFd = pComm->fd_write_event;
440 WINPR_ASSERT(pComm->fd_write_event < FD_SETSIZE);
441 WINPR_ASSERT(pComm->fd_write < FD_SETSIZE);
442 FD_SET(pComm->fd_write_event, &event_set);
443 FD_SET(pComm->fd_write, &write_set);
444 nbFds = select(biggestFd + 1, &event_set, &write_set, NULL, pTmaxTimeout);
448 char ebuffer[256] = { 0 };
449 CommLog_Print(WLOG_WARN,
"select() failure, errno=[%d] %s\n", errno,
450 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
451 SetLastError(ERROR_IO_DEVICE);
458 SetLastError(ERROR_TIMEOUT);
464 if (FD_ISSET(pComm->fd_write_event, &event_set))
466 #if defined(WINPR_HAVE_SYS_EVENTFD_H)
469 if (eventfd_read(pComm->fd_write_event, &event) < 0)
478 char ebuffer[256] = { 0 };
479 CommLog_Print(WLOG_WARN,
480 "unexpected error on reading fd_write_event, errno=[%d] %s\n",
481 errno, winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
485 WINPR_ASSERT(errno == EAGAIN);
488 if (event == WINPR_PURGE_TXABORT)
490 SetLastError(ERROR_CANCELLED);
494 WINPR_ASSERT(event == WINPR_PURGE_TXABORT);
500 if (FD_ISSET(pComm->fd_write, &write_set))
502 ssize_t nbWritten = 0;
503 nbWritten = write(pComm->fd_write, ((
const BYTE*)lpBuffer) + (*lpNumberOfBytesWritten),
504 nNumberOfBytesToWrite - (*lpNumberOfBytesWritten));
508 char ebuffer[256] = { 0 };
509 CommLog_Print(WLOG_WARN,
510 "CommWriteFile failed after %" PRIu32
511 " bytes written, errno=[%d] %s\n",
512 *lpNumberOfBytesWritten, errno,
513 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)));
520 else if (errno == EBADF)
522 SetLastError(ERROR_BAD_DEVICE);
528 SetLastError(ERROR_IO_DEVICE);
533 *lpNumberOfBytesWritten += nbWritten;
545 tcdrain(pComm->fd_write);
548 LeaveCriticalSection(&pComm->WriteLock);
552 LeaveCriticalSection(&pComm->WriteLock);