diff --git a/ismas/ismas_client.cpp b/ismas/ismas_client.cpp index d405da7..8e94f5b 100644 --- a/ismas/ismas_client.cpp +++ b/ismas/ismas_client.cpp @@ -137,7 +137,12 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) { so_linger.l_onoff = 1; so_linger.l_linger = 0; + int maxfdp1; + fd_set rset; + fd_set wset; + setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger)); + // no reliable, but does not harm, as we use select() as well setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); int flag = 1; @@ -151,24 +156,56 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) { int loop = 0; int bytesWritten = 0; while (bytesWritten < bytesToWrite) { - int n = ::sendto(sockfd, buf+bytesWritten, bytesToWrite-bytesWritten, 0, NULL, 0); - if (n >= 0) { - bytesWritten += n; - } else { - if (errno == EWOULDBLOCK) { - if (++loop < 10) { - QThread::msleep(500); - continue; - } - printErrorMessage(port, clientIP, clientPort, - QString("WRITE TIMEOUT %1(").arg(loop) + strerror(errno) + ")"); - ::close(sockfd); - return std::nullopt; - } else + errno = 0; + FD_ZERO(&wset); + FD_SET(sockfd, &wset); + maxfdp1 = sockfd + 1; + tv.tv_sec = 60; /* 60 secs timeout for read and write -> APISM cuts the connection after 30s */ + tv.tv_usec = 0; + + int const w = select(maxfdp1, NULL, &wset, NULL, &tv); + if (w < 0) { // error if (errno == EINTR) { printErrorMessage(port, clientIP, clientPort, - QString("WRITE INTERRUPTED BY SIGNAL (1) (") + strerror(errno) + ")"); + QString("INTERRUPTED BY SIGNAL (1) (") + strerror(errno) + ")"); continue; + } else { + printErrorMessage(port, clientIP, clientPort, + QString("SELECT-ERROR (WRITE) %1(").arg(loop) + strerror(errno) + ")"); + ::close(sockfd); + return std::nullopt; + } + } else + if (w == 0) { // timeout + printErrorMessage(port, clientIP, clientPort, + QString("SELECT-TIMEOUT (WRITE) %1(").arg(loop) + strerror(errno) + ")"); + if (++loop < 10) { + QThread::msleep(500); + continue; + } + ::close(sockfd); + return std::nullopt; + } else + if (w > 0) { + int n = ::sendto(sockfd, buf+bytesWritten, bytesToWrite-bytesWritten, 0, NULL, 0); + if (n >= 0) { + bytesWritten += n; + } else { + if (errno == EWOULDBLOCK) { + if (++loop < 10) { + QThread::msleep(500); + continue; + } + printErrorMessage(port, clientIP, clientPort, + QString("WRITE TIMEOUT %1(").arg(loop) + strerror(errno) + ")"); + ::close(sockfd); + return std::nullopt; + } else + if (errno == EINTR) { + printErrorMessage(port, clientIP, clientPort, + QString("WRITE INTERRUPTED BY SIGNAL (1) (") + strerror(errno) + ")"); + continue; + } } } } @@ -188,33 +225,66 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) { int bytesRead = 0; while (bytesRead < bytesToRead) { errno = 0; - int n = ::recvfrom(sockfd, buf+bytesRead, bytesToRead-bytesRead, - 0, NULL, NULL); - if (n > 0) { // - bytesRead += n; - } else - if (n == 0) { - // The return value will be 0 when the peer has performed an orderly shutdown. - printErrorMessage(port, clientIP, clientPort, - QString("PEER CLOSED CONNECTION (") + strerror(errno) + ")"); - ::close(sockfd); - return std::nullopt; - } else - if (n < 0) { - if (errno == EWOULDBLOCK) { - if (++loop < 10) { - QThread::msleep(500); - continue; - } - printErrorMessage(port, clientIP, clientPort, - QString("READ TIMEOUT %1(").arg(loop) + strerror(errno) + ")"); - ::close(sockfd); - return std::nullopt; - } + FD_ZERO(&rset); + FD_SET(sockfd, &rset); + maxfdp1 = sockfd + 1; + tv.tv_sec = 60; /* 60 secs timeout for read and write */ + tv.tv_usec = 0; + + int const r = select(maxfdp1, &rset, NULL, NULL, &tv); + if (r < 0) { // error if (errno == EINTR) { printErrorMessage(port, clientIP, clientPort, QString("INTERRUPTED BY SIGNAL (2) (") + strerror(errno) + ")"); continue; + } else { + printErrorMessage(port, clientIP, clientPort, + QString("SELECT-ERROR (READ) %1(").arg(loop) + strerror(errno) + ")"); + ::close(sockfd); + return std::nullopt; + } + } else + if (r == 0) { // timeout + printErrorMessage(port, clientIP, clientPort, + QString("SELECT-TIMEOUT (READ) %1(").arg(loop) + strerror(errno) + ")"); + if (++loop < 10) { + QThread::msleep(500); + continue; + } + ::close(sockfd); + return std::nullopt; + } else + if (r > 0) { + if (FD_ISSET(sockfd, &rset)) { + int n = ::recvfrom(sockfd, buf+bytesRead, bytesToRead-bytesRead, + 0, NULL, NULL); + if (n > 0) { // + bytesRead += n; + } else + if (n == 0) { + // The return value will be 0 when the peer has performed an orderly shutdown. + printErrorMessage(port, clientIP, clientPort, + QString("PEER CLOSED CONNECTION (") + strerror(errno) + ")"); + ::close(sockfd); + return std::nullopt; + } else + if (n < 0) { + if (errno == EWOULDBLOCK) { // check just in case + if (++loop < 10) { + QThread::msleep(500); + continue; + } + printErrorMessage(port, clientIP, clientPort, + QString("READ TIMEOUT %1(").arg(loop) + strerror(errno) + ")"); + ::close(sockfd); + return std::nullopt; + } + if (errno == EINTR) { + printErrorMessage(port, clientIP, clientPort, + QString("INTERRUPTED BY SIGNAL (2) (") + strerror(errno) + ")"); + continue; + } + } } }