SO_SNDTIMEO and SO_RCVTIMEO socket options have turned out not to be reliable.
Use select() for detecting timeout on socket (read and write).
This commit is contained in:
		@@ -137,7 +137,12 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) {
 | 
				
			|||||||
    so_linger.l_onoff = 1;
 | 
					    so_linger.l_onoff = 1;
 | 
				
			||||||
    so_linger.l_linger = 0;
 | 
					    so_linger.l_linger = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int maxfdp1;
 | 
				
			||||||
 | 
					    fd_set rset;
 | 
				
			||||||
 | 
					    fd_set wset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));
 | 
					    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_SNDTIMEO, &tv, sizeof(tv));
 | 
				
			||||||
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
 | 
					    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
 | 
				
			||||||
    int flag = 1;
 | 
					    int flag = 1;
 | 
				
			||||||
@@ -151,24 +156,56 @@ IsmasClient::sendRequestReceiveResponse(int port, QString const &request) {
 | 
				
			|||||||
    int loop = 0;
 | 
					    int loop = 0;
 | 
				
			||||||
    int bytesWritten = 0;
 | 
					    int bytesWritten = 0;
 | 
				
			||||||
    while (bytesWritten < bytesToWrite) {
 | 
					    while (bytesWritten < bytesToWrite) {
 | 
				
			||||||
        int n = ::sendto(sockfd, buf+bytesWritten, bytesToWrite-bytesWritten, 0, NULL, 0);
 | 
					        errno = 0;
 | 
				
			||||||
        if (n >= 0) {
 | 
					        FD_ZERO(&wset);
 | 
				
			||||||
            bytesWritten += n;
 | 
					        FD_SET(sockfd, &wset);
 | 
				
			||||||
        } else {
 | 
					        maxfdp1 = sockfd + 1;
 | 
				
			||||||
            if (errno == EWOULDBLOCK) {
 | 
					        tv.tv_sec = 60;  /* 60 secs timeout for read and write -> APISM cuts the connection after 30s */
 | 
				
			||||||
                if (++loop < 10) {
 | 
					        tv.tv_usec = 0;
 | 
				
			||||||
                    QThread::msleep(500);
 | 
					
 | 
				
			||||||
                    continue;
 | 
					        int const w = select(maxfdp1, NULL, &wset, NULL, &tv);
 | 
				
			||||||
                }
 | 
					        if (w < 0) { // error
 | 
				
			||||||
                printErrorMessage(port, clientIP, clientPort,
 | 
					 | 
				
			||||||
                    QString("WRITE TIMEOUT %1(").arg(loop) + strerror(errno) + ")");
 | 
					 | 
				
			||||||
                ::close(sockfd);
 | 
					 | 
				
			||||||
                return std::nullopt;
 | 
					 | 
				
			||||||
            } else
 | 
					 | 
				
			||||||
            if (errno == EINTR) {
 | 
					            if (errno == EINTR) {
 | 
				
			||||||
                printErrorMessage(port, clientIP, clientPort,
 | 
					                printErrorMessage(port, clientIP, clientPort,
 | 
				
			||||||
                    QString("WRITE INTERRUPTED BY SIGNAL (1) (") + strerror(errno) + ")");
 | 
					                    QString("INTERRUPTED BY SIGNAL (1) (") + strerror(errno) + ")");
 | 
				
			||||||
                continue;
 | 
					                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;
 | 
					    int bytesRead = 0;
 | 
				
			||||||
    while (bytesRead < bytesToRead) {
 | 
					    while (bytesRead < bytesToRead) {
 | 
				
			||||||
        errno = 0;
 | 
					        errno = 0;
 | 
				
			||||||
        int n = ::recvfrom(sockfd, buf+bytesRead, bytesToRead-bytesRead,
 | 
					        FD_ZERO(&rset);
 | 
				
			||||||
                           0, NULL, NULL);
 | 
					        FD_SET(sockfd, &rset);
 | 
				
			||||||
        if (n > 0) { //
 | 
					        maxfdp1 = sockfd + 1;
 | 
				
			||||||
            bytesRead += n;
 | 
					        tv.tv_sec = 60;  /* 60 secs timeout for read and write */
 | 
				
			||||||
        } else
 | 
					        tv.tv_usec = 0;
 | 
				
			||||||
        if (n == 0) {
 | 
					
 | 
				
			||||||
            // The return value will be 0 when the peer has performed an orderly shutdown.
 | 
					        int const r = select(maxfdp1, &rset, NULL, NULL, &tv);
 | 
				
			||||||
            printErrorMessage(port, clientIP, clientPort,
 | 
					        if (r < 0) { // error
 | 
				
			||||||
                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;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (errno == EINTR) {
 | 
					            if (errno == EINTR) {
 | 
				
			||||||
                printErrorMessage(port, clientIP, clientPort,
 | 
					                printErrorMessage(port, clientIP, clientPort,
 | 
				
			||||||
                    QString("INTERRUPTED BY SIGNAL (2) (") + strerror(errno) + ")");
 | 
					                    QString("INTERRUPTED BY SIGNAL (2) (") + strerror(errno) + ")");
 | 
				
			||||||
                continue;
 | 
					                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;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user