2019-07-17 13:37:18 -04:00
# define TIMING_DISABLED
# include "POWHandler.h"
# include <thread>
# include <algorithm>
# include <unistd.h>
# include <fcntl.h>
# include "VoiceServer.h"
# include "../client/voice/VoiceClient.h"
# include "../Configuration.h"
# include <log/LogUtils.h>
2020-01-26 12:04:38 -05:00
# include "src/VirtualServer.h"
2019-07-17 13:37:18 -04:00
# include <misc/endianness.h>
2020-01-26 20:21:39 -05:00
# include "src/VirtualServerManager.h"
2019-07-17 13:37:18 -04:00
# include "../InstanceHandler.h"
# include <ThreadPool/Timer.h>
# include <pipes/buffer.h>
# include <netinet/in.h>
# include <misc/sassert.h>
# include "misc/timer.h"
using namespace std ;
using namespace std : : chrono ;
using namespace ts : : server ;
using namespace ts : : buffer ;
using namespace ts ;
extern InstanceHandler * serverInstance ;
2020-01-26 12:04:38 -05:00
VoiceServer : : VoiceServer ( const std : : shared_ptr < VirtualServer > & server ) {
2019-07-17 13:37:18 -04:00
this - > server = server ;
this - > pow_handler = make_unique < POWHandler > ( this ) ;
}
VoiceServer : : ~ VoiceServer ( ) { }
# define SET_OPTION(type, option, flag, error) \
if ( setsockopt ( bind - > file_descriptor , type , option , & flag , sizeof ( flag ) ) < 0 ) { \
2020-01-23 20:57:58 -05:00
error ; \
: : close ( bind - > file_descriptor ) ; \
bind - > file_descriptor = 0 ; \
continue ; \
2019-07-17 13:37:18 -04:00
}
bool VoiceServer : : start ( const std : : deque < std : : shared_ptr < VoiceServerBinding > > & binding , std : : string & error ) {
2020-01-23 20:57:58 -05:00
if ( this - > running ) return false ;
2019-07-17 13:37:18 -04:00
if ( binding . empty ( ) ) {
2020-01-23 20:57:58 -05:00
error = " Missing bindings! " ;
return false ;
2019-07-17 13:37:18 -04:00
}
2020-01-23 20:57:58 -05:00
this - > running = true ;
2019-07-17 13:37:18 -04:00
this - > bindings = binding ;
2020-01-23 20:57:58 -05:00
int enable = 1 , disable = 0 ;
for ( auto & bind : binding ) {
bind - > file_descriptor = socket ( bind - > address . ss_family , SOCK_DGRAM , 0 ) ;
if ( ! bind - > file_descriptor ) {
logError ( this - > server - > getServerId ( ) , " Failed to create socket for {} " , bind - > address_string ( ) ) ;
continue ;
}
if ( setsockopt ( bind - > file_descriptor , SOL_SOCKET , SO_REUSEADDR , & disable , sizeof ( int ) ) < 0 ) logError ( this - > server - > getServerId ( ) , " Could not disable flag reuse address for bound {}! " , bind - > address_string ( ) ) ;
//if(setsockopt(bind->file_descriptor, SOL_SOCKET, SO_REUSEPORT, &disable, sizeof(int)) < 0) logError(this->server->getServerId(), "Could not disable flag reuse port for bound {}!", bind->address_string());
/* We're never sending over MTU size packets! */
int pmtu = IP_PMTUDISC_DO ;
setsockopt ( bind - > file_descriptor , IPPROTO_IP , IP_MTU_DISCOVER , & pmtu , sizeof ( pmtu ) ) ;
if ( fcntl ( bind - > file_descriptor , F_SETFD , FD_CLOEXEC ) < 0 )
logError ( this - > server - > getServerId ( ) , " Failed to enable FD_CLOEXEC for {} ({}) (VoiceServer) " , bind - > file_descriptor , bind - > address_string ( ) ) ;
if ( bind - > address . ss_family = = AF_INET6 ) {
SET_OPTION ( IPPROTO_IPV6 , IPV6_RECVPKTINFO , enable , {
logError ( this - > server - > getServerId ( ) , " Failed to enable packet info (v6) for {} " , bind - > address_string ( ) ) ;
} ) ;
SET_OPTION ( IPPROTO_IPV6 , IPV6_V6ONLY , enable , {
logError ( this - > server - > getServerId ( ) , " Failed to enable ip v6 only for {} " , bind - > address_string ( ) ) ;
} ) ;
} else {
SET_OPTION ( IPPROTO_IP , IP_PKTINFO , enable , {
logError ( this - > server - > getServerId ( ) , " Failed to enable packet info for {} " , bind - > address_string ( ) ) ;
} ) ;
}
if ( : : bind ( bind - > file_descriptor , ( const sockaddr * ) & bind - > address , net : : address_size ( bind - > address ) ) < 0 ) {
logError ( this - > server - > getServerId ( ) , " Failed to bind to {} ({} => {}) " , bind - > address_string ( ) , errno , strerror ( errno ) ) ;
: : close ( bind - > file_descriptor ) ;
bind - > file_descriptor = 0 ;
continue ;
}
fcntl ( bind - > file_descriptor , F_SETFL , fcntl ( bind - > file_descriptor , F_GETFL , 0 ) | O_NONBLOCK ) ;
}
{
auto bindings = this - > activeBindings ( ) ;
if ( bindings . empty ( ) ) {
error = " Failed to bind any address! " ;
this - > running = false ;
return false ;
}
string str ;
for ( auto it = bindings . begin ( ) ; it ! = bindings . end ( ) ; it + + ) {
str + = net : : to_string ( ( * it ) - > address ) + ( it + 1 = = bindings . end ( ) ? " " : " | " ) ;
}
logMessage ( this - > server - > getServerId ( ) , " Started server on {}. " , str ) ;
}
2019-07-17 13:37:18 -04:00
this - > io = serverInstance - > getVoiceServerManager ( ) - > ioManager ( ) - > enableIo ( this - > server . get ( ) ) ;
return true ;
}
void VoiceServer : : triggerWrite ( const std : : shared_ptr < VoiceClient > & client ) {
2020-01-23 20:57:58 -05:00
if ( ! client ) {
logError ( this - > server - > getServerId ( ) , " Invalid client for triggerWrite() " ) ;
return ;
}
2019-07-17 13:37:18 -04:00
2020-11-07 07:17:51 -05:00
if ( auto io { this - > io } ; io ) {
io - > invoke_write ( client ) ;
}
2019-07-17 13:37:18 -04:00
}
2020-01-26 20:21:39 -05:00
void VoiceServer : : schedule_command_handling ( const ts : : server : : VoiceClient * client ) {
2020-01-23 20:57:58 -05:00
auto vmanager = serverInstance - > getVoiceServerManager ( ) ;
if ( ! vmanager )
return ;
auto evloop = vmanager - > get_executor_loop ( ) ;
if ( ! evloop )
return ;
evloop - > schedule ( client - > event_handle_packet ) ;
2019-07-17 13:37:18 -04:00
}
void VoiceServer : : tickHandshakingClients ( ) {
2020-01-23 20:57:58 -05:00
this - > pow_handler - > execute_tick ( ) ;
decltype ( this - > activeConnections ) connections ;
{
lock_guard lock ( this - > connectionLock ) ;
connections = this - > activeConnections ;
}
for ( const auto & client : connections )
if ( client - > state = = ConnectionState : : INIT_HIGH | | client - > state = = ConnectionState : : INIT_LOW )
2019-07-17 13:37:18 -04:00
client - > tick ( system_clock : : now ( ) ) ;
}
void VoiceServer : : execute_resend ( const std : : chrono : : system_clock : : time_point & now , std : : chrono : : system_clock : : time_point & next ) {
2020-01-23 20:57:58 -05:00
decltype ( this - > activeConnections ) connections ;
{
lock_guard lock ( this - > connectionLock ) ;
connections = this - > activeConnections ;
}
string error ;
for ( const auto & client : connections ) {
auto connection = client - > getConnection ( ) ;
sassert ( connection ) ; /* its not possible that a client hasn't a connection! */
2020-07-29 13:05:38 -04:00
connection - > packet_encoder ( ) . execute_resend ( now , next ) ;
2020-01-23 20:57:58 -05:00
}
2019-07-17 13:37:18 -04:00
}
bool VoiceServer : : stop ( const std : : chrono : : milliseconds & flushTimeout ) {
2020-01-23 20:57:58 -05:00
if ( ! this - > running ) return false ;
2019-07-17 13:37:18 -04:00
this - > running = false ;
this - > connectionLock . lock ( ) ;
auto list = this - > activeConnections ;
this - > connectionLock . unlock ( ) ;
for ( const auto & e : list )
2020-02-01 08:32:16 -05:00
e - > close_connection ( system_clock : : now ( ) + seconds ( 1 ) ) ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
auto beg = system_clock : : now ( ) ;
while ( ! this - > activeConnections . empty ( ) & & flushTimeout . count ( ) ! = 0 & & system_clock : : now ( ) - beg < flushTimeout )
threads : : self : : sleep_for ( milliseconds ( 10 ) ) ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
for ( const auto & connection : this - > activeConnections )
connection - > voice_server = nullptr ;
2019-07-17 13:37:18 -04:00
this - > activeConnections . clear ( ) ;
2020-01-23 20:57:58 -05:00
serverInstance - > getVoiceServerManager ( ) - > ioManager ( ) - > disableIo ( this - > server . get ( ) ) ;
this - > io = nullptr ;
for ( const auto & bind : this - > bindings ) {
if ( bind - > file_descriptor > 0 ) {
if ( ! shutdown ( bind - > file_descriptor , SHUT_RDWR ) ) logError ( this - > server - > getServerId ( ) , " Failed to shutdown socket {} ({}) Reason: {}/{} " , bind - > file_descriptor , bind - > address_string ( ) , errno , strerror ( errno ) ) ;
if ( ! close ( bind - > file_descriptor ) ) {
if ( errno ! = ENOTCONN )
logError ( this - > server - > getServerId ( ) , " Failed to close socket {} ({}) Reason: {}/{} " , bind - > file_descriptor , bind - > address_string ( ) , errno , strerror ( errno ) ) ;
}
bind - > file_descriptor = 0 ;
}
}
this - > bindings . clear ( ) ;
2019-07-17 13:37:18 -04:00
return true ;
}
std : : shared_ptr < VoiceClient > VoiceServer : : findClient ( ts : : ClientId client ) {
2020-01-23 20:57:58 -05:00
lock_guard lock ( this - > connectionLock ) ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
for ( const auto & elm : this - > activeConnections ) {
if ( elm - > getClientId ( ) = = client )
return elm ;
}
return nullptr ;
2019-07-17 13:37:18 -04:00
}
std : : shared_ptr < VoiceClient > VoiceServer : : findClient ( sockaddr_in * addr , bool ) {
2020-01-23 20:57:58 -05:00
lock_guard lock ( this - > connectionLock ) ;
2019-07-17 13:37:18 -04:00
for ( const auto & elm : this - > activeConnections ) {
2020-01-23 20:57:58 -05:00
if ( elm - > isAddressV4 ( ) )
if ( elm - > getAddressV4 ( ) - > sin_addr . s_addr = = addr - > sin_addr . s_addr )
if ( elm - > getAddressV4 ( ) - > sin_port = = addr - > sin_port )
return elm ;
2019-07-17 13:37:18 -04:00
}
return nullptr ;
}
std : : shared_ptr < VoiceClient > VoiceServer : : findClient ( sockaddr_in6 * addr , bool ) {
2020-01-23 20:57:58 -05:00
lock_guard lock ( this - > connectionLock ) ;
for ( const auto & elm : this - > activeConnections ) {
if ( elm - > isAddressV6 ( ) )
if ( memcmp ( elm - > getAddressV6 ( ) - > sin6_addr . __in6_u . __u6_addr8 , addr - > sin6_addr . __in6_u . __u6_addr8 , 16 ) = = 0 )
if ( elm - > getAddressV6 ( ) - > sin6_port = = addr - > sin6_port )
return elm ;
}
return nullptr ;
2019-07-17 13:37:18 -04:00
}
bool VoiceServer : : unregisterConnection ( std : : shared_ptr < VoiceClient > connection ) {
2020-01-23 20:57:58 -05:00
lock_guard lock ( this - > connectionLock ) ;
2019-07-17 13:37:18 -04:00
auto found = std : : find ( this - > activeConnections . begin ( ) , this - > activeConnections . end ( ) , connection ) ;
if ( found ! = activeConnections . end ( ) )
this - > activeConnections . erase ( found ) ;
2019-11-23 15:16:55 -05:00
else logError ( LOG_GENERAL , " unregisterConnection(...) - > could not find client " ) ;
2019-07-17 13:37:18 -04:00
return true ;
}
static union {
2020-01-23 20:57:58 -05:00
char literal [ 8 ] = { ' T ' , ' S ' , ' 3 ' , ' I ' , ' N ' , ' I ' , ' T ' , ' 1 ' } ;
uint64_t integral ;
2019-07-17 13:37:18 -04:00
} TS3INIT ;
void VoiceServer : : handleMessageRead ( int fd , short events , void * _event_handle ) {
2020-01-23 20:57:58 -05:00
auto event_handle = ( io : : IOEventLoopEntry * ) _event_handle ;
auto voice_server = event_handle - > voice_server ;
auto ts_server = event_handle - > server ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
size_t raw_read_buffer_length = event_handle - > family = = AF_INET ? 600 : 1600 ; //IPv6 MTU: 1500 | IPv4 MTU: 576
uint8_t raw_read_buffer [ raw_read_buffer_length ] ; //Allocate on stack, so we dont need heap here
2019-07-17 13:37:18 -04:00
ssize_t bytes_read = 0 ;
2020-01-23 20:57:58 -05:00
pipes : : buffer_view read_buffer { raw_read_buffer , raw_read_buffer_length } ; /* will not allocate anything, just sets its mode to ptr and thats it :) */
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
sockaddr_storage remote_address { } ;
iovec io_vector { } ;
io_vector . iov_base = ( void * ) raw_read_buffer ;
io_vector . iov_len = raw_read_buffer_length ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
char message_headers [ 0x100 ] ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
msghdr message { } ;
2019-07-17 13:37:18 -04:00
message . msg_name = & remote_address ;
message . msg_namelen = sizeof ( remote_address ) ;
2020-01-23 20:57:58 -05:00
message . msg_iov = & io_vector ;
message . msg_iovlen = 1 ;
message . msg_control = message_headers ;
message . msg_controllen = 0x100 ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
auto read_timeout = system_clock : : now ( ) + microseconds ( 2500 ) ; /* read 2.5ms long at a time or 'till nothing more is there */
2019-07-17 13:37:18 -04:00
while ( system_clock : : now ( ) < = read_timeout ) {
2020-01-23 20:57:58 -05:00
message . msg_flags = 0 ;
bytes_read = recvmsg ( fd , & message , 0 ) ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
if ( ( message . msg_flags & MSG_TRUNC ) > 0 )
logError ( ts_server - > getServerId ( ) , " Received truncated message from {} " , net : : to_string ( remote_address ) ) ;
2019-07-17 13:37:18 -04:00
2020-09-06 15:00:27 -04:00
if ( bytes_read < 0 ) {
2019-07-17 13:37:18 -04:00
if ( errno = = EAGAIN )
break ;
//Nothing more to read
2020-01-23 20:57:58 -05:00
logCritical ( ts_server - > getServerId ( ) , " Could not receive datagram packet! Code: {} Reason: {} " , errno , strerror ( errno ) ) ;
2019-07-17 13:37:18 -04:00
break ;
} else if ( bytes_read = = 0 ) {
2020-01-23 20:57:58 -05:00
//This should never happen
2019-07-17 13:37:18 -04:00
break ;
}
if ( bytes_read < MAC_SIZE + CLIENT_HEADER_SIZE ) {
2020-01-23 20:57:58 -05:00
/* reenable for debug. else short packages could be a dos attach */
//logError(ts_server->getServerId(), "Received an too short packet!");
2019-07-17 13:37:18 -04:00
continue ;
}
shared_ptr < VoiceClient > client ;
{
2020-01-23 20:57:58 -05:00
if ( * ( uint64_t * ) raw_read_buffer = = TS3INIT . integral ) {
//Handle ddos protection...
voice_server - > pow_handler - > handle_datagram ( event_handle - > socket_id , remote_address , message , read_buffer . view ( 0 , bytes_read ) ) ;
} else {
auto client_id = ( ClientId ) be2le16 ( & raw_read_buffer [ 10 ] ) ;
if ( client_id > 0 ) {
2020-02-01 08:32:16 -05:00
client = dynamic_pointer_cast < VoiceClient > ( voice_server - > server - > find_client_by_id ( client_id ) ) ;
2020-01-23 20:57:58 -05:00
} else {
client = voice_server - > findClient ( & remote_address , true ) ;
}
}
2019-07-17 13:37:18 -04:00
}
if ( ! client )
2020-01-23 20:57:58 -05:00
continue ;
2019-07-17 13:37:18 -04:00
if ( memcmp ( & client - > remote_address , & remote_address , sizeof ( sockaddr_storage ) ) ! = 0 ) { /* verify the remote address */
2020-01-23 20:57:58 -05:00
if ( ( read_buffer [ 12 ] & 0x80 ) = = 0 & & client - > state = = ConnectionState : : CONNECTED ) { /* only encrypted packets are allowed */
if ( client - > connection - > verify_encryption ( read_buffer . view ( 0 , bytes_read ) ) ) { /* the ip had changed */
auto old_address = net : : to_string ( client - > remote_address ) ;
auto new_address = net : : to_string ( remote_address ) ;
auto command = " dummy_ipchange old_ip= " + old_address + " new_ip= " + new_address ;
2020-07-29 16:53:40 -04:00
client - > server_command_executor ( ) . force_insert_command ( pipes : : buffer_view { command . data ( ) , command . length ( ) } ) ;
2020-01-23 20:57:58 -05:00
memcpy ( & client - > remote_address , & remote_address , sizeof ( remote_address ) ) ;
2020-08-03 07:51:47 -04:00
udp : : DatagramPacket : : extract_info ( message , client - > connection - > remote_address_info_ ) ;
2020-01-23 20:57:58 -05:00
}
} else {
continue ; /* we've no clue */
}
2019-07-17 13:37:18 -04:00
}
if ( client - > state ! = ConnectionState : : DISCONNECTED ) {
2020-01-26 20:21:39 -05:00
client - > connection - > handle_incoming_datagram ( read_buffer . view ( 0 , bytes_read ) ) ;
2019-07-17 13:37:18 -04:00
client = nullptr ;
}
}
}
# ifndef USE_TIMER
2020-01-23 20:57:58 -05:00
# ifdef ALARM_TIMER
# undef ALARM_TIMER
# endif
# define ALARM_TIMER(...)
2019-07-17 13:37:18 -04:00
# endif
template < int MHS >
struct IOData {
2020-01-23 20:57:58 -05:00
int file_descriptor = 0 ;
iovec vector { } ;
struct msghdr message { } ;
2020-04-24 16:04:07 -04:00
char message_headers [ MHS ] { } ;
2020-01-23 20:57:58 -05:00
IOData ( ) {
/* Speed is key here, we dont need to zero paddings!
memset ( & this - > vector , 0 , sizeof ( this - > vector ) ) ;
memset ( & this - > message , 0 , sizeof ( this - > message ) ) ;
memset ( this - > message_headers , 0 , sizeof ( this - > message_headers ) ) ;
*/
this - > vector . iov_base = nullptr ;
this - > vector . iov_len = 0 ;
this - > message . msg_name = nullptr ;
this - > message . msg_namelen = 0 ;
this - > message . msg_iov = & vector ;
this - > message . msg_iovlen = 1 ;
this - > message . msg_control = this - > message_headers ;
this - > message . msg_controllen = sizeof ( this - > message_headers ) ;
}
2019-07-17 13:37:18 -04:00
} ;
template < int MHS >
2020-08-03 07:51:47 -04:00
inline ssize_t write_datagram ( IOData < MHS > & io , const sockaddr_storage & address , udp : : pktinfo_storage * info , size_t length , const void * buffer ) {
2020-01-23 20:57:58 -05:00
io . message . msg_flags = 0 ;
io . message . msg_name = ( void * ) & address ;
io . message . msg_namelen = address . ss_family = = AF_INET ? sizeof ( sockaddr_in ) : sizeof ( sockaddr_in6 ) ;
io . vector . iov_len = length ;
2020-04-24 16:04:07 -04:00
io . vector . iov_base = ( void * ) buffer ;
2020-01-23 20:57:58 -05:00
if ( info ) {
auto cmsg = CMSG_FIRSTHDR ( & io . message ) ;
if ( address . ss_family = = AF_INET ) {
cmsg - > cmsg_level = IPPROTO_IP ;
cmsg - > cmsg_type = IP_PKTINFO ;
cmsg - > cmsg_len = CMSG_LEN ( sizeof ( in_pktinfo ) ) ;
memcpy ( CMSG_DATA ( cmsg ) , info , sizeof ( in_pktinfo ) ) ;
io . message . msg_controllen = CMSG_SPACE ( sizeof ( in_pktinfo ) ) ;
} else if ( address . ss_family = = AF_INET6 ) {
cmsg - > cmsg_level = IPPROTO_IPV6 ;
cmsg - > cmsg_type = IPV6_PKTINFO ;
cmsg - > cmsg_len = CMSG_LEN ( sizeof ( in6_pktinfo ) ) ;
memcpy ( CMSG_DATA ( cmsg ) , info , sizeof ( in6_pktinfo ) ) ;
io . message . msg_controllen = CMSG_SPACE ( sizeof ( in6_pktinfo ) ) ;
} else if ( address . ss_family = = 0 )
return length ; /* address is unset (testing ip loss i guess) */
} else {
io . message . msg_controllen = 0 ;
}
auto status = sendmsg ( io . file_descriptor , & io . message , 0 ) ;
if ( status < 0 & & errno = = EINVAL ) {
/* may something is wrong here */
status = send ( io . file_descriptor , buffer , length , 0 ) ;
if ( status < 0 )
return - 0xFEB ;
}
return status ;
2019-07-17 13:37:18 -04:00
}
void VoiceServer : : handleMessageWrite ( int fd , short events , void * _event_handle ) {
2020-07-29 13:05:38 -04:00
using WBufferPopResult = server : : udp : : PacketEncoder : : BufferPopResult ;
2020-01-23 20:57:58 -05:00
auto event_handle = ( io : : IOEventLoopEntry * ) _event_handle ;
auto voice_server = event_handle - > voice_server ;
bool retrigger = false ;
IOData < 0x100 > io { } ;
io . file_descriptor = fd ;
{ /* write and process clients */
shared_ptr < VoiceClient > client ;
2020-04-24 16:04:07 -04:00
protocol : : OutgoingServerPacket * packet ;
WBufferPopResult client_wbuffer_state ;
bool more_clients ;
2020-01-23 20:57:58 -05:00
auto write_timeout = system_clock : : now ( ) + microseconds ( 2500 ) ; /* read 2.5ms long at a time or 'till nothing more is there */
while ( system_clock : : now ( ) < = write_timeout ) {
if ( ! client ) {
auto client_queue_state = event_handle - > pop_voice_write_queue ( client ) ; /* we need a new client, the old client has nothing more to do */
if ( client_queue_state = = 2 )
break ;
2020-04-24 16:04:07 -04:00
assert ( client ) ;
2020-01-23 20:57:58 -05:00
more_clients = ( bool ) client_queue_state ;
}
while ( system_clock : : now ( ) < = write_timeout ) {
2020-04-24 16:04:07 -04:00
packet = nullptr ;
2020-07-29 13:05:38 -04:00
client_wbuffer_state = client - > connection - > packet_encoder ( ) . pop_write_buffer ( packet ) ;
2020-04-24 16:04:07 -04:00
if ( ! packet ) {
assert ( client_wbuffer_state = = WBufferPopResult : : DRAINED ) ;
break ;
}
2020-07-30 05:40:03 -04:00
ssize_t res = write_datagram ( io , client - > remote_address , & client - > connection - > remote_address_info_ , packet - > packet_length ( ) , packet - > packet_data ( ) ) ;
2020-04-24 16:04:07 -04:00
if ( res ! = packet - > packet_length ( ) ) {
if ( errno = = EAGAIN ) {
logCritical ( voice_server - > server - > getServerId ( ) , " Failed to write datagram packet for client {} (EAGAIN). " , client - > getLoggingPeerIp ( ) + " : " + to_string ( client - > getPeerPort ( ) ) ) ;
packet - > unref ( ) ;
return ;
} else if ( errno = = EINVAL | | res = = - 0xFEB ) {
/* needs more debug */
auto voice_client = dynamic_pointer_cast < VoiceClient > ( client ) ;
logCritical (
voice_server - > server - > getServerId ( ) ,
" Failed to write datagram packet ({} @ {}) for client {} ({}) {}. Dropping packet! Extra data: [fd: {}/{}, supposed socket: {}/{} => {}, client family: {}, socket family: {}] " ,
packet - > packet_length ( ) , packet - > packet_data ( ) ,
client - > getLoggingPeerIp ( ) + " : " + to_string ( client - > getPeerPort ( ) ) ,
strerror ( errno ) ,
res ,
fd ,
event_handle - > file_descriptor ,
2020-07-30 05:40:03 -04:00
voice_client - > connection - > socket_id ( ) ,
2020-04-24 16:04:07 -04:00
event_handle - > socket_id ,
voice_server - > io - > resolve_file_descriptor ( voice_client ) ,
voice_client - > isAddressV4 ( ) ? " v4 " : voice_client - > isAddressV6 ( ) ? " v6 " : " v? " ,
event_handle - > family = = AF_INET ? " v4 " : " v6 "
) ;
} else {
logCritical (
voice_server - > server - > getServerId ( ) ,
" Failed to write datagram packet for client {} (errno: {} message: {}). Dropping packet! " ,
client - > getLoggingPeerIp ( ) + " : " + to_string ( client - > getPeerPort ( ) ) ,
errno ,
strerror ( errno )
) ;
2020-01-23 20:57:58 -05:00
}
2020-04-24 16:04:07 -04:00
packet - > unref ( ) ;
break ;
2020-01-23 20:57:58 -05:00
}
2020-04-24 16:04:07 -04:00
packet - > unref ( ) ;
if ( client_wbuffer_state = = WBufferPopResult : : DRAINED )
break ;
2020-01-23 20:57:58 -05:00
}
2020-04-24 16:04:07 -04:00
if ( client_wbuffer_state = = WBufferPopResult : : MORE_AVAILABLE ) {
2020-01-23 20:57:58 -05:00
/* we exceeded the max write time, rescheduling write */
voice_server - > triggerWrite ( client ) ;
}
2020-04-24 16:04:07 -04:00
client . reset ( ) ;
2020-01-23 20:57:58 -05:00
}
2020-04-24 16:04:07 -04:00
retrigger | = more_clients ;
2020-01-23 20:57:58 -05:00
}
2020-04-24 16:04:07 -04:00
2020-01-23 20:57:58 -05:00
/* write all manually specified datagram packets */
{
auto write_timeout = system_clock : : now ( ) + microseconds ( 2500 ) ; /* read 2.5ms long at a time or 'till nothing more is there */
2020-08-03 07:51:47 -04:00
udp : : DatagramPacket * packet ;
2020-01-23 20:57:58 -05:00
while ( system_clock : : now ( ) < = write_timeout & & ( packet = event_handle - > pop_dg_write_queue ( ) ) ) {
2020-08-03 07:51:47 -04:00
ssize_t res = write_datagram ( io , packet - > address , & packet - > pktinfo , packet - > data_length , packet - > data ) ;
2020-01-23 20:57:58 -05:00
if ( res ! = packet - > data_length ) {
if ( errno = = EAGAIN ) {
event_handle - > push_dg_write_queue ( packet ) ;
} else
2020-08-03 07:51:47 -04:00
udp : : DatagramPacket : : destroy ( packet ) ;
2020-01-23 20:57:58 -05:00
logError ( voice_server - > server - > getServerId ( ) , " Failed to send datagram. Wrote {} out of {}. {}/{} " , res , packet - > data_length , errno , strerror ( errno ) ) ;
retrigger = false ;
break ;
}
2020-08-03 07:51:47 -04:00
udp : : DatagramPacket : : destroy ( packet ) ;
2020-01-23 20:57:58 -05:00
}
retrigger | = packet ! = nullptr ; /* memory stored at packet is not accessible anymore. But anyways pop_dg_write_queue returns 0 if there is nothing more */
}
if ( retrigger )
event_add ( event_handle - > event_write , nullptr ) ;
2019-07-17 13:37:18 -04:00
}
2020-08-03 07:51:47 -04:00
void VoiceServer : : send_datagram ( int socket , udp : : DatagramPacket * packet ) {
2020-01-23 20:57:58 -05:00
this - > io - > send_datagram ( packet , socket ) ;
2019-07-17 13:37:18 -04:00
}