From c6e5399e8fc3605a287dc53e24b4bc5250161e3f Mon Sep 17 00:00:00 2001 From: Simon Ninon Date: Sun, 12 Nov 2017 17:30:50 -0800 Subject: [PATCH] make sure socket is in blocking mode before connection (#32) and check for async-connect errors with getsockopt --- sources/network/unix/unix_tcp_socket.cpp | 16 ++++++++++++++++ sources/network/windows/windows_tcp_socket.cpp | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/sources/network/unix/unix_tcp_socket.cpp b/sources/network/unix/unix_tcp_socket.cpp index c146984..5b642df 100644 --- a/sources/network/unix/unix_tcp_socket.cpp +++ b/sources/network/unix/unix_tcp_socket.cpp @@ -89,6 +89,14 @@ tcp_socket::connect(const std::string& host, std::uint32_t port, std::uint32_t t __TACOPIE_THROW(error, "connect() set non-blocking failure"); } } + else { + //! For no timeout case, still make sure that the socket is in blocking mode + //! As reported in #32, this might not be the case on some OS + if (fcntl(m_fd, F_SETFL, fcntl(m_fd, F_GETFL, 0) & (~O_NONBLOCK)) == -1) { + close(); + __TACOPIE_THROW(error, "connect() set blocking failure"); + } + } int ret = ::connect(m_fd, server_addr, addr_len); if (ret < 0 && errno != EINPROGRESS) { @@ -108,6 +116,14 @@ tcp_socket::connect(const std::string& host, std::uint32_t port, std::uint32_t t //! 1 means we are connected. //! 0/-1 means a timeout. if (select(m_fd + 1, NULL, &set, NULL, &tv) == 1) { + //! Make sure there are no async connection errors + int err = 0; + socklen_t len = sizeof(len); + if (getsockopt(m_fd, SOL_SOCKET, SO_ERROR, &err, &len) == -1 || err != 0) { + close(); + __TACOPIE_THROW(error, "connect() failure"); + } + //! Set back to blocking mode as the user of this class is expecting if (fcntl(m_fd, F_SETFL, fcntl(m_fd, F_GETFL, 0) & (~O_NONBLOCK)) == -1) { close(); diff --git a/sources/network/windows/windows_tcp_socket.cpp b/sources/network/windows/windows_tcp_socket.cpp index 4037184..ae26ef1 100644 --- a/sources/network/windows/windows_tcp_socket.cpp +++ b/sources/network/windows/windows_tcp_socket.cpp @@ -70,6 +70,15 @@ tcp_socket::connect(const std::string& host, std::uint32_t port, std::uint32_t t __TACOPIE_THROW(error, "connect() set non-blocking failure"); } } + else { + //! For no timeout case, still make sure that the socket is in blocking mode + //! As reported in #32, this might not be the case on some OS + u_long mode = 0; + if (ioctlsocket(m_fd, FIONBIO, &mode) != 0) { + close(); + __TACOPIE_THROW(error, "connect() set blocking failure"); + } + } int ret = ::connect(m_fd, (const struct sockaddr*) &server_addr, sizeof(server_addr)); if (ret == -1 && WSAGetLastError() != WSAEWOULDBLOCK) { @@ -89,6 +98,14 @@ tcp_socket::connect(const std::string& host, std::uint32_t port, std::uint32_t t //! 1 means we are connected. //! 0 means a timeout. if (select(static_cast(m_fd) + 1, NULL, &set, NULL, &tv) == 1) { + //! Make sure there are no async connection errors + int err = 0; + int len = sizeof(len); + if (getsockopt(m_fd, SOL_SOCKET, SO_ERROR, reinterpret_cast(&err), &len) == -1 || err != 0) { + close(); + __TACOPIE_THROW(error, "connect() failure"); + } + //! Set back to blocking mode as the user of this class is expecting u_long mode = 0; if (ioctlsocket(m_fd, FIONBIO, &mode) != 0) {