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:
parent
66d0214720
commit
8d528f0f55
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user