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_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user