tracy/common/TracySocket.cpp

687 lines
15 KiB
C++
Raw Normal View History

2017-09-11 20:51:11 +00:00
#include <assert.h>
2017-10-18 17:49:17 +00:00
#include <new>
2017-09-11 20:51:11 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
2017-10-18 17:49:17 +00:00
#include "TracyAlloc.hpp"
2017-09-11 20:51:11 +00:00
#include "TracySocket.hpp"
2019-01-19 11:03:30 +00:00
#ifdef _WIN32
2019-10-10 18:29:06 +00:00
# ifndef NOMINMAX
# define NOMINMAX
# endif
2017-09-11 20:51:11 +00:00
# include <winsock2.h>
# include <ws2tcpip.h>
2019-01-19 11:03:30 +00:00
# ifdef _MSC_VER
# pragma warning(disable:4244)
# pragma warning(disable:4267)
# endif
2019-02-10 14:45:23 +00:00
# define poll WSAPoll
2017-09-11 20:51:11 +00:00
#else
2019-06-17 17:51:58 +00:00
# include <arpa/inet.h>
2017-09-11 20:51:11 +00:00
# include <sys/socket.h>
2019-11-21 01:03:32 +00:00
# include <sys/param.h>
# include <errno.h>
# include <fcntl.h>
# include <netinet/in.h>
2017-09-11 20:51:11 +00:00
# include <netdb.h>
# include <unistd.h>
2019-02-10 14:45:23 +00:00
# include <poll.h>
2017-09-11 20:51:11 +00:00
#endif
#ifndef MSG_NOSIGNAL
# define MSG_NOSIGNAL 0
#endif
2017-09-11 20:51:11 +00:00
namespace tracy
{
2019-01-19 11:03:30 +00:00
#ifdef _WIN32
typedef SOCKET socket_t;
#else
typedef int socket_t;
#endif
2019-01-19 11:03:30 +00:00
#ifdef _WIN32
struct __wsinit
2017-09-11 20:51:11 +00:00
{
__wsinit()
2017-09-11 20:51:11 +00:00
{
WSADATA wsaData;
if( WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) != 0 )
{
fprintf( stderr, "Cannot init winsock.\n" );
exit( 1 );
}
}
};
2018-08-19 15:45:03 +00:00
void InitWinSock()
{
static __wsinit init;
}
2017-09-11 20:51:11 +00:00
#endif
enum { BufSize = 128 * 1024 };
2017-09-11 20:51:11 +00:00
Socket::Socket()
: m_buf( (char*)tracy_malloc( BufSize ) )
, m_bufPtr( nullptr )
, m_sock( -1 )
, m_bufLeft( 0 )
, m_ptr( nullptr )
2017-09-11 20:51:11 +00:00
{
2019-01-19 11:03:30 +00:00
#ifdef _WIN32
InitWinSock();
#endif
2017-09-11 20:51:11 +00:00
}
Socket::Socket( int sock )
: m_buf( (char*)tracy_malloc( BufSize ) )
, m_bufPtr( nullptr )
, m_sock( sock )
, m_bufLeft( 0 )
, m_ptr( nullptr )
2017-09-11 20:51:11 +00:00
{
}
Socket::~Socket()
{
tracy_free( m_buf );
2020-05-13 17:12:52 +00:00
if( m_sock.load( std::memory_order_relaxed ) != -1 )
2017-09-11 20:51:11 +00:00
{
Close();
}
if( m_ptr )
{
freeaddrinfo( m_res );
#ifdef _WIN32
closesocket( m_connSock );
#else
close( m_connSock );
#endif
}
2017-09-11 20:51:11 +00:00
}
bool Socket::Connect( const char* addr, int port )
2017-09-11 20:51:11 +00:00
{
2020-05-13 17:12:52 +00:00
assert( !IsValid() );
2017-09-11 20:51:11 +00:00
if( m_ptr )
{
const auto c = connect( m_connSock, m_ptr->ai_addr, m_ptr->ai_addrlen );
if( 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
const auto err = errno;
if( err == EALREADY || err == EINPROGRESS ) return false;
if( err != EISCONN )
{
freeaddrinfo( m_res );
close( m_connSock );
m_ptr = nullptr;
return false;
}
#endif
2020-06-20 16:50:05 +00:00
}
#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;
}
2017-09-11 20:51:11 +00:00
struct addrinfo hints;
struct addrinfo *res, *ptr;
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
char portbuf[32];
sprintf( portbuf, "%i", port );
if( getaddrinfo( addr, portbuf, &hints, &res ) != 0 ) return false;
2018-08-01 12:07:30 +00:00
int sock = 0;
2017-09-11 20:51:11 +00:00
for( ptr = res; ptr; ptr = ptr->ai_next )
{
if( ( sock = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ) ) == -1 ) continue;
2017-11-03 10:09:31 +00:00
#if defined __APPLE__
2017-11-02 10:37:10 +00:00
int val = 1;
2019-04-01 18:14:00 +00:00
setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) );
2017-11-02 10:37:10 +00:00
#endif
#if defined _WIN32 || defined __CYGWIN__
u_long nonblocking = 1;
ioctlsocket( sock, FIONBIO, &nonblocking );
#else
int flags = fcntl( sock, F_GETFL, 0 );
fcntl( sock, F_SETFL, flags | O_NONBLOCK );
#endif
if( connect( sock, ptr->ai_addr, ptr->ai_addrlen ) == 0 )
2017-09-11 20:51:11 +00:00
{
break;
}
else
{
#if defined _WIN32 || defined __CYGWIN__
const auto err = WSAGetLastError();
if( err != WSAEWOULDBLOCK )
{
closesocket( sock );
continue;
}
2017-09-11 20:51:11 +00:00
#else
if( errno != EINPROGRESS )
{
close( sock );
continue;
}
2017-09-11 20:51:11 +00:00
#endif
}
m_res = res;
m_ptr = ptr;
m_connSock = sock;
return false;
2017-09-11 20:51:11 +00:00
}
freeaddrinfo( res );
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
2020-05-13 17:12:52 +00:00
m_sock.store( sock, std::memory_order_relaxed );
2017-09-11 20:51:11 +00:00
return true;
}
void Socket::Close()
{
2020-05-13 17:12:52 +00:00
const auto sock = m_sock.load( std::memory_order_relaxed );
assert( sock != -1 );
2019-01-19 11:03:30 +00:00
#ifdef _WIN32
2020-05-13 17:12:52 +00:00
closesocket( sock );
2017-09-11 20:51:11 +00:00
#else
2020-05-13 17:12:52 +00:00
close( sock );
2017-09-11 20:51:11 +00:00
#endif
2020-05-13 17:12:52 +00:00
m_sock.store( -1, std::memory_order_relaxed );
2017-09-11 20:51:11 +00:00
}
int Socket::Send( const void* _buf, int len )
{
2020-05-13 17:12:52 +00:00
const auto sock = m_sock.load( std::memory_order_relaxed );
2017-09-11 20:51:11 +00:00
auto buf = (const char*)_buf;
2020-05-13 17:12:52 +00:00
assert( sock != -1 );
2017-09-11 20:51:11 +00:00
auto start = buf;
while( len > 0 )
{
2020-05-13 17:12:52 +00:00
auto ret = send( sock, buf, len, MSG_NOSIGNAL );
2017-09-11 20:51:11 +00:00
if( ret == -1 ) return -1;
len -= ret;
buf += ret;
}
2017-10-16 18:42:53 +00:00
return int( buf - start );
2017-09-11 20:51:11 +00:00
}
int Socket::GetSendBufSize()
{
2020-05-13 17:12:52 +00:00
const auto sock = m_sock.load( std::memory_order_relaxed );
int bufSize;
#if defined _WIN32 || defined __CYGWIN__
2019-04-01 18:43:42 +00:00
int sz = sizeof( bufSize );
2020-05-13 17:12:52 +00:00
getsockopt( sock, SOL_SOCKET, SO_SNDBUF, (char*)&bufSize, &sz );
#else
2019-04-01 18:43:42 +00:00
socklen_t sz = sizeof( bufSize );
2020-05-13 17:12:52 +00:00
getsockopt( sock, SOL_SOCKET, SO_SNDBUF, &bufSize, &sz );
#endif
return bufSize;
}
2019-02-10 14:45:23 +00:00
int Socket::RecvBuffered( void* buf, int len, int timeout )
{
if( len <= m_bufLeft )
{
memcpy( buf, m_bufPtr, len );
m_bufPtr += len;
m_bufLeft -= len;
return len;
}
if( m_bufLeft > 0 )
{
memcpy( buf, m_bufPtr, m_bufLeft );
const auto ret = m_bufLeft;
m_bufLeft = 0;
return ret;
}
2019-02-10 14:45:23 +00:00
if( len >= BufSize ) return Recv( buf, len, timeout );
2019-02-10 14:45:23 +00:00
m_bufLeft = Recv( m_buf, BufSize, timeout );
if( m_bufLeft <= 0 ) return m_bufLeft;
2019-11-05 19:09:40 +00:00
const auto sz = len < m_bufLeft ? len : m_bufLeft;
memcpy( buf, m_buf, sz );
m_bufPtr = m_buf + sz;
m_bufLeft -= sz;
return sz;
}
2019-02-10 14:45:23 +00:00
int Socket::Recv( void* _buf, int len, int timeout )
2017-09-11 20:51:11 +00:00
{
2020-05-13 17:12:52 +00:00
const auto sock = m_sock.load( std::memory_order_relaxed );
2017-09-11 20:51:11 +00:00
auto buf = (char*)_buf;
2017-09-12 23:53:47 +00:00
2019-02-10 14:45:23 +00:00
struct pollfd fd;
2020-05-13 17:12:52 +00:00
fd.fd = (socket_t)sock;
2019-02-10 14:45:23 +00:00
fd.events = POLLIN;
2017-09-12 23:53:47 +00:00
2019-02-10 14:45:23 +00:00
if( poll( &fd, 1, timeout ) > 0 )
2017-09-12 23:53:47 +00:00
{
2020-05-13 17:12:52 +00:00
return recv( sock, buf, len, 0 );
2017-09-12 23:53:47 +00:00
}
else
2017-09-11 20:51:11 +00:00
{
2017-09-12 23:53:47 +00:00
return -1;
2017-09-11 20:51:11 +00:00
}
}
bool Socket::Read( void* buf, int len, int timeout )
{
auto cbuf = (char*)buf;
while( len > 0 )
{
if( !ReadImpl( cbuf, len, timeout ) ) return false;
}
return true;
}
2020-04-13 12:14:36 +00:00
bool Socket::ReadImpl( char*& buf, int& len, int timeout )
2017-09-13 00:08:30 +00:00
{
2020-04-13 12:14:36 +00:00
const auto sz = RecvBuffered( buf, len, timeout );
switch( sz )
2017-09-13 00:08:30 +00:00
{
2020-04-13 12:14:36 +00:00
case 0:
return false;
case -1:
2017-09-15 19:43:57 +00:00
#ifdef _WIN32
2020-04-13 12:14:36 +00:00
{
auto err = WSAGetLastError();
if( err == WSAECONNABORTED || err == WSAECONNRESET ) return false;
}
2017-09-15 19:43:57 +00:00
#endif
2020-04-13 12:14:36 +00:00
break;
default:
len -= sz;
buf += sz;
break;
2017-09-13 00:08:30 +00:00
}
return true;
}
2019-02-10 14:45:23 +00:00
bool Socket::ReadRaw( void* _buf, int len, int timeout )
2018-09-09 16:24:58 +00:00
{
auto buf = (char*)_buf;
while( len > 0 )
{
2019-02-10 14:45:23 +00:00
const auto sz = Recv( buf, len, timeout );
2018-09-09 16:24:58 +00:00
if( sz <= 0 ) return false;
len -= sz;
buf += sz;
}
return true;
}
bool Socket::HasData()
{
2020-05-13 17:12:52 +00:00
const auto sock = m_sock.load( std::memory_order_relaxed );
if( m_bufLeft > 0 ) return true;
2019-02-10 14:45:23 +00:00
struct pollfd fd;
2020-05-13 17:12:52 +00:00
fd.fd = (socket_t)sock;
2019-02-10 14:45:23 +00:00
fd.events = POLLIN;
2019-02-10 14:45:23 +00:00
return poll( &fd, 1, 0 ) > 0;
}
2019-12-19 16:23:40 +00:00
bool Socket::IsValid() const
{
2020-05-13 17:12:52 +00:00
return m_sock.load( std::memory_order_relaxed ) >= 0;
2019-12-19 16:23:40 +00:00
}
2017-09-11 20:51:11 +00:00
ListenSocket::ListenSocket()
: m_sock( -1 )
{
2019-01-19 11:03:30 +00:00
#ifdef _WIN32
InitWinSock();
#endif
2017-09-11 20:51:11 +00:00
}
ListenSocket::~ListenSocket()
{
2019-06-09 16:14:04 +00:00
if( m_sock != -1 ) Close();
2017-09-11 20:51:11 +00:00
}
static int addrinfo_and_socket_for_family(int port, int ai_family, struct addrinfo** res)
2017-09-11 20:51:11 +00:00
{
struct addrinfo hints;
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = ai_family;
2017-09-11 20:51:11 +00:00
hints.ai_socktype = SOCK_STREAM;
#ifndef TRACY_ONLY_LOCALHOST
const char* onlyLocalhost = getenv( "TRACY_ONLY_LOCALHOST" );
if( !onlyLocalhost || onlyLocalhost[0] != '1' )
{
hints.ai_flags = AI_PASSIVE;
}
#endif
2019-09-21 13:11:15 +00:00
char portbuf[32];
sprintf( portbuf, "%i", port );
if( getaddrinfo( nullptr, portbuf, &hints, res ) != 0 ) return -1;
int sock = socket( (*res)->ai_family, (*res)->ai_socktype, (*res)->ai_protocol );
if (sock == -1) freeaddrinfo( *res );
return sock;
}
2019-09-21 13:11:15 +00:00
bool ListenSocket::Listen( int port, int backlog )
{
assert( m_sock == -1 );
2017-09-11 20:51:11 +00:00
struct addrinfo* res = nullptr;
#ifndef TRACY_ONLY_IPV4
const char* onlyIPv4 = getenv( "TRACY_ONLY_IPV4" );
if( !onlyIPv4 || onlyIPv4[0] != '1' )
{
m_sock = addrinfo_and_socket_for_family(port, AF_INET6, &res);
}
#endif
if (m_sock == -1)
{
// IPV6 protocol may not be available/is disabled. Try to create a socket
// with the IPV4 protocol
m_sock = addrinfo_and_socket_for_family(port, AF_INET, &res);
2020-04-13 19:39:51 +00:00
if( m_sock == -1 ) return false;
}
2019-01-19 11:03:30 +00:00
#if defined _WIN32 || defined __CYGWIN__
unsigned long val = 0;
2017-09-11 20:51:11 +00:00
setsockopt( m_sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&val, sizeof( val ) );
2019-11-21 01:03:32 +00:00
#elif defined BSD
int val = 0;
setsockopt( m_sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&val, sizeof( val ) );
2019-11-21 19:38:15 +00:00
val = 1;
setsockopt( m_sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof( val ) );
#else
int val = 1;
setsockopt( m_sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof( val ) );
2017-09-11 20:51:11 +00:00
#endif
2020-04-13 19:40:35 +00:00
if( bind( m_sock, res->ai_addr, res->ai_addrlen ) == -1 ) { freeaddrinfo( res ); Close(); return false; }
if( listen( m_sock, backlog ) == -1 ) { freeaddrinfo( res ); Close(); return false; }
2019-10-27 12:39:01 +00:00
freeaddrinfo( res );
2017-09-11 20:51:11 +00:00
return true;
}
2017-10-18 17:49:17 +00:00
Socket* ListenSocket::Accept()
2017-09-11 20:51:11 +00:00
{
struct sockaddr_storage remote;
socklen_t sz = sizeof( remote );
2019-02-10 14:45:23 +00:00
struct pollfd fd;
fd.fd = (socket_t)m_sock;
fd.events = POLLIN;
2017-09-11 20:51:11 +00:00
2019-02-10 14:45:23 +00:00
if( poll( &fd, 1, 10 ) > 0 )
2017-09-11 20:51:11 +00:00
{
int sock = accept( m_sock, (sockaddr*)&remote, &sz);
if( sock == -1 ) return nullptr;
2017-11-03 10:09:31 +00:00
#if defined __APPLE__
2017-11-02 10:37:10 +00:00
int val = 1;
2017-11-03 10:20:39 +00:00
setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) );
2017-11-02 10:37:10 +00:00
#endif
auto ptr = (Socket*)tracy_malloc( sizeof( Socket ) );
new(ptr) Socket( sock );
return ptr;
2017-09-11 20:51:11 +00:00
}
else
{
return nullptr;
}
}
void ListenSocket::Close()
{
assert( m_sock != -1 );
2019-01-19 11:03:30 +00:00
#ifdef _WIN32
2017-09-11 20:51:11 +00:00
closesocket( m_sock );
#else
close( m_sock );
#endif
m_sock = -1;
}
2019-06-17 00:24:55 +00:00
UdpBroadcast::UdpBroadcast()
: m_sock( -1 )
{
#ifdef _WIN32
InitWinSock();
#endif
}
UdpBroadcast::~UdpBroadcast()
{
if( m_sock != -1 ) Close();
}
2019-09-21 13:11:15 +00:00
bool UdpBroadcast::Open( const char* addr, int port )
2019-06-17 00:24:55 +00:00
{
assert( m_sock == -1 );
struct addrinfo hints;
struct addrinfo *res, *ptr;
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
2019-09-21 13:11:15 +00:00
char portbuf[32];
sprintf( portbuf, "%i", port );
if( getaddrinfo( addr, portbuf, &hints, &res ) != 0 ) return false;
2019-06-17 00:24:55 +00:00
int sock = 0;
for( ptr = res; ptr; ptr = ptr->ai_next )
{
if( ( sock = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ) ) == -1 ) continue;
#if defined __APPLE__
int val = 1;
setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) );
#endif
#if defined _WIN32 || defined __CYGWIN__
unsigned long broadcast = 1;
if( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof( broadcast ) ) == -1 )
#else
int broadcast = 1;
if( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof( broadcast ) ) == -1 )
#endif
{
#ifdef _WIN32
closesocket( sock );
#else
close( sock );
#endif
continue;
}
break;
}
freeaddrinfo( res );
if( !ptr ) return false;
m_sock = sock;
return true;
}
void UdpBroadcast::Close()
{
assert( m_sock != -1 );
#ifdef _WIN32
closesocket( m_sock );
#else
close( m_sock );
#endif
m_sock = -1;
}
2019-06-17 16:37:34 +00:00
int UdpBroadcast::Send( int port, const void* data, int len )
2019-06-17 00:24:55 +00:00
{
assert( m_sock != -1 );
struct sockaddr_in addr;
addr.sin_family = AF_INET;
2019-06-17 16:37:34 +00:00
addr.sin_port = htons( port );
2019-06-17 00:24:55 +00:00
addr.sin_addr.s_addr = INADDR_BROADCAST;
return sendto( m_sock, (const char*)data, len, MSG_NOSIGNAL, (sockaddr*)&addr, sizeof( addr ) );
}
IpAddress::IpAddress()
: m_number( 0 )
{
*m_text = '\0';
}
IpAddress::~IpAddress()
{
}
void IpAddress::Set( const struct sockaddr& addr )
{
#if defined _WIN32 && ( !defined NTDDI_WIN10 || NTDDI_VERSION < NTDDI_WIN10 )
struct sockaddr_in tmp;
memcpy( &tmp, &addr, sizeof( tmp ) );
auto ai = &tmp;
#else
auto ai = (const struct sockaddr_in*)&addr;
#endif
inet_ntop( AF_INET, &ai->sin_addr, m_text, 17 );
m_number = ai->sin_addr.s_addr;
}
UdpListen::UdpListen()
: m_sock( -1 )
{
#ifdef _WIN32
InitWinSock();
#endif
}
UdpListen::~UdpListen()
{
if( m_sock != -1 ) Close();
}
bool UdpListen::Listen( int port )
{
assert( m_sock == -1 );
int sock;
if( ( sock = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 ) return false;
#if defined __APPLE__
int val = 1;
setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) );
#endif
#if defined _WIN32 || defined __CYGWIN__
unsigned long reuse = 1;
setsockopt( m_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof( reuse ) );
#else
int reuse = 1;
setsockopt( m_sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof( reuse ) );
#endif
#if defined _WIN32 || defined __CYGWIN__
unsigned long broadcast = 1;
if( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof( broadcast ) ) == -1 )
#else
int broadcast = 1;
if( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof( broadcast ) ) == -1 )
#endif
{
#ifdef _WIN32
closesocket( sock );
#else
close( sock );
#endif
return false;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons( port );
addr.sin_addr.s_addr = INADDR_ANY;
if( bind( sock, (sockaddr*)&addr, sizeof( addr ) ) == -1 )
{
#ifdef _WIN32
closesocket( sock );
#else
close( sock );
#endif
return false;
}
m_sock = sock;
return true;
}
void UdpListen::Close()
{
assert( m_sock != -1 );
#ifdef _WIN32
closesocket( m_sock );
#else
close( m_sock );
#endif
m_sock = -1;
}
const char* UdpListen::Read( size_t& len, IpAddress& addr )
{
static char buf[2048];
struct pollfd fd;
fd.fd = (socket_t)m_sock;
fd.events = POLLIN;
if( poll( &fd, 1, 10 ) <= 0 ) return nullptr;
sockaddr sa;
socklen_t salen = sizeof( struct sockaddr );
len = (size_t)recvfrom( m_sock, buf, 2048, 0, &sa, &salen );
addr.Set( sa );
return buf;
}
2017-09-11 20:51:11 +00:00
}