| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748 |
- #include <assert.h>
- #include <inttypes.h>
- #include <new>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include "TracyAlloc.hpp"
- #include "TracySocket.hpp"
- #ifdef _WIN32
- # ifndef NOMINMAX
- # define NOMINMAX
- # endif
- # include <winsock2.h>
- # include <ws2tcpip.h>
- # ifdef _MSC_VER
- # pragma warning(disable:4244)
- # pragma warning(disable:4267)
- # endif
- # define poll WSAPoll
- #else
- # include <arpa/inet.h>
- # include <sys/socket.h>
- # include <sys/param.h>
- # include <errno.h>
- # include <fcntl.h>
- # include <netinet/in.h>
- # include <netdb.h>
- # include <unistd.h>
- # include <poll.h>
- #endif
- #ifndef MSG_NOSIGNAL
- # define MSG_NOSIGNAL 0
- #endif
- namespace tracy
- {
- #ifdef _WIN32
- typedef SOCKET socket_t;
- #else
- typedef int socket_t;
- #endif
- #ifdef _WIN32
- struct __wsinit
- {
- __wsinit()
- {
- WSADATA wsaData;
- if( WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) != 0 )
- {
- fprintf( stderr, "Cannot init winsock.\n" );
- exit( 1 );
- }
- }
- };
- void InitWinSock()
- {
- static __wsinit init;
- }
- #endif
- enum { BufSize = 128 * 1024 };
- Socket::Socket()
- : m_buf( (char*)tracy_malloc( BufSize ) )
- , m_bufPtr( nullptr )
- , m_sock( -1 )
- , m_bufLeft( 0 )
- , m_ptr( nullptr )
- {
- #ifdef _WIN32
- InitWinSock();
- #endif
- }
- Socket::Socket( int sock )
- : m_buf( (char*)tracy_malloc( BufSize ) )
- , m_bufPtr( nullptr )
- , m_sock( sock )
- , m_bufLeft( 0 )
- , m_ptr( nullptr )
- {
- }
- Socket::~Socket()
- {
- tracy_free( m_buf );
- if( m_sock.load( std::memory_order_relaxed ) != -1 )
- {
- Close();
- }
- if( m_ptr )
- {
- freeaddrinfo( m_res );
- #ifdef _WIN32
- closesocket( m_connSock );
- #else
- close( m_connSock );
- #endif
- }
- }
- bool Socket::Connect( const char* addr, uint16_t port )
- {
- assert( !IsValid() );
- if( m_ptr )
- {
- const auto c = connect( m_connSock, m_ptr->ai_addr, m_ptr->ai_addrlen );
- if( c == -1 )
- {
- #if defined _WIN32
- 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
- }
- #if defined _WIN32
- 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 *res, *ptr;
- memset( &hints, 0, sizeof( hints ) );
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- char portbuf[32];
- sprintf( portbuf, "%" PRIu16, port );
- if( getaddrinfo( addr, portbuf, &hints, &res ) != 0 ) return false;
- 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
- 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 )
- {
- break;
- }
- else
- {
- #if defined _WIN32
- const auto err = WSAGetLastError();
- if( err != WSAEWOULDBLOCK )
- {
- closesocket( sock );
- continue;
- }
- #else
- if( errno != EINPROGRESS )
- {
- close( sock );
- continue;
- }
- #endif
- }
- m_res = res;
- m_ptr = ptr;
- m_connSock = sock;
- return false;
- }
- freeaddrinfo( res );
- if( !ptr ) return false;
- #if defined _WIN32
- 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 );
- return true;
- }
- bool Socket::ConnectBlocking( const char* addr, uint16_t port )
- {
- assert( !IsValid() );
- assert( !m_ptr );
- 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, "%" PRIu16, port );
- if( getaddrinfo( addr, portbuf, &hints, &res ) != 0 ) return false;
- 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( connect( sock, ptr->ai_addr, ptr->ai_addrlen ) == -1 )
- {
- #ifdef _WIN32
- closesocket( sock );
- #else
- close( sock );
- #endif
- continue;
- }
- break;
- }
- freeaddrinfo( res );
- if( !ptr ) return false;
- m_sock.store( sock, std::memory_order_relaxed );
- return true;
- }
- void Socket::Close()
- {
- const auto sock = m_sock.load( std::memory_order_relaxed );
- assert( sock != -1 );
- #ifdef _WIN32
- closesocket( sock );
- #else
- close( sock );
- #endif
- m_sock.store( -1, std::memory_order_relaxed );
- }
- int Socket::Send( const void* _buf, int len )
- {
- const auto sock = m_sock.load( std::memory_order_relaxed );
- auto buf = (const char*)_buf;
- assert( sock != -1 );
- auto start = buf;
- while( len > 0 )
- {
- auto ret = send( sock, buf, len, MSG_NOSIGNAL );
- if( ret == -1 ) return -1;
- len -= ret;
- buf += ret;
- }
- return int( buf - start );
- }
- int Socket::GetSendBufSize()
- {
- const auto sock = m_sock.load( std::memory_order_relaxed );
- int bufSize;
- #if defined _WIN32
- int sz = sizeof( bufSize );
- getsockopt( sock, SOL_SOCKET, SO_SNDBUF, (char*)&bufSize, &sz );
- #else
- socklen_t sz = sizeof( bufSize );
- getsockopt( sock, SOL_SOCKET, SO_SNDBUF, &bufSize, &sz );
- #endif
- return bufSize;
- }
- 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;
- }
- if( len >= BufSize ) return Recv( buf, len, timeout );
- m_bufLeft = Recv( m_buf, BufSize, timeout );
- if( m_bufLeft <= 0 ) return m_bufLeft;
- const auto sz = len < m_bufLeft ? len : m_bufLeft;
- memcpy( buf, m_buf, sz );
- m_bufPtr = m_buf + sz;
- m_bufLeft -= sz;
- return sz;
- }
- int Socket::Recv( void* _buf, int len, int timeout )
- {
- const auto sock = m_sock.load( std::memory_order_relaxed );
- auto buf = (char*)_buf;
- struct pollfd fd;
- fd.fd = (socket_t)sock;
- fd.events = POLLIN;
- if( poll( &fd, 1, timeout ) > 0 )
- {
- return recv( sock, buf, len, 0 );
- }
- else
- {
- return -1;
- }
- }
- int Socket::ReadUpTo( void* _buf, int len, int timeout )
- {
- const auto sock = m_sock.load( std::memory_order_relaxed );
- auto buf = (char*)_buf;
- int rd = 0;
- while( len > 0 )
- {
- const auto res = recv( sock, buf, len, 0 );
- if( res == 0 ) break;
- if( res == -1 ) return -1;
- len -= res;
- rd += res;
- buf += res;
- }
- return rd;
- }
- 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;
- }
- bool Socket::ReadImpl( char*& buf, int& len, int timeout )
- {
- const auto sz = RecvBuffered( buf, len, timeout );
- switch( sz )
- {
- case 0:
- return false;
- case -1:
- #ifdef _WIN32
- {
- auto err = WSAGetLastError();
- if( err == WSAECONNABORTED || err == WSAECONNRESET ) return false;
- }
- #endif
- break;
- default:
- len -= sz;
- buf += sz;
- break;
- }
- return true;
- }
- bool Socket::ReadRaw( void* _buf, int len, int timeout )
- {
- auto buf = (char*)_buf;
- while( len > 0 )
- {
- const auto sz = Recv( buf, len, timeout );
- if( sz <= 0 ) return false;
- len -= sz;
- buf += sz;
- }
- return true;
- }
- bool Socket::HasData()
- {
- const auto sock = m_sock.load( std::memory_order_relaxed );
- if( m_bufLeft > 0 ) return true;
- struct pollfd fd;
- fd.fd = (socket_t)sock;
- fd.events = POLLIN;
- return poll( &fd, 1, 0 ) > 0;
- }
- bool Socket::IsValid() const
- {
- return m_sock.load( std::memory_order_relaxed ) >= 0;
- }
- ListenSocket::ListenSocket()
- : m_sock( -1 )
- {
- #ifdef _WIN32
- InitWinSock();
- #endif
- }
- ListenSocket::~ListenSocket()
- {
- if( m_sock != -1 ) Close();
- }
- static int addrinfo_and_socket_for_family( uint16_t port, int ai_family, struct addrinfo** res )
- {
- struct addrinfo hints;
- memset( &hints, 0, sizeof( hints ) );
- hints.ai_family = ai_family;
- 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
- char portbuf[32];
- sprintf( portbuf, "%" PRIu16, 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;
- }
- bool ListenSocket::Listen( uint16_t port, int backlog )
- {
- assert( m_sock == -1 );
- struct addrinfo* res = nullptr;
- #if !defined TRACY_ONLY_IPV4 && !defined TRACY_ONLY_LOCALHOST
- 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 );
- if( m_sock == -1 ) return false;
- }
- #if defined _WIN32 || defined __CYGWIN__
- unsigned long val = 0;
- setsockopt( m_sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&val, sizeof( val ) );
- #elif defined BSD
- int val = 0;
- setsockopt( m_sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&val, sizeof( val ) );
- 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 ) );
- #endif
- 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; }
- freeaddrinfo( res );
- return true;
- }
- Socket* ListenSocket::Accept()
- {
- struct sockaddr_storage remote;
- socklen_t sz = sizeof( remote );
- struct pollfd fd;
- fd.fd = (socket_t)m_sock;
- fd.events = POLLIN;
- if( poll( &fd, 1, 10 ) > 0 )
- {
- int sock = accept( m_sock, (sockaddr*)&remote, &sz);
- if( sock == -1 ) return nullptr;
- #if defined __APPLE__
- int val = 1;
- setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) );
- #endif
- auto ptr = (Socket*)tracy_malloc( sizeof( Socket ) );
- new(ptr) Socket( sock );
- return ptr;
- }
- else
- {
- return nullptr;
- }
- }
- void ListenSocket::Close()
- {
- assert( m_sock != -1 );
- #ifdef _WIN32
- closesocket( m_sock );
- #else
- close( m_sock );
- #endif
- m_sock = -1;
- }
- UdpBroadcast::UdpBroadcast()
- : m_sock( -1 )
- {
- #ifdef _WIN32
- InitWinSock();
- #endif
- }
- UdpBroadcast::~UdpBroadcast()
- {
- if( m_sock != -1 ) Close();
- }
- bool UdpBroadcast::Open( const char* addr, uint16_t port )
- {
- 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;
- char portbuf[32];
- sprintf( portbuf, "%" PRIu16, port );
- if( getaddrinfo( addr, portbuf, &hints, &res ) != 0 ) return false;
- 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
- 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;
- inet_pton( AF_INET, addr, &m_addr );
- return true;
- }
- void UdpBroadcast::Close()
- {
- assert( m_sock != -1 );
- #ifdef _WIN32
- closesocket( m_sock );
- #else
- close( m_sock );
- #endif
- m_sock = -1;
- }
- int UdpBroadcast::Send( uint16_t port, const void* data, int len )
- {
- assert( m_sock != -1 );
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons( port );
- addr.sin_addr.s_addr = m_addr;
- 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( uint16_t 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
- 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
- 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, int timeout )
- {
- static char buf[2048];
- struct pollfd fd;
- fd.fd = (socket_t)m_sock;
- fd.events = POLLIN;
- if( poll( &fd, 1, timeout ) <= 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;
- }
- }
|