2021-08-22 10:20:59 +00:00
/*
* This file is part of the Monero P2Pool < https : //github.com/SChernykh/p2pool>
2023-01-04 12:07:55 +00:00
* Copyright ( c ) 2021 - 2023 SChernykh < https : //github.com/SChernykh>
2021-08-22 10:20:59 +00:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , version 3.
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2023-04-19 09:36:12 +00:00
# include "common.h"
# include "tcp_server.h"
2021-08-26 17:14:04 +00:00
2023-04-19 09:36:12 +00:00
static thread_local void * server_event_loop_thread = nullptr ;
static thread_local const char * log_category_prefix = " TCPServer " ;
2021-08-22 10:20:59 +00:00
namespace p2pool {
2023-04-19 09:36:12 +00:00
TCPServer : : TCPServer ( int default_backlog , allocate_client_callback allocate_new_client )
2021-08-22 10:20:59 +00:00
: m_allocateNewClient ( allocate_new_client )
2023-04-19 09:36:12 +00:00
, m_defaultBacklog ( default_backlog )
2021-09-06 07:02:35 +00:00
, m_loopThread { }
2023-05-01 18:13:57 +00:00
, m_loopThreadRunning ( false )
2023-03-21 09:19:56 +00:00
# ifdef WITH_UPNP
, m_portMapping ( 0 )
# endif
2022-08-31 14:37:33 +00:00
, m_socks5ProxyV6 ( false )
, m_socks5ProxyIP { }
, m_socks5ProxyPort ( - 1 )
2021-09-06 07:02:35 +00:00
, m_finished ( 0 )
2021-08-22 10:20:59 +00:00
, m_listenPort ( - 1 )
2022-06-04 11:16:05 +00:00
, m_loop { }
2022-05-09 14:07:49 +00:00
, m_numConnections { 0 }
, m_numIncomingConnections { 0 }
2022-10-18 16:41:58 +00:00
, m_shutdownPrepare { }
, m_shutdownTimer { }
, m_shutdownCountdown ( 30 )
, m_numHandles ( 0 )
2021-08-22 10:20:59 +00:00
{
int err = uv_loop_init ( & m_loop ) ;
if ( err ) {
LOGERR ( 1 , " failed to create event loop, error " < < uv_err_name ( err ) ) ;
2023-01-14 11:19:25 +00:00
PANIC_STOP ( ) ;
2021-08-22 10:20:59 +00:00
}
2022-06-04 11:16:05 +00:00
// Init loop user data before running it
GetLoopUserData ( & m_loop ) ;
2022-05-23 13:46:15 +00:00
err = uv_async_init ( & m_loop , & m_dropConnectionsAsync , on_drop_connections ) ;
if ( err ) {
LOGERR ( 1 , " uv_async_init failed, error " < < uv_err_name ( err ) ) ;
2023-01-14 11:19:25 +00:00
PANIC_STOP ( ) ;
2022-05-23 13:46:15 +00:00
}
2021-08-26 21:27:05 +00:00
m_dropConnectionsAsync . data = this ;
2022-05-23 13:46:15 +00:00
err = uv_async_init ( & m_loop , & m_shutdownAsync , on_shutdown ) ;
if ( err ) {
LOGERR ( 1 , " uv_async_init failed, error " < < uv_err_name ( err ) ) ;
2023-01-14 11:19:25 +00:00
PANIC_STOP ( ) ;
2022-05-23 13:46:15 +00:00
}
2021-08-26 21:27:05 +00:00
m_shutdownAsync . data = this ;
2021-08-22 10:20:59 +00:00
uv_mutex_init_checked ( & m_bansLock ) ;
m_connectedClientsList = m_allocateNewClient ( ) ;
m_connectedClientsList - > m_next = m_connectedClientsList ;
m_connectedClientsList - > m_prev = m_connectedClientsList ;
}
2023-04-19 09:36:12 +00:00
TCPServer : : ~ TCPServer ( )
2021-08-22 10:20:59 +00:00
{
if ( m_finished . load ( ) = = 0 ) {
LOGERR ( 1 , " TCP wasn't shutdown properly " ) ;
shutdown_tcp ( ) ;
}
2021-08-26 21:27:05 +00:00
2021-08-26 17:14:04 +00:00
delete m_connectedClientsList ;
2021-08-22 10:20:59 +00:00
}
2023-04-19 09:36:12 +00:00
void TCPServer : : parse_address_list_internal ( const std : : string & address_list , Callback < void , bool , const std : : string & , const std : : string & , int > : : Base & & callback )
2021-08-22 10:20:59 +00:00
{
if ( address_list . empty ( ) ) {
return ;
}
std : : string address , ip ;
address . reserve ( 64 ) ;
ip . reserve ( 64 ) ;
for ( size_t k1 = 0 ; ; + + k1 ) {
const size_t next_k1 = address_list . find_first_of ( ' , ' , k1 ) ;
2021-08-23 20:24:26 +00:00
address = address_list . substr ( k1 , next_k1 - k1 ) ;
2021-08-22 10:20:59 +00:00
k1 = next_k1 ;
const size_t k2 = address . find_last_of ( ' : ' ) ;
if ( k2 ! = std : : string : : npos ) {
ip = address . substr ( 0 , k2 ) ;
const bool is_v6 = ( ip . find ( ' : ' ) ! = std : : string : : npos ) ;
if ( is_v6 ) {
if ( ! ip . empty ( ) & & ip . front ( ) = = ' [ ' ) {
ip . erase ( ip . begin ( ) ) ;
}
if ( ! ip . empty ( ) & & ip . back ( ) = = ' ] ' ) {
ip . pop_back ( ) ;
}
}
2023-05-10 19:22:51 +00:00
const int port = strtol ( address . substr ( k2 + 1 ) . c_str ( ) , nullptr , 10 ) ;
2021-10-13 12:56:27 +00:00
if ( ( port > 0 ) & & ( port < 65536 ) ) {
2021-08-22 10:20:59 +00:00
callback ( is_v6 , address , ip , port ) ;
}
else {
2023-04-19 09:36:12 +00:00
error_invalid_ip ( address ) ;
2021-08-22 10:20:59 +00:00
}
}
if ( k1 = = std : : string : : npos ) {
return ;
}
}
}
2023-04-19 09:36:12 +00:00
bool TCPServer : : start_listening ( bool is_v6 , const std : : string & ip , int port , std : : string address )
2021-08-22 10:20:59 +00:00
{
2023-04-18 13:38:24 +00:00
if ( ( m_listenPort > = 0 ) & & ( m_listenPort ! = port ) ) {
LOGERR ( 1 , " all sockets must be listening on the same port number, fix the command line " ) ;
return false ;
2021-08-22 10:20:59 +00:00
}
2023-04-18 13:38:24 +00:00
uv_tcp_t * socket = new uv_tcp_t ( ) ;
2021-08-22 10:20:59 +00:00
2023-04-18 13:38:24 +00:00
int err = uv_tcp_init ( & m_loop , socket ) ;
if ( err ) {
LOGERR ( 1 , " failed to create tcp server handle, error " < < uv_err_name ( err ) ) ;
delete socket ;
return false ;
}
socket - > data = this ;
2021-08-22 10:20:59 +00:00
2023-04-18 13:38:24 +00:00
ON_SCOPE_LEAVE ( [ is_v6 , this , socket ] ( )
{
const std : : vector < uv_tcp_t * > & v = is_v6 ? m_listenSockets6 : m_listenSockets ;
if ( std : : find ( v . begin ( ) , v . end ( ) , socket ) = = v . end ( ) ) {
uv_close ( reinterpret_cast < uv_handle_t * > ( socket ) , [ ] ( uv_handle_t * h ) { delete reinterpret_cast < uv_tcp_t * > ( h ) ; } ) ;
}
} ) ;
2021-08-22 10:20:59 +00:00
2023-04-18 13:38:24 +00:00
err = uv_tcp_nodelay ( socket , 1 ) ;
if ( err ) {
LOGERR ( 1 , " failed to set tcp_nodelay on tcp server handle, error " < < uv_err_name ( err ) ) ;
return false ;
}
2021-08-22 10:20:59 +00:00
2023-04-18 13:38:24 +00:00
if ( is_v6 ) {
if ( address . empty ( ) ) {
char buf [ 64 ] = { } ;
log : : Stream s ( buf ) ;
s < < ' [ ' < < ip < < " ]: " < < port ;
address = buf ;
}
2021-08-22 10:20:59 +00:00
2023-04-18 13:38:24 +00:00
sockaddr_in6 addr6 ;
err = uv_ip6_addr ( ip . c_str ( ) , port , & addr6 ) ;
if ( err ) {
LOGERR ( 1 , " failed to parse IPv6 address " < < ip < < " , error " < < uv_err_name ( err ) ) ;
return false ;
}
2021-08-22 10:20:59 +00:00
2023-04-18 13:38:24 +00:00
err = uv_tcp_bind ( socket , reinterpret_cast < sockaddr * > ( & addr6 ) , UV_TCP_IPV6ONLY ) ;
if ( err ) {
LOGERR ( 1 , " failed to bind tcp server IPv6 socket " < < address < < " , error " < < uv_err_name ( err ) ) ;
return false ;
}
}
else {
if ( address . empty ( ) ) {
char buf [ 64 ] = { } ;
log : : Stream s ( buf ) ;
s < < ip < < ' : ' < < port ;
address = buf ;
}
2021-08-22 10:20:59 +00:00
2023-04-18 13:38:24 +00:00
sockaddr_in addr ;
err = uv_ip4_addr ( ip . c_str ( ) , port , & addr ) ;
if ( err ) {
LOGERR ( 1 , " failed to parse IPv4 address " < < ip < < " , error " < < uv_err_name ( err ) ) ;
return false ;
}
err = uv_tcp_bind ( socket , reinterpret_cast < sockaddr * > ( & addr ) , 0 ) ;
if ( err ) {
LOGERR ( 1 , " failed to bind tcp server IPv4 socket " < < address < < " , error " < < uv_err_name ( err ) ) ;
return false ;
}
}
2023-04-19 09:36:12 +00:00
err = uv_listen ( reinterpret_cast < uv_stream_t * > ( socket ) , m_defaultBacklog , on_new_connection ) ;
2023-04-18 13:38:24 +00:00
if ( err ) {
LOGERR ( 1 , " failed to listen on tcp server socket " < < address < < " , error " < < uv_err_name ( err ) ) ;
return false ;
}
if ( is_v6 ) {
m_listenSockets6 . push_back ( socket ) ;
}
else {
m_listenSockets . push_back ( socket ) ;
}
2021-08-22 10:20:59 +00:00
2023-04-18 13:38:24 +00:00
if ( m_listenPort < 0 ) {
m_listenPort = port ;
}
LOGINFO ( 1 , " listening on " < < log : : Gray ( ) < < address ) ;
return true ;
}
2023-04-19 09:36:12 +00:00
void TCPServer : : start_listening ( const std : : string & listen_addresses , bool upnp )
2023-04-18 13:38:24 +00:00
{
if ( listen_addresses . empty ( ) ) {
LOGERR ( 1 , " listen address not set " ) ;
PANIC_STOP ( ) ;
}
parse_address_list ( listen_addresses ,
[ this ] ( bool is_v6 , const std : : string & /*address*/ , const std : : string & ip , int port )
{
if ( ! start_listening ( is_v6 , ip , port ) ) {
2023-01-14 11:19:25 +00:00
PANIC_STOP ( ) ;
2021-08-22 10:20:59 +00:00
}
} ) ;
2021-08-26 22:19:01 +00:00
2023-03-19 21:54:18 +00:00
# ifdef WITH_UPNP
if ( upnp ) {
2023-03-21 09:19:56 +00:00
m_portMapping = add_portmapping ( external_listen_port ( ) , m_listenPort ) ;
2023-03-19 21:54:18 +00:00
}
# else
( void ) upnp ;
# endif
2021-08-26 22:19:01 +00:00
const int err = uv_thread_create ( & m_loopThread , loop , this ) ;
if ( err ) {
LOGERR ( 1 , " failed to start event loop thread, error " < < uv_err_name ( err ) ) ;
2023-01-14 11:19:25 +00:00
PANIC_STOP ( ) ;
2021-08-26 22:19:01 +00:00
}
2021-08-22 10:20:59 +00:00
}
2023-04-19 09:36:12 +00:00
bool TCPServer : : connect_to_peer ( bool is_v6 , const char * ip , int port )
2021-08-22 10:20:59 +00:00
{
if ( ! ip | | ( strlen ( ip ) > sizeof ( Client : : m_addrString ) - 16 ) ) {
LOGERR ( 1 , " failed to parse IP address, too long " ) ;
return false ;
}
if ( m_finished . load ( ) ) {
return false ;
}
2023-02-17 07:47:52 +00:00
Client * client = get_client ( ) ;
2021-08-22 10:20:59 +00:00
client - > m_owner = this ;
client - > m_port = port ;
2022-08-31 14:37:33 +00:00
client - > m_isV6 = is_v6 ;
2021-08-22 10:20:59 +00:00
2022-08-31 14:37:33 +00:00
if ( ! str_to_ip ( is_v6 , ip , client - > m_addr ) ) {
2023-02-17 07:47:52 +00:00
return_client ( client ) ;
2022-08-31 14:37:33 +00:00
return false ;
}
2021-08-22 10:20:59 +00:00
2022-08-31 14:37:33 +00:00
log : : Stream s ( client - > m_addrString ) ;
2021-08-22 10:20:59 +00:00
if ( is_v6 ) {
s < < ' [ ' < < ip < < " ]: " < < port < < ' \0 ' ;
}
else {
s < < ip < < ' : ' < < port < < ' \0 ' ;
}
2022-08-31 14:37:33 +00:00
return connect_to_peer ( client ) ;
2021-08-22 10:20:59 +00:00
}
2023-04-19 09:36:12 +00:00
bool TCPServer : : connect_to_peer ( bool is_v6 , const raw_ip & ip , int port )
2021-08-22 10:20:59 +00:00
{
if ( m_finished . load ( ) ) {
return false ;
}
2023-02-17 07:47:52 +00:00
Client * client = get_client ( ) ;
2021-08-22 10:20:59 +00:00
client - > m_owner = this ;
client - > m_addr = ip ;
client - > m_port = port ;
2022-08-31 14:37:33 +00:00
client - > m_isV6 = is_v6 ;
client - > init_addr_string ( ) ;
2021-08-22 10:20:59 +00:00
2022-08-31 14:37:33 +00:00
return connect_to_peer ( client ) ;
2021-08-22 10:20:59 +00:00
}
2023-04-27 08:28:32 +00:00
bool TCPServer : : is_banned ( bool is_v6 , raw_ip ip )
2021-08-22 10:20:59 +00:00
{
2022-05-03 11:11:55 +00:00
if ( ip . is_localhost ( ) ) {
return false ;
}
2023-04-27 08:28:32 +00:00
// If it's IPv6, check the whole /64 prefix
if ( is_v6 & & ! ip . is_ipv4_prefix ( ) ) {
memset ( ip . data + 8 , 0 , sizeof ( ip . data ) - 8 ) ;
}
2022-02-21 17:41:36 +00:00
const auto cur_time = std : : chrono : : steady_clock : : now ( ) ;
2021-08-27 14:36:06 +00:00
MutexLock lock ( m_bansLock ) ;
2021-08-22 10:20:59 +00:00
2021-08-27 14:36:06 +00:00
auto it = m_bans . find ( ip ) ;
2021-10-29 12:24:05 +00:00
if ( it ! = m_bans . end ( ) ) {
2022-02-21 17:41:36 +00:00
const bool banned = ( cur_time < it - > second ) ;
2021-10-29 12:24:05 +00:00
if ( ! banned ) {
m_bans . erase ( it ) ;
}
return banned ;
2021-08-27 14:36:06 +00:00
}
return false ;
}
2023-04-19 09:36:12 +00:00
bool TCPServer : : connect_to_peer ( Client * client )
2021-08-27 14:36:06 +00:00
{
2023-04-27 08:28:32 +00:00
if ( is_banned ( client - > m_isV6 , client - > m_addr ) ) {
2021-08-27 14:36:06 +00:00
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( client - > m_addrString ) < < log : : NoColor ( ) < < " is banned, not connecting to it " ) ;
2023-02-17 07:47:52 +00:00
return_client ( client ) ;
2021-08-27 14:36:06 +00:00
return false ;
2021-08-22 10:20:59 +00:00
}
2022-09-05 13:14:10 +00:00
if ( ! m_pendingConnections . insert ( client - > m_addr ) . second ) {
LOGINFO ( 6 , " there is already a pending connection to this IP, not connecting to " < < log : : Gray ( ) < < static_cast < char * > ( client - > m_addrString ) ) ;
2023-02-17 07:47:52 +00:00
return_client ( client ) ;
2022-09-05 13:14:10 +00:00
return false ;
}
2021-08-22 10:20:59 +00:00
int err = uv_tcp_init ( & m_loop , & client - > m_socket ) ;
if ( err ) {
LOGERR ( 1 , " failed to create tcp client handle, error " < < uv_err_name ( err ) ) ;
2023-02-17 07:47:52 +00:00
return_client ( client ) ;
2021-08-22 10:20:59 +00:00
return false ;
}
2021-08-25 11:58:00 +00:00
client - > m_socket . data = client ;
2021-08-22 10:20:59 +00:00
err = uv_tcp_nodelay ( & client - > m_socket , 1 ) ;
if ( err ) {
LOGERR ( 1 , " failed to set tcp_nodelay on tcp client handle, error " < < uv_err_name ( err ) ) ;
2022-06-07 20:25:27 +00:00
uv_close ( reinterpret_cast < uv_handle_t * > ( & client - > m_socket ) , on_connection_error ) ;
2021-08-22 10:20:59 +00:00
return false ;
}
2023-04-19 09:36:12 +00:00
if ( client - > m_readBufSize < sizeof ( uv_connect_t ) ) {
LOGERR ( 1 , " client read buf size is too small ( " < < client - > m_readBufSize < < " bytes), expected at least " < < sizeof ( uv_connect_t ) < < " bytes " ) ;
uv_close ( reinterpret_cast < uv_handle_t * > ( & client - > m_socket ) , on_connection_error ) ;
return false ;
}
2021-08-22 10:20:59 +00:00
2022-05-07 10:29:45 +00:00
uv_connect_t * connect_request = reinterpret_cast < uv_connect_t * > ( client - > m_readBuf ) ;
memset ( connect_request , 0 , sizeof ( uv_connect_t ) ) ;
connect_request - > data = client ;
2022-08-31 14:37:33 +00:00
sockaddr_storage addr { } ;
if ( m_socks5Proxy . empty ( ) ) {
if ( client - > m_isV6 ) {
sockaddr_in6 * addr6 = reinterpret_cast < sockaddr_in6 * > ( & addr ) ;
addr6 - > sin6_family = AF_INET6 ;
memcpy ( & addr6 - > sin6_addr , client - > m_addr . data , sizeof ( in6_addr ) ) ;
addr6 - > sin6_port = htons ( static_cast < uint16_t > ( client - > m_port ) ) ;
}
else {
sockaddr_in * addr4 = reinterpret_cast < sockaddr_in * > ( & addr ) ;
addr4 - > sin_family = AF_INET ;
memcpy ( & addr4 - > sin_addr , client - > m_addr . data + 12 , sizeof ( in_addr ) ) ;
addr4 - > sin_port = htons ( static_cast < uint16_t > ( client - > m_port ) ) ;
}
}
else {
if ( m_socks5ProxyV6 ) {
sockaddr_in6 * addr6 = reinterpret_cast < sockaddr_in6 * > ( & addr ) ;
addr6 - > sin6_family = AF_INET6 ;
memcpy ( & addr6 - > sin6_addr , m_socks5ProxyIP . data , sizeof ( in6_addr ) ) ;
addr6 - > sin6_port = htons ( static_cast < uint16_t > ( m_socks5ProxyPort ) ) ;
}
else {
sockaddr_in * addr4 = reinterpret_cast < sockaddr_in * > ( & addr ) ;
addr4 - > sin_family = AF_INET ;
memcpy ( & addr4 - > sin_addr , m_socks5ProxyIP . data + 12 , sizeof ( in_addr ) ) ;
addr4 - > sin_port = htons ( static_cast < uint16_t > ( m_socks5ProxyPort ) ) ;
}
}
err = uv_tcp_connect ( connect_request , & client - > m_socket , reinterpret_cast < sockaddr * > ( & addr ) , on_connect ) ;
2021-08-22 10:20:59 +00:00
if ( err ) {
2023-01-18 19:57:45 +00:00
LOGWARN ( 5 , " failed to initiate tcp connection to " < < static_cast < const char * > ( client - > m_addrString ) < < " , error " < < uv_err_name ( err ) ) ;
2021-08-22 10:20:59 +00:00
m_pendingConnections . erase ( client - > m_addr ) ;
2022-06-07 20:25:27 +00:00
uv_close ( reinterpret_cast < uv_handle_t * > ( & client - > m_socket ) , on_connection_error ) ;
2021-08-22 10:20:59 +00:00
return false ;
}
else {
2022-08-27 08:52:02 +00:00
LOGINFO ( 5 , " connecting to " < < log : : Gray ( ) < < static_cast < const char * > ( client - > m_addrString ) ) ;
2021-08-22 10:20:59 +00:00
}
return true ;
}
2023-02-27 18:14:03 +00:00
# ifdef P2POOL_DEBUGGING
2023-04-19 09:36:12 +00:00
void TCPServer : : check_event_loop_thread ( const char * func ) const
2021-08-22 10:20:59 +00:00
{
2023-04-19 09:36:12 +00:00
if ( server_event_loop_thread ! = this ) {
2023-02-27 14:38:30 +00:00
LOGERR ( 1 , func < < " called from another thread, this is not thread safe " ) ;
2021-08-26 21:27:05 +00:00
}
2023-02-27 14:38:30 +00:00
}
2023-02-27 18:14:03 +00:00
# endif
2023-02-27 14:38:30 +00:00
2023-04-19 09:36:12 +00:00
void TCPServer : : close_sockets ( bool listen_sockets )
2023-02-27 14:38:30 +00:00
{
check_event_loop_thread ( __func__ ) ;
2021-08-26 21:27:05 +00:00
if ( listen_sockets ) {
for ( uv_tcp_t * s : m_listenSockets6 ) {
2021-09-13 17:11:59 +00:00
uv_handle_t * h = reinterpret_cast < uv_handle_t * > ( s ) ;
if ( ! uv_is_closing ( h ) ) {
uv_close ( h , [ ] ( uv_handle_t * h ) { delete reinterpret_cast < uv_tcp_t * > ( h ) ; } ) ;
}
2021-08-26 21:27:05 +00:00
}
for ( uv_tcp_t * s : m_listenSockets ) {
2021-09-13 17:11:59 +00:00
uv_handle_t * h = reinterpret_cast < uv_handle_t * > ( s ) ;
if ( ! uv_is_closing ( h ) ) {
uv_close ( h , [ ] ( uv_handle_t * h ) { delete reinterpret_cast < uv_tcp_t * > ( h ) ; } ) ;
}
2021-08-26 21:27:05 +00:00
}
}
2021-08-22 10:20:59 +00:00
size_t numClosed = 0 ;
2023-02-27 14:38:30 +00:00
for ( Client * c = m_connectedClientsList - > m_next ; c ! = m_connectedClientsList ; c = c - > m_next ) {
uv_handle_t * h = reinterpret_cast < uv_handle_t * > ( & c - > m_socket ) ;
if ( ! uv_is_closing ( h ) ) {
uv_close ( h , on_connection_close ) ;
+ + numClosed ;
2021-08-22 10:20:59 +00:00
}
}
if ( numClosed > 0 ) {
LOGWARN ( 1 , " closed " < < numClosed < < " active client connections " ) ;
}
}
2023-04-19 09:36:12 +00:00
void TCPServer : : error_invalid_ip ( const std : : string & address )
{
LOGERR ( 1 , " invalid IP:port " < < address ) ;
}
void TCPServer : : shutdown_tcp ( )
2021-08-22 10:20:59 +00:00
{
if ( m_finished . exchange ( 1 ) ) {
return ;
}
2021-08-26 21:27:05 +00:00
uv_async_send ( & m_shutdownAsync ) ;
2023-03-21 09:19:56 +00:00
# ifdef WITH_UPNP
if ( m_portMapping ) {
remove_portmapping ( m_portMapping ) ;
}
# endif
2023-05-01 18:13:57 +00:00
if ( m_loopThreadRunning . load ( ) ) {
uv_thread_join ( & m_loopThread ) ;
}
2021-08-22 10:20:59 +00:00
uv_mutex_destroy ( & m_bansLock ) ;
2021-10-31 14:25:59 +00:00
2021-08-22 10:20:59 +00:00
LOGINFO ( 1 , " stopped " ) ;
}
2023-04-19 09:36:12 +00:00
void TCPServer : : print_status ( )
2021-08-22 10:20:59 +00:00
{
LOGINFO ( 0 , " status " < <
2022-05-09 14:07:49 +00:00
" \n Connections = " < < m_numConnections . load ( ) < < " ( " < < m_numIncomingConnections . load ( ) < < " incoming) "
2021-08-22 10:20:59 +00:00
) ;
}
2023-04-27 08:28:32 +00:00
void TCPServer : : ban ( bool is_v6 , raw_ip ip , uint64_t seconds )
2021-08-22 10:20:59 +00:00
{
2022-05-03 11:11:55 +00:00
if ( ip . is_localhost ( ) ) {
return ;
}
2023-04-27 08:28:32 +00:00
// If it's IPv6, ban the whole /64 prefix
if ( is_v6 & & ! ip . is_ipv4_prefix ( ) ) {
memset ( ip . data + 8 , 0 , sizeof ( ip . data ) - 8 ) ;
}
2022-02-21 17:41:36 +00:00
const auto ban_time = std : : chrono : : steady_clock : : now ( ) + std : : chrono : : seconds ( seconds ) ;
2021-08-22 10:20:59 +00:00
MutexLock lock ( m_bansLock ) ;
2022-02-21 17:41:36 +00:00
m_bans [ ip ] = ban_time ;
2021-08-22 10:20:59 +00:00
}
2023-04-19 09:36:12 +00:00
void TCPServer : : print_bans ( )
2022-02-21 18:59:57 +00:00
{
using namespace std : : chrono ;
const auto cur_time = steady_clock : : now ( ) ;
2022-09-05 13:14:10 +00:00
MutexLock lock ( m_bansLock ) ;
2022-02-21 18:59:57 +00:00
2022-09-05 13:14:10 +00:00
for ( const auto & b : m_bans ) {
2022-02-21 18:59:57 +00:00
if ( cur_time < b . second ) {
const uint64_t t = duration_cast < seconds > ( b . second - cur_time ) . count ( ) ;
LOGINFO ( 0 , b . first < < " is banned ( " < < t < < " seconds left) " ) ;
}
}
}
2023-04-19 09:36:12 +00:00
bool TCPServer : : send_internal ( Client * client , Callback < size_t , uint8_t * , size_t > : : Base & & callback )
2021-08-22 10:20:59 +00:00
{
2023-02-27 14:38:30 +00:00
check_event_loop_thread ( __func__ ) ;
2021-08-22 10:20:59 +00:00
2022-07-06 12:17:09 +00:00
if ( client - > m_isClosing ) {
LOGWARN ( 5 , " client " < < static_cast < const char * > ( client - > m_addrString ) < < " is being disconnected, can't send any more data " ) ;
return true ;
}
2023-04-19 09:36:12 +00:00
const size_t bytes_written = callback ( m_callbackBuf . data ( ) , m_callbackBuf . size ( ) ) ;
2021-08-22 10:20:59 +00:00
2023-04-19 09:36:12 +00:00
if ( bytes_written > m_callbackBuf . size ( ) ) {
LOGERR ( 0 , " send callback wrote " < < bytes_written < < " bytes, expected no more than " < < m_callbackBuf . size ( ) < < " bytes " ) ;
2023-01-14 11:19:25 +00:00
PANIC_STOP ( ) ;
2021-08-22 10:20:59 +00:00
}
if ( bytes_written = = 0 ) {
LOGWARN ( 1 , " send callback wrote 0 bytes, nothing to do " ) ;
return true ;
}
2023-04-17 14:22:46 +00:00
WriteBuf * buf = get_write_buffer ( bytes_written ) ;
2021-08-22 10:20:59 +00:00
buf - > m_write . data = buf ;
2023-01-20 16:03:59 +00:00
buf - > m_client = client ;
if ( buf - > m_dataCapacity < bytes_written ) {
buf - > m_dataCapacity = round_up ( bytes_written , 64 ) ;
buf - > m_data = realloc_hook ( buf - > m_data , buf - > m_dataCapacity ) ;
if ( ! buf - > m_data ) {
LOGERR ( 0 , " failed to allocate " < < buf - > m_dataCapacity < < " bytes to send data " ) ;
PANIC_STOP ( ) ;
}
}
2023-04-19 09:36:12 +00:00
memcpy ( buf - > m_data , m_callbackBuf . data ( ) , bytes_written ) ;
2021-08-22 10:20:59 +00:00
uv_buf_t bufs [ 1 ] ;
2023-01-20 16:03:59 +00:00
bufs [ 0 ] . base = reinterpret_cast < char * > ( buf - > m_data ) ;
2021-08-22 10:20:59 +00:00
bufs [ 0 ] . len = static_cast < int > ( bytes_written ) ;
const int err = uv_write ( & buf - > m_write , reinterpret_cast < uv_stream_t * > ( & client - > m_socket ) , bufs , 1 , Client : : on_write ) ;
if ( err ) {
2021-09-05 18:20:28 +00:00
LOGWARN ( 1 , " failed to start writing data to client connection " < < static_cast < const char * > ( client - > m_addrString ) < < " , error " < < uv_err_name ( err ) ) ;
2023-02-17 07:47:52 +00:00
return_write_buffer ( buf ) ;
2021-08-22 10:20:59 +00:00
return false ;
}
return true ;
}
2023-04-19 09:36:12 +00:00
void TCPServer : : loop ( void * data )
2021-08-22 10:20:59 +00:00
{
2021-08-26 21:27:05 +00:00
TCPServer * server = static_cast < TCPServer * > ( data ) ;
2023-05-01 18:13:57 +00:00
server - > m_loopThreadRunning . exchange ( true ) ;
ON_SCOPE_LEAVE ( [ server ] ( ) { server - > m_loopThreadRunning . exchange ( false ) ; } ) ;
2023-04-19 09:36:12 +00:00
log_category_prefix = server - > get_category ( ) ;
LOGINFO ( 1 , " event loop started " ) ;
server_event_loop_thread = data ;
2022-08-31 14:37:33 +00:00
2023-04-19 09:36:12 +00:00
server - > m_preallocatedClients . reserve ( server - > m_defaultBacklog ) ;
for ( int i = 0 ; i < server - > m_defaultBacklog ; + + i ) {
2023-02-17 07:47:52 +00:00
WriteBuf * wb = new WriteBuf ( ) ;
2023-04-17 14:22:46 +00:00
const size_t capacity = wb - > m_dataCapacity ;
2023-02-17 07:47:52 +00:00
Client * c = server - > m_allocateNewClient ( ) ;
2023-04-17 14:22:46 +00:00
2023-02-17 07:47:52 +00:00
ASAN_POISON_MEMORY_REGION ( wb , sizeof ( WriteBuf ) ) ;
ASAN_POISON_MEMORY_REGION ( c , c - > size ( ) ) ;
2023-04-17 14:22:46 +00:00
server - > m_writeBuffers . emplace ( capacity , wb ) ;
2023-02-17 07:47:52 +00:00
server - > m_preallocatedClients . emplace_back ( c ) ;
2022-08-31 14:37:33 +00:00
}
2022-09-08 07:18:30 +00:00
int err = uv_run ( & server - > m_loop , UV_RUN_DEFAULT ) ;
if ( err ) {
LOGWARN ( 1 , " uv_run returned " < < err ) ;
}
err = uv_loop_close ( & server - > m_loop ) ;
if ( err ) {
LOGWARN ( 1 , " uv_loop_close returned error " < < uv_err_name ( err ) ) ;
}
2022-08-31 14:37:33 +00:00
2023-04-17 14:22:46 +00:00
for ( const auto & it : server - > m_writeBuffers ) {
WriteBuf * buf = it . second ;
2023-02-17 07:47:52 +00:00
ASAN_UNPOISON_MEMORY_REGION ( buf , sizeof ( WriteBuf ) ) ;
if ( buf - > m_data ) {
ASAN_UNPOISON_MEMORY_REGION ( buf - > m_data , buf - > m_dataCapacity ) ;
free_hook ( buf - > m_data ) ;
}
2022-08-31 14:37:33 +00:00
delete buf ;
}
server - > m_writeBuffers . clear ( ) ;
for ( Client * c : server - > m_preallocatedClients ) {
2023-02-17 07:47:52 +00:00
ASAN_UNPOISON_MEMORY_REGION ( c , sizeof ( Client ) ) ;
ASAN_UNPOISON_MEMORY_REGION ( c , c - > size ( ) ) ;
2022-08-31 14:37:33 +00:00
delete c ;
}
server - > m_preallocatedClients . clear ( ) ;
2021-11-20 10:51:22 +00:00
LOGINFO ( 1 , " event loop stopped " ) ;
2021-08-22 10:20:59 +00:00
}
2023-04-19 09:36:12 +00:00
void TCPServer : : on_new_connection ( uv_stream_t * server , int status )
2021-08-22 10:20:59 +00:00
{
TCPServer * pThis = static_cast < TCPServer * > ( server - > data ) ;
if ( pThis - > m_finished . load ( ) ) {
return ;
}
if ( status < 0 ) {
LOGWARN ( 1 , " new connection error " < < uv_strerror ( status ) ) ;
return ;
}
pThis - > on_new_client ( server ) ;
}
2023-04-19 09:36:12 +00:00
void TCPServer : : on_connection_close ( uv_handle_t * handle )
2021-08-22 10:20:59 +00:00
{
2022-04-08 21:14:08 +00:00
Client * client = static_cast < Client * > ( handle - > data ) ;
2021-08-22 10:20:59 +00:00
TCPServer * owner = client - > m_owner ;
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( client - > m_addrString ) < < log : : NoColor ( ) < < " disconnected " ) ;
if ( owner ) {
2023-04-19 09:36:12 +00:00
owner - > check_event_loop_thread ( __func__ ) ;
2021-08-22 10:20:59 +00:00
Client * prev_in_list = client - > m_prev ;
Client * next_in_list = client - > m_next ;
const bool is_incoming = client - > m_isIncoming ;
client - > reset ( ) ;
prev_in_list - > m_next = next_in_list ;
next_in_list - > m_prev = prev_in_list ;
2023-02-17 07:47:52 +00:00
owner - > return_client ( client ) ;
2021-08-22 10:20:59 +00:00
- - owner - > m_numConnections ;
if ( is_incoming ) {
- - owner - > m_numIncomingConnections ;
}
}
else {
2021-08-26 17:14:04 +00:00
LOGERR ( 5 , " internal error: can't find TCPServer instance for peer " < < log : : Gray ( ) < < static_cast < char * > ( client - > m_addrString ) < < " , this will leak memory " ) ;
2021-08-22 10:20:59 +00:00
}
}
2023-04-19 09:36:12 +00:00
void TCPServer : : on_connection_error ( uv_handle_t * handle )
2022-06-07 20:25:27 +00:00
{
Client * client = reinterpret_cast < Client * > ( handle - > data ) ;
2023-02-17 07:47:52 +00:00
client - > m_owner - > return_client ( client ) ;
2022-06-07 20:25:27 +00:00
}
2023-04-19 09:36:12 +00:00
void TCPServer : : on_connect ( uv_connect_t * req , int status )
2021-08-22 10:20:59 +00:00
{
Client * client = reinterpret_cast < Client * > ( req - > data ) ;
TCPServer * server = client - > m_owner ;
if ( ! server ) {
return ;
}
2022-08-31 14:37:33 +00:00
server - > m_pendingConnections . erase ( client - > m_addr ) ;
2021-08-22 10:20:59 +00:00
if ( status ) {
2021-08-23 12:05:07 +00:00
if ( status = = UV_ETIMEDOUT ) {
LOGINFO ( 5 , " connection to " < < static_cast < char * > ( client - > m_addrString ) < < " timed out " ) ;
}
else {
LOGWARN ( 5 , " failed to connect to " < < static_cast < char * > ( client - > m_addrString ) < < " , error " < < uv_err_name ( status ) ) ;
}
2021-08-22 10:20:59 +00:00
server - > on_connect_failed ( client - > m_isV6 , client - > m_addr , client - > m_port ) ;
2022-06-07 20:25:27 +00:00
uv_close ( reinterpret_cast < uv_handle_t * > ( & client - > m_socket ) , on_connection_error ) ;
2021-08-22 10:20:59 +00:00
return ;
}
2022-08-31 14:37:33 +00:00
server - > on_new_client ( nullptr , client ) ;
2021-08-22 10:20:59 +00:00
}
2023-04-19 09:36:12 +00:00
void TCPServer : : on_new_client ( uv_stream_t * server )
2021-08-22 10:20:59 +00:00
{
if ( m_finished . load ( ) ) {
return ;
}
2023-02-17 07:47:52 +00:00
Client * client = get_client ( ) ;
2021-08-22 10:20:59 +00:00
int err = uv_tcp_init ( & m_loop , & client - > m_socket ) ;
if ( err ) {
LOGERR ( 1 , " failed to create tcp client handle, error " < < uv_err_name ( err ) ) ;
2023-02-17 07:47:52 +00:00
return_client ( client ) ;
2021-08-22 10:20:59 +00:00
return ;
}
2021-08-25 11:58:00 +00:00
client - > m_socket . data = client ;
client - > m_owner = this ;
2021-08-22 10:20:59 +00:00
err = uv_tcp_nodelay ( & client - > m_socket , 1 ) ;
if ( err ) {
LOGERR ( 1 , " failed to set tcp_nodelay on tcp client handle, error " < < uv_err_name ( err ) ) ;
2022-06-07 20:25:27 +00:00
uv_close ( reinterpret_cast < uv_handle_t * > ( & client - > m_socket ) , on_connection_error ) ;
2021-08-22 10:20:59 +00:00
return ;
}
err = uv_accept ( server , reinterpret_cast < uv_stream_t * > ( & client - > m_socket ) ) ;
if ( err ) {
LOGERR ( 1 , " failed to accept client connection, error " < < uv_err_name ( err ) ) ;
2022-06-07 20:25:27 +00:00
uv_close ( reinterpret_cast < uv_handle_t * > ( & client - > m_socket ) , on_connection_error ) ;
2021-08-22 10:20:59 +00:00
return ;
}
2022-08-31 14:37:33 +00:00
on_new_client ( server , client ) ;
2021-08-22 10:20:59 +00:00
}
2023-04-19 09:36:12 +00:00
void TCPServer : : on_new_client ( uv_stream_t * server , Client * client )
2021-08-22 10:20:59 +00:00
{
2023-02-27 14:38:30 +00:00
check_event_loop_thread ( __func__ ) ;
2022-08-31 14:37:33 +00:00
2021-08-22 10:20:59 +00:00
client - > m_prev = m_connectedClientsList ;
client - > m_next = m_connectedClientsList - > m_next ;
m_connectedClientsList - > m_next - > m_prev = client ;
m_connectedClientsList - > m_next = client ;
+ + m_numConnections ;
2022-08-31 14:37:33 +00:00
client - > m_isIncoming = ( server ! = nullptr ) ;
2021-08-22 10:20:59 +00:00
2022-08-31 14:37:33 +00:00
if ( client - > m_isIncoming ) {
2022-09-22 09:28:38 +00:00
+ + m_numIncomingConnections ;
2022-08-31 14:37:33 +00:00
client - > m_isV6 = ( std : : find ( m_listenSockets6 . begin ( ) , m_listenSockets6 . end ( ) , reinterpret_cast < uv_tcp_t * > ( server ) ) ! = m_listenSockets6 . end ( ) ) ;
2021-08-22 10:20:59 +00:00
2022-08-31 14:37:33 +00:00
sockaddr_storage peer_addr ;
int peer_addr_len = static_cast < int > ( sizeof ( peer_addr ) ) ;
int err = uv_tcp_getpeername ( & client - > m_socket , reinterpret_cast < sockaddr * > ( & peer_addr ) , & peer_addr_len ) ;
if ( err ) {
LOGERR ( 1 , " failed to get IP address of the client connection, error " < < uv_err_name ( err ) ) ;
client - > close ( ) ;
return ;
}
2021-08-22 10:20:59 +00:00
2022-08-31 14:37:33 +00:00
if ( client - > m_isV6 ) {
memcpy ( client - > m_addr . data , & reinterpret_cast < sockaddr_in6 * > ( & peer_addr ) - > sin6_addr , sizeof ( in6_addr ) ) ;
client - > m_port = ntohs ( reinterpret_cast < sockaddr_in6 * > ( & peer_addr ) - > sin6_port ) ;
}
else {
client - > m_addr = { } ;
client - > m_addr . data [ 10 ] = 0xFF ;
client - > m_addr . data [ 11 ] = 0xFF ;
memcpy ( client - > m_addr . data + 12 , & reinterpret_cast < sockaddr_in * > ( & peer_addr ) - > sin_addr , sizeof ( in_addr ) ) ;
client - > m_port = ntohs ( reinterpret_cast < sockaddr_in * > ( & peer_addr ) - > sin_port ) ;
}
2021-08-22 10:20:59 +00:00
2022-08-31 14:37:33 +00:00
client - > init_addr_string ( ) ;
2021-08-22 10:20:59 +00:00
}
2022-08-31 14:37:33 +00:00
LOGINFO ( 5 , " new connection " < < ( client - > m_isIncoming ? " from " : " to " ) < < log : : Gray ( ) < < static_cast < char * > ( client - > m_addrString ) ) ;
2021-08-22 10:20:59 +00:00
2023-04-27 08:28:32 +00:00
if ( is_banned ( client - > m_isV6 , client - > m_addr ) ) {
2021-08-27 14:36:06 +00:00
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( client - > m_addrString ) < < log : : NoColor ( ) < < " is banned, disconnecting " ) ;
client - > close ( ) ;
return ;
2021-08-22 10:20:59 +00:00
}
2022-08-31 14:37:33 +00:00
TCPServer * owner = client - > m_owner ;
if ( owner - > m_finished . load ( ) ) {
2021-08-22 10:20:59 +00:00
client - > close ( ) ;
return ;
}
2022-09-06 13:59:05 +00:00
if ( client - > m_isIncoming | | owner - > m_socks5Proxy . empty ( ) ) {
2022-08-31 14:37:33 +00:00
if ( ! client - > on_connect ( ) ) {
client - > close ( ) ;
return ;
}
}
else {
const bool result = owner - > send ( client ,
[ ] ( void * buf , size_t buf_size ) - > size_t
{
if ( buf_size < 3 ) {
return 0 ;
}
uint8_t * p = reinterpret_cast < uint8_t * > ( buf ) ;
p [ 0 ] = 5 ; // Protocol version (SOCKS5)
p [ 1 ] = 1 ; // NMETHODS
p [ 2 ] = 0 ; // Method 0 (no authentication)
return 3 ;
} ) ;
if ( result ) {
client - > m_socks5ProxyState = Client : : Socks5ProxyState : : MethodSelectionSent ;
}
else {
client - > close ( ) ;
}
}
const int err = uv_read_start ( reinterpret_cast < uv_stream_t * > ( & client - > m_socket ) , Client : : on_alloc , Client : : on_read ) ;
2021-08-22 10:20:59 +00:00
if ( err ) {
LOGERR ( 1 , " failed to start reading from client connection, error " < < uv_err_name ( err ) ) ;
client - > close ( ) ;
}
}
2023-04-19 09:36:12 +00:00
void TCPServer : : on_shutdown ( uv_async_t * async )
2022-10-18 16:41:58 +00:00
{
TCPServer * s = reinterpret_cast < TCPServer * > ( async - > data ) ;
s - > on_shutdown ( ) ;
s - > close_sockets ( true ) ;
uv_close ( reinterpret_cast < uv_handle_t * > ( & s - > m_dropConnectionsAsync ) , nullptr ) ;
uv_close ( reinterpret_cast < uv_handle_t * > ( & s - > m_shutdownAsync ) , nullptr ) ;
delete GetLoopUserData ( & s - > m_loop , false ) ;
s - > m_numHandles = 0 ;
2023-01-17 07:15:53 +00:00
uv_walk ( & s - > m_loop , [ ] ( uv_handle_t * , void * n ) { ( * reinterpret_cast < uint32_t * > ( n ) ) + + ; } , & s - > m_numHandles ) ;
2022-10-18 16:41:58 +00:00
uv_prepare_init ( & s - > m_loop , & s - > m_shutdownPrepare ) ;
s - > m_shutdownPrepare . data = s ;
uv_timer_init ( & s - > m_loop , & s - > m_shutdownTimer ) ;
s - > m_shutdownTimer . data = s ;
s - > m_shutdownCountdown = 30 ;
uv_timer_start ( & s - > m_shutdownTimer ,
[ ] ( uv_timer_t * h )
{
TCPServer * s = reinterpret_cast < TCPServer * > ( h - > data ) ;
const uint32_t k = - - s - > m_shutdownCountdown ;
if ( k > 0 ) {
LOGINFO ( 1 , " waiting for event loop to stop for " < < k < < " more seconds ( " < < s - > m_numHandles < < " handles left)... " ) ;
}
else {
LOGINFO ( 1 , " force stopping the event loop... " ) ;
uv_timer_stop ( & s - > m_shutdownTimer ) ;
uv_prepare_stop ( & s - > m_shutdownPrepare ) ;
uv_close ( reinterpret_cast < uv_handle_t * > ( & s - > m_shutdownTimer ) , nullptr ) ;
uv_close ( reinterpret_cast < uv_handle_t * > ( & s - > m_shutdownPrepare ) , nullptr ) ;
uv_stop ( & s - > m_loop ) ;
}
} , 1000 , 1000 ) ;
uv_prepare_start ( & s - > m_shutdownPrepare ,
[ ] ( uv_prepare_t * h )
{
TCPServer * s = reinterpret_cast < TCPServer * > ( h - > data ) ;
s - > m_numHandles = 0 ;
2023-01-17 07:15:53 +00:00
uv_walk ( & s - > m_loop , [ ] ( uv_handle_t * , void * n ) { ( * reinterpret_cast < uint32_t * > ( n ) ) + + ; } , & s - > m_numHandles ) ;
2022-10-18 16:41:58 +00:00
if ( s - > m_numHandles > 2 ) {
// Don't count m_shutdownTimer and m_shutdownPrepare
s - > m_numHandles - = 2 ;
}
else {
uv_timer_stop ( & s - > m_shutdownTimer ) ;
uv_prepare_stop ( & s - > m_shutdownPrepare ) ;
uv_close ( reinterpret_cast < uv_handle_t * > ( & s - > m_shutdownTimer ) , nullptr ) ;
uv_close ( reinterpret_cast < uv_handle_t * > ( & s - > m_shutdownPrepare ) , nullptr ) ;
}
} ) ;
}
2023-04-19 09:36:12 +00:00
TCPServer : : WriteBuf * TCPServer : : get_write_buffer ( size_t size_hint )
2023-02-17 07:47:52 +00:00
{
WriteBuf * buf ;
if ( ! m_writeBuffers . empty ( ) ) {
2023-04-17 14:22:46 +00:00
// Try to find the smallest buffer that still has enough capacity
// If there is no buffer with enough capacity, just take the largest available buffer
auto it = m_writeBuffers . lower_bound ( size_hint ) ;
if ( it = = m_writeBuffers . end ( ) ) {
it = std : : prev ( it ) ;
}
buf = it - > second ;
m_writeBuffers . erase ( it ) ;
2023-02-17 07:47:52 +00:00
ASAN_UNPOISON_MEMORY_REGION ( buf , sizeof ( WriteBuf ) ) ;
if ( buf - > m_data ) {
ASAN_UNPOISON_MEMORY_REGION ( buf - > m_data , buf - > m_dataCapacity ) ;
}
}
else {
buf = new WriteBuf ( ) ;
}
return buf ;
}
2023-04-19 09:36:12 +00:00
void TCPServer : : return_write_buffer ( WriteBuf * buf )
2023-02-17 07:47:52 +00:00
{
2023-04-17 14:22:46 +00:00
const size_t capacity = buf - > m_dataCapacity ;
2023-02-17 07:47:52 +00:00
if ( buf - > m_data ) {
2023-04-17 14:22:46 +00:00
ASAN_POISON_MEMORY_REGION ( buf - > m_data , capacity ) ;
2023-02-17 07:47:52 +00:00
}
ASAN_POISON_MEMORY_REGION ( buf , sizeof ( WriteBuf ) ) ;
2023-04-17 14:22:46 +00:00
m_writeBuffers . emplace ( capacity , buf ) ;
2023-02-17 07:47:52 +00:00
}
2023-04-19 09:36:12 +00:00
TCPServer : : Client * TCPServer : : get_client ( )
2023-02-17 07:47:52 +00:00
{
Client * c ;
if ( ! m_preallocatedClients . empty ( ) ) {
c = m_preallocatedClients . back ( ) ;
m_preallocatedClients . pop_back ( ) ;
ASAN_UNPOISON_MEMORY_REGION ( c , sizeof ( Client ) ) ;
ASAN_UNPOISON_MEMORY_REGION ( c , c - > size ( ) ) ;
c - > reset ( ) ;
}
else {
c = m_allocateNewClient ( ) ;
}
return c ;
}
2023-04-19 09:36:12 +00:00
void TCPServer : : return_client ( Client * c )
2023-02-17 07:47:52 +00:00
{
ASAN_POISON_MEMORY_REGION ( c , c - > size ( ) ) ;
m_preallocatedClients . push_back ( c ) ;
}
2023-04-19 09:36:12 +00:00
TCPServer : : Client : : Client ( char * read_buf , size_t size )
: m_readBuf ( read_buf )
, m_readBufSize ( static_cast < uint32_t > ( size ) )
, m_owner ( nullptr )
2022-05-09 17:13:34 +00:00
, m_prev ( nullptr )
, m_next ( nullptr )
, m_socket { }
, m_isV6 ( false )
, m_isIncoming ( false )
, m_readBufInUse ( false )
2022-07-06 12:17:09 +00:00
, m_isClosing ( false )
2022-05-09 17:13:34 +00:00
, m_numRead ( 0 )
, m_addr { }
, m_port ( 0 )
, m_addrString { }
2022-08-31 14:37:33 +00:00
, m_socks5ProxyState ( Socks5ProxyState : : Default )
2022-05-09 17:13:34 +00:00
, m_resetCounter { 0 }
2021-08-22 10:20:59 +00:00
{
m_readBuf [ 0 ] = ' \0 ' ;
2023-04-19 09:36:12 +00:00
m_readBuf [ m_readBufSize - 1 ] = ' \0 ' ;
2021-08-22 10:20:59 +00:00
}
2023-04-19 09:36:12 +00:00
void TCPServer : : Client : : reset ( )
2021-08-22 10:20:59 +00:00
{
m_resetCounter . fetch_add ( 1 ) ;
m_owner = nullptr ;
m_prev = nullptr ;
m_next = nullptr ;
memset ( & m_socket , 0 , sizeof ( m_socket ) ) ;
m_isV6 = false ;
m_isIncoming = false ;
2022-05-07 10:29:45 +00:00
m_readBufInUse = false ;
2022-07-06 12:17:09 +00:00
m_isClosing = false ;
2022-05-07 10:29:45 +00:00
m_numRead = 0 ;
2021-08-22 10:20:59 +00:00
m_addr = { } ;
m_port = - 1 ;
m_addrString [ 0 ] = ' \0 ' ;
2022-08-31 14:37:33 +00:00
m_socks5ProxyState = Socks5ProxyState : : Default ;
2022-09-05 13:14:10 +00:00
m_readBuf [ 0 ] = ' \0 ' ;
2023-04-19 09:36:12 +00:00
m_readBuf [ m_readBufSize - 1 ] = ' \0 ' ;
2021-08-22 10:20:59 +00:00
}
2023-04-19 09:36:12 +00:00
void TCPServer : : Client : : on_alloc ( uv_handle_t * handle , size_t /*suggested_size*/ , uv_buf_t * buf )
2021-08-22 10:20:59 +00:00
{
Client * pThis = static_cast < Client * > ( handle - > data ) ;
if ( pThis - > m_readBufInUse ) {
2021-09-05 18:20:28 +00:00
LOGWARN ( 4 , " client " < < static_cast < const char * > ( pThis - > m_addrString ) < < " read buffer is already in use " ) ;
2021-08-22 10:20:59 +00:00
buf - > len = 0 ;
buf - > base = nullptr ;
return ;
}
2023-04-19 09:36:12 +00:00
if ( pThis - > m_numRead > = pThis - > m_readBufSize ) {
2021-09-05 18:20:28 +00:00
LOGWARN ( 4 , " client " < < static_cast < const char * > ( pThis - > m_addrString ) < < " read buffer is full " ) ;
2021-08-22 10:20:59 +00:00
buf - > len = 0 ;
buf - > base = nullptr ;
return ;
}
2023-04-19 09:36:12 +00:00
buf - > len = pThis - > m_readBufSize - pThis - > m_numRead ;
2021-08-22 10:20:59 +00:00
buf - > base = pThis - > m_readBuf + pThis - > m_numRead ;
pThis - > m_readBufInUse = true ;
}
2023-04-19 09:36:12 +00:00
void TCPServer : : Client : : on_read ( uv_stream_t * stream , ssize_t nread , const uv_buf_t * buf )
2021-08-22 10:20:59 +00:00
{
2022-08-31 14:37:33 +00:00
Client * client = static_cast < Client * > ( stream - > data ) ;
client - > m_readBufInUse = false ;
2021-08-22 10:20:59 +00:00
2022-08-31 14:37:33 +00:00
if ( client - > m_isClosing ) {
LOGWARN ( 5 , " client " < < static_cast < const char * > ( client - > m_addrString ) < < " is being disconnected but data received from it, nread = " < < nread < < " . Ignoring it. " ) ;
2022-07-06 12:17:09 +00:00
return ;
}
2021-08-22 10:20:59 +00:00
if ( nread > 0 ) {
2022-08-31 14:37:33 +00:00
if ( client - > m_owner & & ! client - > m_owner - > m_finished . load ( ) ) {
if ( client - > m_socks5ProxyState = = Socks5ProxyState : : Default ) {
if ( ! client - > on_read ( buf - > base , static_cast < uint32_t > ( nread ) ) ) {
client - > close ( ) ;
}
}
else if ( ! client - > on_proxy_handshake ( buf - > base , static_cast < uint32_t > ( nread ) ) ) {
client - > close ( ) ;
2021-08-22 10:20:59 +00:00
}
}
}
else if ( nread < 0 ) {
if ( nread ! = UV_EOF ) {
2021-09-06 14:17:20 +00:00
const int err = static_cast < int > ( nread ) ;
2022-08-31 14:37:33 +00:00
LOGWARN ( 5 , " client " < < static_cast < const char * > ( client - > m_addrString ) < < " failed to read response, err = " < < uv_err_name ( err ) ) ;
client - > on_read_failed ( err ) ;
2021-08-22 10:20:59 +00:00
}
2021-09-07 07:53:38 +00:00
else {
2022-08-31 14:37:33 +00:00
client - > on_disconnected ( ) ;
2021-09-07 07:53:38 +00:00
}
2022-08-31 14:37:33 +00:00
client - > close ( ) ;
2021-08-22 10:20:59 +00:00
}
}
2023-04-19 09:36:12 +00:00
bool TCPServer : : Client : : on_proxy_handshake ( char * data , uint32_t size )
2022-08-31 14:37:33 +00:00
{
2023-04-19 09:36:12 +00:00
if ( ( data ! = m_readBuf + m_numRead ) | | ( data + size > m_readBuf + m_readBufSize ) ) {
2022-08-31 14:37:33 +00:00
LOGERR ( 1 , " peer " < < static_cast < char * > ( m_addrString ) < < " invalid data pointer or size in on_read() " ) ;
return false ;
}
m_numRead + = size ;
uint32_t n = 0 ;
switch ( m_socks5ProxyState ) {
case Socks5ProxyState : : MethodSelectionSent :
if ( m_numRead > = 2 ) {
if ( ( m_readBuf [ 0 ] ! = 5 ) & & ( m_readBuf [ 1 ] ! = 0 ) ) {
LOGWARN ( 5 , " SOCKS5 proxy returned an invalid METHOD selection message " ) ;
return false ;
}
n = 2 ;
const bool result = m_owner - > send ( this ,
[ this ] ( void * buf , size_t buf_size ) - > size_t
{
2022-09-05 13:14:10 +00:00
if ( buf_size < 22 ) {
2022-08-31 14:37:33 +00:00
return 0 ;
}
uint8_t * p = reinterpret_cast < uint8_t * > ( buf ) ;
p [ 0 ] = 5 ; // Protocol version (SOCKS5)
p [ 1 ] = 1 ; // CONNECT
p [ 2 ] = 0 ; // RESERVED
if ( m_isV6 ) {
p [ 3 ] = 4 ; // ATYP
memcpy ( p + 4 , m_addr . data , 16 ) ;
p [ 20 ] = static_cast < uint8_t > ( m_port > > 8 ) ;
p [ 21 ] = static_cast < uint8_t > ( m_port & 0xFF ) ;
}
else {
p [ 3 ] = 1 ; // ATYP
memcpy ( p + 4 , m_addr . data + 12 , 4 ) ;
p [ 8 ] = static_cast < uint8_t > ( m_port > > 8 ) ;
p [ 9 ] = static_cast < uint8_t > ( m_port & 0xFF ) ;
}
return m_isV6 ? 22 : 10 ;
} ) ;
if ( result ) {
m_socks5ProxyState = Socks5ProxyState : : ConnectRequestSent ;
}
else {
close ( ) ;
}
}
break ;
case Socks5ProxyState : : ConnectRequestSent :
if ( m_numRead > = 4 ) {
2023-05-23 18:11:00 +00:00
const uint8_t * p = reinterpret_cast < uint8_t * > ( m_readBuf ) ;
2022-08-31 14:37:33 +00:00
if ( ( p [ 0 ] ! = 5 ) & & ( p [ 1 ] ! = 0 ) & & p [ 2 ] ! = 0 ) {
LOGWARN ( 5 , " SOCKS5 proxy returned an invalid reply to CONNECT " ) ;
return false ;
}
switch ( p [ 3 ] ) {
case 1 :
if ( m_numRead > = 10 ) {
m_socks5ProxyState = Socks5ProxyState : : Default ;
n = 10 ;
}
break ;
case 3 :
if ( m_numRead > = 5 ) {
const uint32_t len = p [ 4 ] ;
if ( m_numRead > = 7 + len ) {
m_socks5ProxyState = Socks5ProxyState : : Default ;
n = 7 + len ;
}
}
break ;
case 4 :
if ( m_numRead > = 22 ) {
m_socks5ProxyState = Socks5ProxyState : : Default ;
n = 22 ;
}
break ;
2022-09-05 13:14:10 +00:00
default :
LOGWARN ( 5 , " SOCKS5 proxy returned an invalid reply to CONNECT (invalid address type " < < p [ 3 ] < < ' ) ' ) ;
return false ;
2022-08-31 14:37:33 +00:00
}
}
break ;
default :
return false ;
}
// Move the possible unfinished message to the beginning of m_readBuf to free up more space for reading
if ( n > 0 ) {
m_numRead - = n ;
if ( m_numRead > 0 ) {
memmove ( m_readBuf , m_readBuf + n , m_numRead ) ;
}
}
if ( m_socks5ProxyState = = Socks5ProxyState : : Default ) {
if ( ! on_connect ( ) ) {
return false ;
}
if ( m_numRead > 0 ) {
const uint32_t nread = m_numRead ;
m_numRead = 0 ;
if ( ! on_read ( m_readBuf , nread ) ) {
return false ;
}
}
}
return true ;
}
2023-04-19 09:36:12 +00:00
void TCPServer : : Client : : on_write ( uv_write_t * req , int status )
2021-08-22 10:20:59 +00:00
{
2021-10-31 14:25:59 +00:00
WriteBuf * buf = static_cast < WriteBuf * > ( req - > data ) ;
2021-08-22 10:20:59 +00:00
Client * client = buf - > m_client ;
2021-10-31 14:25:59 +00:00
TCPServer * server = client - > m_owner ;
2021-08-22 10:20:59 +00:00
2021-10-31 14:25:59 +00:00
if ( server ) {
2023-02-17 07:47:52 +00:00
server - > return_write_buffer ( buf ) ;
2021-08-22 10:20:59 +00:00
}
if ( status ! = 0 ) {
2021-09-05 18:20:28 +00:00
LOGWARN ( 5 , " client " < < static_cast < const char * > ( client - > m_addrString ) < < " failed to write data to client connection, error " < < uv_err_name ( status ) ) ;
2021-08-22 10:20:59 +00:00
client - > close ( ) ;
}
}
2023-04-19 09:36:12 +00:00
void TCPServer : : Client : : close ( )
2021-08-22 10:20:59 +00:00
{
2022-07-06 12:17:09 +00:00
if ( m_isClosing | | ! m_owner ) {
2021-08-22 10:20:59 +00:00
// Already closed
return ;
}
2022-07-06 12:17:09 +00:00
m_isClosing = true ;
2021-08-25 14:19:21 +00:00
uv_read_stop ( reinterpret_cast < uv_stream_t * > ( & m_socket ) ) ;
2021-08-22 10:20:59 +00:00
uv_tcp_t * s = & m_socket ;
uv_handle_t * h = reinterpret_cast < uv_handle_t * > ( s ) ;
if ( ! uv_is_closing ( h ) ) {
2021-08-25 15:27:46 +00:00
uv_close ( h , on_connection_close ) ;
2021-08-22 10:20:59 +00:00
}
}
2023-04-19 09:36:12 +00:00
void TCPServer : : Client : : ban ( uint64_t seconds )
2021-08-22 10:20:59 +00:00
{
2023-03-17 15:59:01 +00:00
if ( m_addr . is_localhost ( ) ) {
return ;
}
2021-08-22 10:20:59 +00:00
if ( m_owner ) {
LOGWARN ( 3 , " peer " < < static_cast < char * > ( m_addrString ) < < " banned for " < < seconds < < " seconds " ) ;
2023-04-27 08:28:32 +00:00
m_owner - > ban ( m_isV6 , m_addr , seconds ) ;
2021-08-22 10:20:59 +00:00
}
}
2023-04-19 09:36:12 +00:00
void TCPServer : : Client : : init_addr_string ( )
2021-08-22 10:20:59 +00:00
{
const char * addr_str ;
char addr_str_buf [ 64 ] ;
2022-08-31 14:37:33 +00:00
if ( m_isV6 ) {
addr_str = inet_ntop ( AF_INET6 , m_addr . data , addr_str_buf , sizeof ( addr_str_buf ) ) ;
2021-08-22 10:20:59 +00:00
}
else {
2022-08-31 14:37:33 +00:00
addr_str = inet_ntop ( AF_INET , m_addr . data + 12 , addr_str_buf , sizeof ( addr_str_buf ) ) ;
2021-08-22 10:20:59 +00:00
}
if ( addr_str ) {
size_t n = strlen ( addr_str ) ;
if ( n > sizeof ( m_addrString ) - 16 ) {
n = sizeof ( m_addrString ) - 16 ;
}
log : : Stream s ( m_addrString ) ;
2022-08-31 14:37:33 +00:00
if ( m_isV6 ) {
s < < ' [ ' < < log : : const_buf ( addr_str , n ) < < " ]: " < < m_port < < ' \0 ' ;
2021-08-22 10:20:59 +00:00
}
else {
2022-08-31 14:37:33 +00:00
s < < log : : const_buf ( addr_str , n ) < < ' : ' < < m_port < < ' \0 ' ;
2021-08-22 10:20:59 +00:00
}
}
}
} // namespace p2pool