Use non-blocking connect() call.

Exploit connect() error codes to determine whether connection was
established. Using poll/select proved to be problematic.
This commit is contained in:
Bartosz Taudul 2020-05-14 02:27:04 +02:00
parent b166451750
commit d10ef8c501
2 changed files with 93 additions and 7 deletions

View File

@ -23,6 +23,8 @@
# include <arpa/inet.h> # include <arpa/inet.h>
# include <sys/socket.h> # include <sys/socket.h>
# include <sys/param.h> # include <sys/param.h>
# include <errno.h>
# include <fcntl.h>
# include <netinet/in.h> # include <netinet/in.h>
# include <netdb.h> # include <netdb.h>
# include <unistd.h> # include <unistd.h>
@ -70,6 +72,7 @@ Socket::Socket()
, m_bufPtr( nullptr ) , m_bufPtr( nullptr )
, m_sock( -1 ) , m_sock( -1 )
, m_bufLeft( 0 ) , m_bufLeft( 0 )
, m_ptr( nullptr )
{ {
#ifdef _WIN32 #ifdef _WIN32
InitWinSock(); InitWinSock();
@ -81,6 +84,7 @@ Socket::Socket( int sock )
, m_bufPtr( nullptr ) , m_bufPtr( nullptr )
, m_sock( sock ) , m_sock( sock )
, m_bufLeft( 0 ) , m_bufLeft( 0 )
, m_ptr( nullptr )
{ {
} }
@ -91,12 +95,59 @@ Socket::~Socket()
{ {
Close(); Close();
} }
if( m_ptr )
{
freeaddrinfo( m_res );
#ifdef _WIN32
closesocket( m_connSock );
#else
close( m_connSock );
#endif
}
} }
bool Socket::Connect( const char* addr, int port ) bool Socket::Connect( const char* addr, int port )
{ {
assert( !IsValid() ); assert( !IsValid() );
if( m_ptr )
{
const auto c = connect( m_connSock, m_ptr->ai_addr, m_ptr->ai_addrlen );
assert( c == -1 );
#if defined _WIN32 || defined __CYGWIN__
const auto err = WSAGetLastError();
if( err == WSAEALREADY || err == WSAEINPROGRESS ) return false;
if( err != WSAEISCONN )
{
freeaddrinfo( m_res );
closesocket( m_connSock );
m_ptr = nullptr;
return false;
}
#else
if( errno == EALREADY || errno == EINPROGRESS ) return false;
if( errno != EISCONN )
{
freeaddrinfo( m_res );
close( m_connSock );
m_ptr = nullptr;
return false;
}
#endif
#if defined _WIN32 || defined __CYGWIN__
u_long nonblocking = 0;
ioctlsocket( m_connSock, FIONBIO, &nonblocking );
#else
int flags = fcntl( m_connSock, F_GETFL, 0 );
fcntl( m_connSock, F_SETFL, flags & ~O_NONBLOCK );
#endif
m_sock.store( m_connSock, std::memory_order_relaxed );
freeaddrinfo( m_res );
m_ptr = nullptr;
return true;
}
struct addrinfo hints; struct addrinfo hints;
struct addrinfo *res, *ptr; struct addrinfo *res, *ptr;
@ -116,20 +167,50 @@ bool Socket::Connect( const char* addr, int port )
int val = 1; int val = 1;
setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) ); setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) );
#endif #endif
if( connect( sock, ptr->ai_addr, ptr->ai_addrlen ) == -1 ) #if defined _WIN32 || defined __CYGWIN__
{ u_long nonblocking = 1;
#ifdef _WIN32 ioctlsocket( sock, FIONBIO, &nonblocking );
closesocket( sock );
#else #else
close( sock ); int flags = fcntl( sock, F_GETFL, 0 );
fcntl( sock, F_SETFL, flags | O_NONBLOCK );
#endif #endif
if( connect( sock, ptr->ai_addr, ptr->ai_addrlen ) == 0 )
{
break;
}
else
{
#if defined _WIN32 || defined __CYGWIN__
const auto err = WSAGetLastError();
if( err != WSAEWOULDBLOCK )
{
closesocket( sock );
continue; continue;
} }
break; #else
if( errno != EINPROGRESS )
{
close( sock );
continue;
}
#endif
}
m_res = res;
m_ptr = ptr;
m_connSock = sock;
return false;
} }
freeaddrinfo( res ); freeaddrinfo( res );
if( !ptr ) return false; if( !ptr ) return false;
#if defined _WIN32 || defined __CYGWIN__
u_long nonblocking = 0;
ioctlsocket( sock, FIONBIO, &nonblocking );
#else
int flags = fcntl( sock, F_GETFL, 0 );
fcntl( sock, F_SETFL, flags & ~O_NONBLOCK );
#endif
m_sock.store( sock, std::memory_order_relaxed ); m_sock.store( sock, std::memory_order_relaxed );
return true; return true;
} }

View File

@ -6,6 +6,7 @@
#include "TracyForceInline.hpp" #include "TracyForceInline.hpp"
struct addrinfo;
struct sockaddr; struct sockaddr;
namespace tracy namespace tracy
@ -61,6 +62,10 @@ private:
char* m_bufPtr; char* m_bufPtr;
std::atomic<int> m_sock; std::atomic<int> m_sock;
int m_bufLeft; int m_bufLeft;
struct addrinfo *m_res;
struct addrinfo *m_ptr;
int m_connSock;
}; };
class ListenSocket class ListenSocket