check select errors better

This commit is contained in:
Benjamin Sergeant 2019-01-07 11:18:00 -08:00
parent 76f196206b
commit 8a0afef825
5 changed files with 55 additions and 43 deletions

View File

@ -171,11 +171,16 @@ namespace ix
fd_set rfds; fd_set rfds;
struct timeval timeout; struct timeval timeout;
timeout.tv_sec = 0; timeout.tv_sec = 0;
timeout.tv_usec = 1 * 1000; // 1ms timeout.tv_usec = 1 * 1000; // 1ms timeout
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_SET(_sockfd, &rfds); FD_SET(_sockfd, &rfds);
select(_sockfd + 1, &rfds, nullptr, nullptr, &timeout);
if (select(_sockfd + 1, &rfds, nullptr, nullptr, &timeout) < 0 &&
(errno == EBADF || errno == EINVAL))
{
return false;
}
continue; continue;
} }

View File

@ -43,9 +43,9 @@ namespace ix
{ {
errMsg = "no error"; errMsg = "no error";
int fd = (int) socket(address->ai_family, int fd = socket(address->ai_family,
address->ai_socktype, address->ai_socktype,
address->ai_protocol); address->ai_protocol);
if (fd < 0) if (fd < 0)
{ {
errMsg = "Cannot create a socket"; errMsg = "Cannot create a socket";
@ -56,33 +56,14 @@ namespace ix
// block us for too long // block us for too long
SocketConnect::configure(fd); SocketConnect::configure(fd);
if (::connect(fd, address->ai_addr, address->ai_addrlen) == -1) if (::connect(fd, address->ai_addr, address->ai_addrlen) == -1
&& errno != EINPROGRESS)
{ {
#ifdef _WIN32 closeSocket(fd);
if (WSAGetLastError() == WSAEWOULDBLOCK) errno = EINPROGRESS; errMsg = strerror(errno);
#endif return -1;
if (errno != EINPROGRESS)
{
closeSocket(fd);
errMsg = std::string("Connect error in ::connect:") + strerror(errno);
return -1;
}
} }
// Use select to see if the connect did succeed.
fd_set wfds;
FD_ZERO(&wfds);
FD_SET(fd, &wfds);
fd_set efds;
FD_ZERO(&efds);
FD_SET(fd, &efds);
// 50ms select timeout
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 50 * 1000;
for (;;) for (;;)
{ {
if (isCancellationRequested()) // Must handle timeout as well if (isCancellationRequested()) // Must handle timeout as well
@ -91,14 +72,31 @@ namespace ix
errMsg = "Cancelled"; errMsg = "Cancelled";
return -1; return -1;
} }
// Use select to check the status of the new connection
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 10 * 1000; // 10ms timeout
fd_set wfds;
fd_set efds;
select(fd + 1, nullptr, &wfds, &efds, &timeout); FD_ZERO(&wfds);
FD_SET(fd, &wfds);
FD_ZERO(&efds);
FD_SET(fd, &efds);
if (select(fd + 1, nullptr, &wfds, &efds, &timeout) < 0 &&
(errno == EBADF || errno == EINVAL))
{
closeSocket(fd);
errMsg = std::string("Connect error, select error: ") + strerror(errno);
return -1;
}
// Nothing was written to the socket, wait again. // Nothing was written to the socket, wait again.
if (!FD_ISSET(fd, &wfds)) continue; if (!FD_ISSET(fd, &wfds)) continue;
// Something was written to the socket. Check for errors. // Something was written to the socket. Check for errors.
int optval = -1; int optval = -1;
socklen_t optlen = sizeof(optval); socklen_t optlen = sizeof(optval);
@ -113,7 +111,7 @@ namespace ix
#endif #endif
{ {
closeSocket(fd); closeSocket(fd);
errMsg = std::string("Connect error in getsockopt:") + strerror(optval); errMsg = strerror(optval);
return -1; return -1;
} }
else else
@ -124,7 +122,7 @@ namespace ix
} }
closeSocket(fd); closeSocket(fd);
errMsg = "connect timed out"; errMsg = "connect timed out after 60 seconds";
return -1; return -1;
} }

View File

@ -146,19 +146,28 @@ namespace ix
// Return value of std::async, ignored // Return value of std::async, ignored
std::future<void> f; std::future<void> f;
// Select arguments
fd_set rfds;
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 10 * 1000; // 10ms
for (;;) for (;;)
{ {
if (_stop) return; if (_stop) return;
// Use select to check whether a new connection is in progress
fd_set rfds;
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 10 * 1000; // 10ms timeout
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_SET(_serverFd, &rfds); FD_SET(_serverFd, &rfds);
select(_serverFd + 1, &rfds, nullptr, nullptr, &timeout);
if (select(_serverFd + 1, &rfds, nullptr, nullptr, &timeout) < 0 &&
(errno == EBADF || errno == EINVAL))
{
std::stringstream ss;
ss << "SocketServer::run() error in select: "
<< strerror(Socket::getErrno());
logError(ss.str());
continue;
}
if (!FD_ISSET(_serverFd, &rfds)) if (!FD_ISSET(_serverFd, &rfds))
{ {

View File

@ -158,9 +158,8 @@ namespace ix
{ {
int N = (int) _rxbuf.size(); int N = (int) _rxbuf.size();
int ret;
_rxbuf.resize(N + 1500); _rxbuf.resize(N + 1500);
ret = _socket->recv((char*)&_rxbuf[0] + N, 1500); ssize_t ret = _socket->recv((char*)&_rxbuf[0] + N, 1500);
if (ret < 0 && (_socket->getErrno() == EWOULDBLOCK || if (ret < 0 && (_socket->getErrno() == EWOULDBLOCK ||
_socket->getErrno() == EAGAIN)) { _socket->getErrno() == EAGAIN)) {

View File

@ -16,7 +16,8 @@ using namespace ix;
namespace namespace
{ {
const std::string WEBSOCKET_DOT_ORG_URL("wss://echo.websocket.org"); // const std::string WEBSOCKET_DOT_ORG_URL("wss://echo.websocket.org");
const std::string WEBSOCKET_DOT_ORG_URL("wss://api.cobra.mobilewar-online.com/v2?appkey=ADdc208AB26B911F4cB05bFeedD8EbBA");
const std::string GOOGLE_URL("wss://google.com"); const std::string GOOGLE_URL("wss://google.com");
const std::string UNKNOWN_URL("wss://asdcasdcaasdcasdcasdcasdcasdcasdcasassdd.com"); const std::string UNKNOWN_URL("wss://asdcasdcaasdcasdcasdcasdcasdcasdcasassdd.com");