diff --git a/CMakeLists.txt b/CMakeLists.txt index 07653d65c..8c5757bc1 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -369,6 +369,7 @@ if(UNIX OR CYGWIN) check_include_files(sys/eventfd.h HAVE_AIO_H) check_include_files(sys/eventfd.h HAVE_EVENTFD_H) check_include_files(sys/timerfd.h HAVE_TIMERFD_H) + check_include_files(poll.h HAVE_POLL_H) set(X11_FEATURE_TYPE "RECOMMENDED") else() set(X11_FEATURE_TYPE "DISABLED") diff --git a/config.h.in b/config.h.in index df9001f72..e0da60c6a 100755 --- a/config.h.in +++ b/config.h.in @@ -24,6 +24,7 @@ #cmakedefine HAVE_TIMERFD_H #cmakedefine HAVE_TM_GMTOFF #cmakedefine HAVE_AIO_H +#cmakedefine HAVE_POLL_H #cmakedefine HAVE_PTHREAD_GNU_EXT #cmakedefine HAVE_VALGRIND_MEMCHECK_H diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index c3276860c..245d3b1b9 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -41,6 +41,13 @@ #include #include +#ifdef HAVE_POLL_H +#include +#else +#include +#include +#endif + #ifdef __FreeBSD__ #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP @@ -739,6 +746,83 @@ HANDLE tcp_get_event_handle(rdpTcp* tcp) #endif } + +int tcp_wait_read(rdpTcp* tcp, DWORD dwMilliSeconds) +{ + int status; + +#ifdef HAVE_POLL_H + struct pollfd pollset; + + pollset.fd = tcp->sockfd; + pollset.events = POLLIN; + pollset.revents = 0; + + do + { + status = poll(&pollset, 1, dwMilliSeconds); + } + while ((status < 0) && (errno == EINTR)); +#else + struct timeval tv; + fd_set rset; + + FD_ZERO(&rset); + FD_SET(tcp->sockfd, &rset); + + if (dwMilliSeconds) + { + tv.tv_sec = dwMilliSeconds / 1000; + tv.tv_usec = (dwMilliSeconds % 1000) * 1000; + } + + do + { + status = select(tcp->sockfd + 1, &rset, NULL, NULL, dwMilliSeconds ? &tv : NULL); + } + while ((status < 0) && (errno == EINTR)); +#endif + return status; +} + +int tcp_wait_write(rdpTcp* tcp, DWORD dwMilliSeconds) +{ + int status; + +#ifdef HAVE_POLL_H + struct pollfd pollset; + + pollset.fd = tcp->sockfd; + pollset.events = POLLOUT; + pollset.revents = 0; + + do + { + status = poll(&pollset, 1, dwMilliSeconds); + } + while ((status < 0) && (errno == EINTR)); +#else + struct timeval tv; + fd_set rset; + + FD_ZERO(&rset); + FD_SET(tcp->sockfd, &rset); + + if (dwMilliSeconds) + { + tv.tv_sec = dwMilliSeconds / 1000; + tv.tv_usec = (dwMilliSeconds % 1000) * 1000; + } + + do + { + status = select(tcp->sockfd + 1, NULL, &rset, NULL, dwMilliSeconds ? &tv : NULL); + } + while ((status < 0) && (errno == EINTR)); +#endif + return status; +} + rdpTcp* tcp_new(rdpSettings* settings) { rdpTcp* tcp; diff --git a/libfreerdp/core/tcp.h b/libfreerdp/core/tcp.h index 8998f3856..4d87e3b01 100644 --- a/libfreerdp/core/tcp.h +++ b/libfreerdp/core/tcp.h @@ -64,8 +64,8 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout); BOOL tcp_disconnect(rdpTcp* tcp); int tcp_read(rdpTcp* tcp, BYTE* data, int length); int tcp_write(rdpTcp* tcp, BYTE* data, int length); -int tcp_wait_read(rdpTcp* tcp); -int tcp_wait_write(rdpTcp* tcp); +int tcp_wait_read(rdpTcp* tcp, DWORD dwMilliSeconds); +int tcp_wait_write(rdpTcp* tcp, DWORD dwMilliSeconds); BOOL tcp_set_blocking_mode(rdpTcp* tcp, BOOL blocking); BOOL tcp_set_keep_alive_mode(rdpTcp* tcp); int tcp_attach(rdpTcp* tcp, int sockfd); diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index b65294292..b11fdd038 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -43,9 +43,7 @@ #ifndef _WIN32 #include #include -#include -#include -#endif +#endif /* _WIN32 */ #ifdef HAVE_VALGRIND_MEMCHECK_H #include @@ -642,69 +640,37 @@ UINT32 nla_header_length(wStream* s) static int transport_wait_for_read(rdpTransport* transport) { - struct timeval tv; - fd_set rset, wset; - fd_set *rsetPtr = NULL, *wsetPtr = NULL; - rdpTcp *tcpIn; - - tcpIn = transport->TcpIn; + rdpTcp *tcpIn = transport->TcpIn; if (tcpIn->readBlocked) { - rsetPtr = &rset; - FD_ZERO(rsetPtr); - FD_SET(tcpIn->sockfd, rsetPtr); + return tcp_wait_read(tcpIn, 1000); } else if (tcpIn->writeBlocked) { - wsetPtr = &wset; - FD_ZERO(wsetPtr); - FD_SET(tcpIn->sockfd, wsetPtr); + return tcp_wait_write(tcpIn, 1000); } - if (!wsetPtr && !rsetPtr) - { - USleep(1000); - return 0; - } - - tv.tv_sec = 0; - tv.tv_usec = 1000; - - return select(tcpIn->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv); + USleep(1000); + return 0; } static int transport_wait_for_write(rdpTransport* transport) { - struct timeval tv; - fd_set rset, wset; - fd_set *rsetPtr = NULL, *wsetPtr = NULL; rdpTcp *tcpOut; tcpOut = transport->SplitInputOutput ? transport->TcpOut : transport->TcpIn; if (tcpOut->writeBlocked) { - wsetPtr = &wset; - FD_ZERO(wsetPtr); - FD_SET(tcpOut->sockfd, wsetPtr); + return tcp_wait_write(tcpOut, 1000); } else if (tcpOut->readBlocked) { - rsetPtr = &rset; - FD_ZERO(rsetPtr); - FD_SET(tcpOut->sockfd, rsetPtr); + return tcp_wait_read(tcpOut, 1000); } - if (!wsetPtr && !rsetPtr) - { - USleep(1000); - return 0; - } - - tv.tv_sec = 0; - tv.tv_usec = 1000; - - return select(tcpOut->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv); + USleep(1000); + return 0; } int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes) diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index c6e779280..9075f1e59 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -33,6 +33,11 @@ #include #include "../core/tcp.h" +#ifdef HAVE_POLL_H +#include +#endif + + struct _BIO_RDP_TLS { SSL* ssl; @@ -586,8 +591,12 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode) do { +#ifdef HAVE_POLL_H + struct pollfd pollfds; +#else struct timeval tv; fd_set rset; +#endif int fd; status = BIO_do_handshake(tls->bio); @@ -600,8 +609,6 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode) /* we select() only for read even if we should test both read and write * depending of what have blocked */ - FD_ZERO(&rset); - fd = BIO_get_fd(tls->bio, NULL); if (fd < 0) @@ -610,12 +617,24 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode) return -1; } +#ifdef HAVE_POLL_H + pollfds.fd = fd; + pollfds.events = POLLIN; + pollfds.revents = 0; + + do + { + status = poll(&pollfds, 1, 10 * 1000); + } + while ((status < 0) && (errno == EINTR)); +#else + FD_ZERO(&rset); FD_SET(fd, &rset); tv.tv_sec = 0; tv.tv_usec = 10 * 1000; /* 10ms */ - status = select(fd + 1, &rset, NULL, NULL, &tv); - + status = _select(fd + 1, &rset, NULL, NULL, &tv); +#endif if (status < 0) { fprintf(stderr, "%s: error during select()\n", __FUNCTION__); @@ -830,9 +849,13 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length) { int status, nchunks, commitedBytes; rdpTcp *tcp; +#ifdef HAVE_POLL_H + struct pollfd pollfds; +#else fd_set rset, wset; fd_set *rsetPtr, *wsetPtr; struct timeval tv; +#endif BIO* bio = tls->bio; DataChunk chunks[2]; @@ -855,9 +878,34 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length) if (!BIO_should_retry(bio)) return -1; +#ifdef HAVE_POLL_H + pollfds.fd = tcp->sockfd; + pollfds.revents = 0; + pollfds.events = 0; + if (tcp->writeBlocked) + { + pollfds.events |= POLLOUT; + } + else if (tcp->readBlocked) + { + pollfds.events |= POLLIN; + } + else + { + fprintf(stderr, "%s: weird we're blocked but the underlying is not read or write blocked !\n", __FUNCTION__); + USleep(10); + continue; + } + + do + { + status = poll(&pollfds, 1, 100); + } + while ((status < 0) && (errno == EINTR)); +#else /* we try to handle SSL want_read and want_write nicely */ - rsetPtr = wsetPtr = 0; + rsetPtr = wsetPtr = NULL; if (tcp->writeBlocked) { @@ -881,8 +929,8 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length) tv.tv_sec = 0; tv.tv_usec = 100 * 1000; - status = select(tcp->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv); - + status = _select(tcp->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv); +#endif if (status < 0) return -1; } @@ -911,13 +959,24 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length) if (!BIO_should_retry(tcp->socketBio)) goto out_fail; +#ifdef HAVE_POLL_H + pollfds.fd = tcp->sockfd; + pollfds.events = POLLIN; + pollfds.revents = 0; + + do + { + status = poll(&pollfds, 1, 100); + } + while ((status < 0) && (errno == EINTR)); +#else FD_ZERO(&rset); FD_SET(tcp->sockfd, &rset); tv.tv_sec = 0; tv.tv_usec = 100 * 1000; - status = select(tcp->sockfd + 1, &rset, NULL, NULL, &tv); - + status = _select(tcp->sockfd + 1, &rset, NULL, NULL, &tv); +#endif if (status < 0) goto out_fail; } diff --git a/libfreerdp/utils/tcp.c b/libfreerdp/utils/tcp.c index 45293dbf3..e1cd2684e 100644 --- a/libfreerdp/utils/tcp.c +++ b/libfreerdp/utils/tcp.c @@ -41,11 +41,16 @@ #include #include #include -#include #include #include #include +#ifdef HAVE_POLL_H +#include +#else +#include +#endif + #ifdef __APPLE__ #ifndef TCP_KEEPIDLE #define TCP_KEEPIDLE TCP_KEEPALIVE @@ -186,8 +191,14 @@ int freerdp_tcp_write(int sockfd, BYTE* data, int length) int freerdp_tcp_wait_read(int sockfd) { + int status; + +#ifdef HAVE_POLL_H + struct pollfd pollfds; +#else fd_set fds; struct timeval timeout; +#endif if (sockfd < 1) { @@ -195,37 +206,61 @@ int freerdp_tcp_wait_read(int sockfd) return 0 ; } +#ifdef HAVE_POLL_H + pollfds.fd = sockfd; + pollfds.events = POLLIN; + pollfds.revents = 0; + do + { + status = poll(&pollfds, 1, 5 * 1000); + } + while ((status < 0) && (errno == EINTR)); +#else FD_ZERO(&fds); FD_SET(sockfd, &fds); timeout.tv_sec = 5; timeout.tv_usec = 0; - select(sockfd+1, &fds, NULL, NULL, &timeout); - if (!FD_ISSET(sockfd, &fds)) - return -1; + status = _select(sockfd+1, &fds, NULL, NULL, &timeout); +#endif - return 0; + return status > 0 ? 1 : 0; } int freerdp_tcp_wait_write(int sockfd) { + int status; + +#ifdef HAVE_POLL_H + struct pollfd pollfds; +#else fd_set fds; struct timeval timeout; +#endif if (sockfd < 1) { fprintf(stderr, "Invalid socket to watch: %d\n", sockfd); - return 0; + return 0 ; } +#ifdef HAVE_POLL_H + pollfds.fd = sockfd; + pollfds.events = POLLOUT; + pollfds.revents = 0; + do + { + status = poll(&pollfds, 1, 5 * 1000); + } + while ((status < 0) && (errno == EINTR)); +#else FD_ZERO(&fds); FD_SET(sockfd, &fds); timeout.tv_sec = 5; timeout.tv_usec = 0; - select(sockfd+1, NULL, &fds, NULL, &timeout); - if (!FD_ISSET(sockfd, &fds)) - return -1; + status = _select(sockfd+1, NULL, &fds, NULL, &timeout); +#endif - return 0; + return status > 0 ? 1 : 0; } int freerdp_tcp_disconnect(int sockfd) diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index 0272415ad..90275c830 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -3,6 +3,7 @@ * Synchronization Functions * * Copyright 2012 Marc-Andre Moreau + * Copyright 2014 Hardening * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +26,10 @@ #include #endif +#ifdef HAVE_POLL_H +#include +#endif + #include #include @@ -164,6 +169,47 @@ static void ts_add_ms(struct timespec *ts, DWORD dwMilliseconds) ts->tv_nsec = ts->tv_nsec % 1000000000L; } +static int waitOnFd(int fd, DWORD dwMilliseconds) +{ + int status; + +#ifdef HAVE_POLL_H + struct pollfd pollfds; + + pollfds.fd = fd; + pollfds.events = POLLIN; + pollfds.revents = 0; + + do + { + status = poll(&pollfds, 1, dwMilliseconds); + } + while ((status < 0) && (errno == EINTR)); + +#else + struct timespec timeout; + fd_set rfds; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + ZeroMemory(&timeout, sizeof(timeout)); + + if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) + { + timeout.tv_sec = dwMilliseconds / 1000; + timeout.tv_usec = (dwMilliseconds % 1000) * 1000; + } + + do + { + status = select(fd + 1, &rfds, NULL, NULL, (dwMilliseconds == INFINITE) ? NULL : &timeout); + } + while (status < 0 && (errno == EINTR)); +#endif + + return status; +} + DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { ULONG Type; @@ -256,29 +302,11 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) else if (Type == HANDLE_TYPE_EVENT) { int status; - fd_set rfds; WINPR_EVENT* event; - struct timeval timeout; event = (WINPR_EVENT*) Object; - FD_ZERO(&rfds); - FD_SET(event->pipe_fd[0], &rfds); - ZeroMemory(&timeout, sizeof(timeout)); - - if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) - { - timeout.tv_sec = dwMilliseconds / 1000; - timeout.tv_usec = (dwMilliseconds % 1000) * 1000; - } - - do - { - status = select(event->pipe_fd[0] + 1, &rfds, NULL, NULL, - (dwMilliseconds == INFINITE) ? NULL : &timeout); - } - while (status < 0 && (errno == EINTR)); - + status = waitOnFd(event->pipe_fd[0], dwMilliseconds); if (status < 0) { fprintf(stderr, "WaitForSingleObject: event select() failure [%d] %s\n", errno, strerror(errno)); @@ -299,26 +327,8 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { int status; int length; - fd_set rfds; - struct timeval timeout; - - FD_ZERO(&rfds); - FD_SET(semaphore->pipe_fd[0], &rfds); - ZeroMemory(&timeout, sizeof(timeout)); - - if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) - { - timeout.tv_sec = dwMilliseconds / 1000; - timeout.tv_usec = (dwMilliseconds % 1000) * 1000; - } - - do - { - status = select(semaphore->pipe_fd[0] + 1, &rfds, 0, 0, - (dwMilliseconds == INFINITE) ? NULL : &timeout); - } - while (status < 0 && (errno == EINTR)); + status = waitOnFd(semaphore->pipe_fd[0], dwMilliseconds); if (status < 0) { fprintf(stderr, "WaitForSingleObject: semaphore select() failure [%d] %s\n", errno, strerror(errno)); @@ -356,27 +366,9 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (timer->fd != -1) { int status; - fd_set rfds; UINT64 expirations; - struct timeval timeout; - - FD_ZERO(&rfds); - FD_SET(timer->fd, &rfds); - ZeroMemory(&timeout, sizeof(timeout)); - - if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) - { - timeout.tv_sec = dwMilliseconds / 1000; - timeout.tv_usec = (dwMilliseconds % 1000) * 1000; - } - - do - { - status = select(timer->fd + 1, &rfds, 0, 0, - (dwMilliseconds == INFINITE) ? NULL : &timeout); - } - while (status < 0 && (errno == EINTR)); + status = waitOnFd(timer->fd, dwMilliseconds); if (status < 0) { fprintf(stderr, "WaitForSingleObject: timer select() failure [%d] %s\n", errno, strerror(errno)); @@ -420,8 +412,6 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { int fd; int status; - fd_set rfds; - struct timeval timeout; WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*) Object; fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd; @@ -432,23 +422,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) return WAIT_FAILED; } - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - ZeroMemory(&timeout, sizeof(timeout)); - - if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) - { - timeout.tv_sec = dwMilliseconds / 1000; - timeout.tv_usec = (dwMilliseconds % 1000) * 1000; - } - - do - { - status = select(fd + 1, &rfds, NULL, NULL, - (dwMilliseconds == INFINITE) ? NULL : &timeout); - } - while (status < 0 && (errno == EINTR)); - + status = waitOnFd(fd, dwMilliseconds); if (status < 0) { fprintf(stderr, "WaitForSingleObject: named pipe select() failure [%d] %s\n", errno, strerror(errno)); @@ -478,13 +452,17 @@ DWORD WaitForSingleObjectEx(HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertabl DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds) { int fd = -1; - int maxfd; int index; int status; - fd_set fds; ULONG Type; PVOID Object; +#ifdef HAVE_POLL_H + struct pollfd *pollfds; +#else + int maxfd; + fd_set fds; struct timeval timeout; +#endif if (!nCount) { @@ -492,10 +470,15 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl return WAIT_FAILED; } +#ifdef HAVE_POLL_H + pollfds = alloca(nCount * sizeof(struct pollfd)); +#else maxfd = 0; FD_ZERO(&fds); ZeroMemory(&timeout, sizeof(timeout)); +#endif + if (bWaitAll) { fprintf(stderr, "WaitForMultipleObjects: bWaitAll not yet implemented\n"); @@ -564,12 +547,25 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl return WAIT_FAILED; } +#ifdef HAVE_POLL_H + pollfds[index].fd = fd; + pollfds[index].events = POLLIN; + pollfds[index].revents = 0; +#else FD_SET(fd, &fds); if (fd > maxfd) maxfd = fd; +#endif } +#ifdef HAVE_POLL_H + do + { + status = poll(pollfds, nCount, dwMilliseconds); + } + while (status < 0 && errno == EINTR); +#else if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) { timeout.tv_sec = dwMilliseconds / 1000; @@ -582,6 +578,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl (dwMilliseconds == INFINITE) ? NULL : &timeout); } while (status < 0 && errno == EINTR); +#endif if (status < 0) { @@ -615,7 +612,11 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd; } +#ifdef HAVE_POLL_H + if (pollfds[index].revents & POLLIN) +#else if (FD_ISSET(fd, &fds)) +#endif { if (Type == HANDLE_TYPE_SEMAPHORE) { @@ -677,3 +678,4 @@ DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD } #endif + diff --git a/winpr/libwinpr/winsock/winsock.c b/winpr/libwinpr/winsock/winsock.c index ac07ea694..5f7757903 100644 --- a/winpr/libwinpr/winsock/winsock.c +++ b/winpr/libwinpr/winsock/winsock.c @@ -612,7 +612,11 @@ int _select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, cons { int status; - status = select(nfds, readfds, writefds, exceptfds, (struct timeval*) timeout); + do + { + status = select(nfds, readfds, writefds, exceptfds, (struct timeval*) timeout); + } + while ((status < 0) && (errno == EINTR)); return status; }