2018-06-25 10:47:27 +00:00
/*
* $ Id $
*
2019-06-06 05:28:23 +00:00
Copyright ( c ) 2006 - 2019 Chung , Hyung - Hwan . All rights reserved .
2018-06-25 10:47:27 +00:00
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
documentation and / or other materials provided with the distribution .
2023-11-18 02:23:14 +00:00
THIS SOFTWARE IS PROVIDED BY THE AUTHOR " AS IS " AND ANY EXPRESS OR
2018-06-25 10:47:27 +00:00
IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include <qse/si/TcpServer.hpp>
2018-06-25 15:52:05 +00:00
# include <qse/si/os.h>
2018-06-26 14:43:43 +00:00
# include <qse/cmn/str.h>
2020-08-12 08:22:23 +00:00
# include <qse/cmn/chr.h>
2018-06-26 14:43:43 +00:00
# include "../cmn/mem-prv.h"
# include <errno.h>
# include <unistd.h>
# include <fcntl.h>
2019-06-13 10:18:30 +00:00
# include <string.h>
2018-06-25 10:47:27 +00:00
2018-10-20 03:36:40 +00:00
2018-07-01 13:57:37 +00:00
# define WID_MAP_ALIGN 128
2019-06-14 08:35:11 +00:00
# define WID_MAX (_wid_map_t::WID_INVALID - 1)
2018-07-01 11:21:00 +00:00
2018-06-25 10:47:27 +00:00
QSE_BEGIN_NAMESPACE ( QSE )
2018-06-26 14:43:43 +00:00
# include "../cmn/syserr.h"
2019-06-14 03:34:39 +00:00
IMPLEMENT_SYSERR_TO_ERRNUM ( TcpServer : : ErrorNumber , TcpServer : : )
2018-06-26 14:43:43 +00:00
2019-06-14 08:35:11 +00:00
int TcpServer : : Connection : : main ( )
2018-06-25 10:47:27 +00:00
{
2018-07-01 11:21:00 +00:00
int n ;
2018-06-25 10:47:27 +00:00
// blockAllSignals is called inside run because
2019-06-14 08:35:11 +00:00
// Connection is instantiated in the TcpServer thread.
// so if it is called in the constructor of Connection,
2018-06-25 10:47:27 +00:00
// it would just block signals to the TcpProxy thread.
2018-06-25 15:52:05 +00:00
this - > blockAllSignals ( ) ; // don't care about the result.
2018-06-25 10:47:27 +00:00
2019-06-14 08:35:11 +00:00
try { n = this - > listener - > server - > handle_connection ( this ) ; }
2018-07-01 11:21:00 +00:00
catch ( . . . ) { n = - 1 ; }
TcpServer * server = this - > getServer ( ) ;
2020-09-14 04:19:57 +00:00
server - > logfmt ( QSE_LOG_INFO , QSE_T ( " [h=%d,w=%zu] closing connection \n " ) , ( int ) this - > socket . getHandle ( ) , this - > getWid ( ) ) ;
2019-11-13 06:33:43 +00:00
2019-06-14 08:35:11 +00:00
server - > _connection_list_spl . lock ( ) ;
2018-07-02 13:02:27 +00:00
this - > csspl . lock ( ) ;
this - > socket . close ( ) ;
this - > csspl . unlock ( ) ;
2018-07-01 11:21:00 +00:00
if ( ! this - > claimed )
{
2019-06-14 08:35:11 +00:00
server - > _connection_list [ Connection : : LIVE ] . remove ( this ) ;
server - > _connection_list [ Connection : : DEAD ] . append ( this ) ;
2018-07-01 11:21:00 +00:00
}
2019-06-14 08:35:11 +00:00
server - > _connection_list_spl . unlock ( ) ;
2018-07-01 11:21:00 +00:00
return n ;
2018-06-25 10:47:27 +00:00
}
2019-11-13 06:33:43 +00:00
int TcpServer : : Connection : : stop ( ) QSE_CPP_NOEXCEPT
2018-06-25 10:47:27 +00:00
{
// the receiver will be notified of the end of
// the connection by the socket's closing.
2019-06-14 08:35:11 +00:00
// therefore, handle_connection() must return
2018-06-25 10:47:27 +00:00
// when it detects the end of the connection.
2018-06-28 04:08:43 +00:00
this - > csspl . lock ( ) ;
2018-06-25 15:52:05 +00:00
this - > socket . shutdown ( ) ;
2018-06-28 04:08:43 +00:00
this - > csspl . unlock ( ) ;
2018-06-25 10:47:27 +00:00
return 0 ;
}
2018-07-01 02:11:33 +00:00
TcpServer : : TcpServer ( Mmgr * mmgr ) QSE_CPP_NOEXCEPT :
Mmged ( mmgr ) ,
2019-11-12 07:55:32 +00:00
_halt_requested ( false ) ,
2019-06-14 08:35:11 +00:00
_server_serving ( false ) ,
_max_connections ( 0 ) ,
_thread_stack_size ( 0 )
2018-06-25 10:47:27 +00:00
{
}
2018-06-25 15:52:05 +00:00
TcpServer : : ~ TcpServer ( ) QSE_CPP_NOEXCEPT
2018-06-25 10:47:27 +00:00
{
2019-06-14 08:35:11 +00:00
// QSE_ASSERT (this->_server_serving == false);
this - > delete_all_connections ( Connection : : LIVE ) ;
this - > delete_all_connections ( Connection : : DEAD ) ;
2018-06-25 10:47:27 +00:00
}
2018-06-26 14:43:43 +00:00
void TcpServer : : free_all_listeners ( ) QSE_CPP_NOEXCEPT
2018-06-25 10:47:27 +00:00
{
2018-06-26 14:43:43 +00:00
Listener * lp ;
2019-06-14 08:35:11 +00:00
while ( this - > _listener_list . head )
2018-06-25 10:47:27 +00:00
{
2019-06-14 08:35:11 +00:00
lp = this - > _listener_list . head ;
this - > _listener_list . head = lp - > next_listener ;
this - > _listener_list . count - - ;
2018-06-28 09:43:34 +00:00
qse_mux_evt_t evt ;
evt . hnd = lp - > getHandle ( ) ;
2019-06-14 08:35:11 +00:00
qse_mux_delete ( this - > _listener_list . mux , & evt ) ;
2018-06-26 14:43:43 +00:00
2020-09-14 04:19:57 +00:00
this - > logfmt ( QSE_LOG_INFO , QSE_T ( " [l=%d] closing listener \n " ) , ( int ) evt . hnd ) ;
2018-06-26 14:43:43 +00:00
lp - > close ( ) ;
2018-07-01 07:33:56 +00:00
2019-06-13 10:18:30 +00:00
QSE_CPP_DELETE_WITH_MMGR ( lp , Listener , this - > getMmgr ( ) ) ; // delete lp
2018-06-25 10:47:27 +00:00
}
2019-06-14 08:35:11 +00:00
if ( this - > _listener_list . mux_pipe [ 0 ] > = 0 )
2018-06-26 15:45:44 +00:00
{
2018-06-28 09:43:34 +00:00
qse_mux_evt_t evt ;
2019-06-14 08:35:11 +00:00
evt . hnd = this - > _listener_list . mux_pipe [ 0 ] ;
qse_mux_delete ( this - > _listener_list . mux , & evt ) ;
2018-06-28 09:43:34 +00:00
2019-06-14 08:35:11 +00:00
close ( this - > _listener_list . mux_pipe [ 0 ] ) ;
this - > _listener_list . mux_pipe [ 0 ] = - 1 ;
2018-06-26 15:45:44 +00:00
}
2018-06-28 14:07:35 +00:00
2019-06-14 08:35:11 +00:00
this - > _listener_list . mux_pipe_spl . lock ( ) ;
if ( this - > _listener_list . mux_pipe [ 1 ] > = 0 )
2018-06-26 15:45:44 +00:00
{
2019-06-14 08:35:11 +00:00
close ( this - > _listener_list . mux_pipe [ 1 ] ) ;
this - > _listener_list . mux_pipe [ 1 ] = - 1 ;
2018-06-26 15:45:44 +00:00
}
2019-06-14 08:35:11 +00:00
this - > _listener_list . mux_pipe_spl . unlock ( ) ;
2018-06-26 15:45:44 +00:00
2019-06-14 08:35:11 +00:00
QSE_ASSERT ( this - > _listener_list . mux ! = QSE_NULL ) ;
qse_mux_close ( this - > _listener_list . mux ) ;
this - > _listener_list . mux = QSE_NULL ;
2018-06-26 14:43:43 +00:00
}
2018-06-25 10:47:27 +00:00
2018-06-28 09:43:34 +00:00
struct mux_xtn_t
{
2018-06-28 14:07:35 +00:00
bool first_time ;
2018-06-28 09:43:34 +00:00
TcpServer * server ;
} ;
2018-07-01 13:57:37 +00:00
2018-06-28 09:43:34 +00:00
void TcpServer : : dispatch_mux_event ( qse_mux_t * mux , const qse_mux_evt_t * evt ) QSE_CPP_NOEXCEPT
{
mux_xtn_t * mux_xtn = ( mux_xtn_t * ) qse_mux_getxtn ( mux ) ;
TcpServer * server = mux_xtn - > server ;
2018-06-28 14:07:35 +00:00
if ( mux_xtn - > first_time )
{
2019-06-14 08:35:11 +00:00
server - > delete_all_connections ( Connection : : DEAD ) ;
2018-06-28 14:07:35 +00:00
mux_xtn - > first_time = false ;
}
2018-06-28 09:43:34 +00:00
if ( ! evt - > mask ) return ;
if ( evt - > data = = NULL )
{
2019-11-12 07:55:32 +00:00
/* just consume data written by TcpServer::halt() */
2018-06-28 09:43:34 +00:00
char tmp [ 128 ] ;
2019-06-14 08:35:11 +00:00
while ( : : read ( server - > _listener_list . mux_pipe [ 0 ] , tmp , QSE_SIZEOF ( tmp ) ) > 0 ) /* nothing */ ;
2018-06-28 09:43:34 +00:00
}
else
{
/* the reset should be the listener's socket */
Listener * lsck = ( Listener * ) evt - > data ;
2019-06-14 08:35:11 +00:00
if ( server - > _max_connections > 0 & & server - > _max_connections < = server - > _connection_list [ Connection : : LIVE ] . getSize ( ) )
2018-06-28 09:43:34 +00:00
{
// too many connections. accept the connection and close it.
2020-09-14 04:19:57 +00:00
server - > logfmt ( QSE_LOG_ERROR , QSE_T ( " [l=%d] - too many connections - %zu \n " ) , ( int ) lsck - > getHandle ( ) , server - > _connection_list [ Connection : : LIVE ] . getSize ( ) ) ;
2018-07-01 13:57:37 +00:00
goto accept_and_drop ;
2018-06-28 09:43:34 +00:00
}
2019-06-14 08:35:11 +00:00
Connection * connection ;
2018-06-28 09:43:34 +00:00
2019-06-14 08:35:11 +00:00
// allocating the connection object before accept is
2018-06-28 09:43:34 +00:00
// a bit awkward. but socket.accept() can be passed
2019-06-14 08:35:11 +00:00
// the socket field inside the connection object.
try { connection = new ( server - > getMmgr ( ) ) Connection ( lsck ) ; }
2018-06-28 09:43:34 +00:00
catch ( . . . )
{
// memory alloc failed. accept the connection and close it.
2020-09-14 04:19:57 +00:00
server - > logfmt ( QSE_LOG_ERROR , QSE_T ( " [l=%d] unable to instantiate connection \n " ) , ( int ) lsck - > getHandle ( ) ) ;
2018-07-01 13:57:37 +00:00
goto accept_and_drop ;
}
2019-06-14 08:35:11 +00:00
if ( server - > _wid_map . free_first = = _wid_map_t : : WID_INVALID & & server - > prepare_to_acquire_wid ( ) < = - 1 )
2018-07-01 13:57:37 +00:00
{
2020-09-14 04:19:57 +00:00
server - > logfmt ( QSE_LOG_ERROR , QSE_T ( " [l=%d] unable to assign id to connection \n " ) , ( int ) lsck - > getHandle ( ) ) ;
2019-06-14 08:35:11 +00:00
QSE_CPP_DELETE_WITH_MMGR ( connection , Connection , server - > getMmgr ( ) ) ;
2018-07-01 13:57:37 +00:00
goto accept_and_drop ;
2018-06-28 09:43:34 +00:00
}
2019-06-14 08:35:11 +00:00
if ( lsck - > accept ( & connection - > socket , & connection - > address , Socket : : T_CLOEXEC ) < = - 1 )
2018-06-28 09:43:34 +00:00
{
2020-09-14 04:19:57 +00:00
server - > logfmt ( QSE_LOG_ERROR , QSE_T ( " [l=%d] unable to accept connection - %hs \n " ) , ( int ) lsck - > getHandle ( ) , strerror ( errno ) ) ;
2019-06-14 08:35:11 +00:00
QSE_CPP_DELETE_WITH_MMGR ( connection , Connection , server - > getMmgr ( ) ) ;
2018-07-01 11:21:00 +00:00
2019-11-13 06:33:43 +00:00
if ( server - > isHaltRequested ( ) ) return ; /* normal termination requested */
2018-06-28 09:43:34 +00:00
2019-06-14 03:34:39 +00:00
Socket : : ErrorNumber lerr = lsck - > getErrorNumber ( ) ;
2018-06-28 09:43:34 +00:00
if ( lerr = = Socket : : E_EINTR | | lerr = = Socket : : E_EAGAIN ) return ;
2019-06-14 03:34:39 +00:00
server - > setErrorNumber ( lerr ) ;
2019-11-12 07:55:32 +00:00
server - > halt ( ) ;
2018-06-28 09:43:34 +00:00
return ;
}
2019-06-14 08:35:11 +00:00
server - > _connection_list_spl . lock ( ) ;
server - > _connection_list [ Connection : : LIVE ] . append ( connection ) ;
server - > _connection_list_spl . unlock ( ) ;
2018-07-01 07:33:56 +00:00
2019-06-14 08:35:11 +00:00
server - > acquire_wid ( connection ) ;
connection - > setStackSize ( server - > _thread_stack_size ) ;
2018-06-28 09:43:34 +00:00
# if defined(_WIN32)
2019-06-14 08:35:11 +00:00
if ( connection - > start ( Thread : : DETACHED ) < = - 1 )
2018-06-28 09:43:34 +00:00
# else
2019-06-14 08:35:11 +00:00
if ( connection - > start ( 0 ) < = - 1 )
2018-06-28 09:43:34 +00:00
# endif
2018-06-28 14:07:35 +00:00
{
2019-06-14 05:53:24 +00:00
qse_char_t addrbuf [ 128 ] ;
2020-09-14 04:19:57 +00:00
server - > logfmt ( QSE_LOG_ERROR , QSE_T ( " [l=%d] unable to start connection for connection from %s \n " ) , ( int ) lsck - > getHandle ( ) , connection - > address . toStrBuf ( addrbuf , QSE_COUNTOF ( addrbuf ) ) ) ;
2018-07-01 11:21:00 +00:00
2019-06-14 08:35:11 +00:00
server - > _connection_list_spl . lock ( ) ;
server - > _connection_list [ Connection : : LIVE ] . remove ( connection ) ;
server - > _connection_list_spl . unlock ( ) ;
2018-07-01 13:57:37 +00:00
2019-06-14 08:35:11 +00:00
server - > release_wid ( connection ) ;
QSE_CPP_DELETE_WITH_MMGR ( connection , Connection , server - > getMmgr ( ) ) ;
2018-06-28 14:07:35 +00:00
}
2019-11-13 06:33:43 +00:00
else
{
qse_char_t addrbuf [ 128 ] ;
2020-09-14 04:19:57 +00:00
server - > logfmt ( QSE_LOG_INFO , QSE_T ( " [l=%d,h=%d,w=%zu] connection from %js \n " ) , ( int ) lsck - > getHandle ( ) , ( int ) connection - > socket . getHandle ( ) , connection - > getWid ( ) , connection - > address . toStrBuf ( addrbuf , QSE_COUNTOF ( addrbuf ) ) ) ;
2019-11-13 06:33:43 +00:00
}
2018-07-01 13:57:37 +00:00
return ;
accept_and_drop :
Socket s ;
SocketAddress sa ;
2019-11-13 06:33:43 +00:00
2019-06-14 05:53:24 +00:00
if ( lsck - > accept ( & s , & sa , Socket : : T_CLOEXEC ) > = 0 )
{
qse_char_t addrbuf [ 128 ] ;
2020-09-14 04:19:57 +00:00
server - > logfmt ( QSE_LOG_ERROR , QSE_T ( " [l=%d] accepted but dropped connection from %js \n " ) , ( int ) lsck - > getHandle ( ) , sa . toStrBuf ( addrbuf , QSE_COUNTOF ( addrbuf ) ) ) ;
2019-06-14 05:53:24 +00:00
s . close ( ) ;
}
2018-06-28 09:43:34 +00:00
}
}
2020-08-12 08:22:23 +00:00
static const qse_char_t * strip_enclosing_spaces ( const qse_char_t * ptr , qse_size_t * len )
{
const qse_char_t * end = ptr + * len ;
while ( ptr < end )
{
if ( ! QSE_ISSPACE ( * ptr ) ) break ;
ptr + + ;
}
while ( end > ptr )
{
if ( ! QSE_ISSPACE ( end [ - 1 ] ) ) break ;
end - - ;
}
* len = end - ptr ;
return ptr ;
}
2018-06-26 14:43:43 +00:00
int TcpServer : : setup_listeners ( const qse_char_t * addrs ) QSE_CPP_NOEXCEPT
{
const qse_char_t * addr_ptr , * comma ;
2018-06-28 09:43:34 +00:00
qse_mux_t * mux = QSE_NULL ;
qse_mux_evt_t ev ;
int fcv , pfd [ 2 ] = { - 1 , - 1 } ;
2018-06-26 14:43:43 +00:00
SocketAddress sockaddr ;
2019-06-13 10:18:30 +00:00
errno = 0 ;
2018-06-28 09:43:34 +00:00
mux = qse_mux_open ( this - > getMmgr ( ) , QSE_SIZEOF ( mux_xtn_t ) , TcpServer : : dispatch_mux_event , 1024 , QSE_NULL ) ;
if ( ! mux )
2018-06-25 10:47:27 +00:00
{
2019-06-13 10:18:30 +00:00
if ( errno ! = 0 )
this - > setErrorFmt ( syserr_to_errnum ( errno ) , QSE_T ( " %hs " ) , strerror ( errno ) ) ;
else
2019-06-14 03:34:39 +00:00
this - > setErrorNumber ( E_ENOMEM ) ;
2018-06-25 10:47:27 +00:00
return - 1 ;
}
2018-06-28 09:43:34 +00:00
mux_xtn_t * mux_xtn = ( mux_xtn_t * ) qse_mux_getxtn ( mux ) ;
mux_xtn - > server = this ;
2018-06-28 14:07:35 +00:00
mux_xtn - > first_time = true ;
2018-06-26 14:43:43 +00:00
if ( : : pipe ( pfd ) < = - 1 )
2018-06-25 10:47:27 +00:00
{
2019-06-13 10:18:30 +00:00
this - > setErrorFmt ( syserr_to_errnum ( errno ) , QSE_T ( " %hs " ) , strerror ( errno ) ) ;
2018-06-26 14:43:43 +00:00
goto oops ;
2018-06-25 10:47:27 +00:00
}
2018-10-22 03:46:19 +00:00
# if defined(FD_CLOEXEC)
2018-06-26 14:43:43 +00:00
fcv = : : fcntl ( pfd [ 0 ] , F_GETFD , 0 ) ;
2018-10-22 03:46:19 +00:00
if ( fcv > = 0 ) : : fcntl ( pfd [ 0 ] , F_SETFD , fcv | FD_CLOEXEC ) ;
2018-06-26 14:43:43 +00:00
fcv = : : fcntl ( pfd [ 1 ] , F_GETFD , 0 ) ;
2018-10-22 03:46:19 +00:00
if ( fcv > = 0 ) : : fcntl ( pfd [ 1 ] , F_SETFD , fcv | FD_CLOEXEC ) ;
2018-06-26 14:43:43 +00:00
# endif
# if defined(O_NONBLOCK)
fcv = : : fcntl ( pfd [ 0 ] , F_GETFL , 0 ) ;
if ( fcv > = 0 ) : : fcntl ( pfd [ 0 ] , F_SETFL , fcv | O_NONBLOCK ) ;
fcv = : : fcntl ( pfd [ 1 ] , F_GETFL , 0 ) ;
if ( fcv > = 0 ) : : fcntl ( pfd [ 1 ] , F_SETFL , fcv | O_NONBLOCK ) ;
# endif
QSE_MEMSET ( & ev , 0 , QSE_SIZEOF ( ev ) ) ;
2018-06-28 09:43:34 +00:00
ev . hnd = pfd [ 0 ] ;
ev . mask = QSE_MUX_IN ;
ev . data = QSE_NULL ;
if ( qse_mux_insert ( mux , & ev ) < = - 1 )
{
2019-06-14 03:34:39 +00:00
this - > setErrorNumber ( E_ESYSERR ) ;
2018-06-28 09:43:34 +00:00
goto oops ;
2018-06-26 14:43:43 +00:00
}
2019-06-14 03:34:39 +00:00
this - > setErrorNumber ( E_ENOERR ) ;
2019-06-13 10:18:30 +00:00
2018-06-26 14:43:43 +00:00
addr_ptr = addrs ;
while ( 1 )
{
qse_size_t addr_len ;
2019-06-13 10:18:30 +00:00
Listener * lsck = QSE_NULL ;
2018-06-26 14:43:43 +00:00
Socket sock ;
comma = qse_strchr ( addr_ptr , QSE_T ( ' , ' ) ) ;
addr_len = comma ? comma - addr_ptr : qse_strlen ( addr_ptr ) ;
2020-08-12 08:22:23 +00:00
addr_ptr = strip_enclosing_spaces ( addr_ptr , & addr_len ) ;
2018-06-26 14:43:43 +00:00
if ( sockaddr . set ( addr_ptr , addr_len ) < = - 1 )
{
2019-11-13 06:33:43 +00:00
this - > logfmt ( QSE_LOG_ERROR , QSE_T ( " unrecognized listener address - %.*js \n " ) , ( int ) addr_len , addr_ptr ) ;
2019-06-13 10:18:30 +00:00
goto skip_segment ;
2018-06-26 14:43:43 +00:00
}
try
{
2018-07-01 02:11:33 +00:00
lsck = new ( this - > getMmgr ( ) ) Listener ( this ) ;
2018-06-26 14:43:43 +00:00
}
catch ( . . . )
{
2019-11-13 06:33:43 +00:00
this - > logfmt ( QSE_LOG_ERROR , QSE_T ( " unable to instantiate listener \n " ) ) ;
2019-06-13 10:18:30 +00:00
goto skip_segment ;
2018-06-26 14:43:43 +00:00
}
2018-06-26 15:27:52 +00:00
if ( lsck - > open ( sockaddr . getFamily ( ) , QSE_SOCK_STREAM , 0 , Socket : : T_CLOEXEC | Socket : : T_NONBLOCK ) < = - 1 )
2018-06-26 14:43:43 +00:00
{
2019-06-14 05:53:24 +00:00
int xerrno = errno ;
2019-11-13 06:33:43 +00:00
this - > logfmt ( QSE_LOG_ERROR , QSE_T ( " unable to open listener socket on %.*js on %hs \n " ) , ( int ) addr_len , addr_ptr , strerror ( xerrno ) ) ;
2019-06-14 05:53:24 +00:00
this - > setErrorFmt ( syserr_to_errnum ( xerrno ) , QSE_T ( " %hs " ) , strerror ( xerrno ) ) ;
2019-06-13 10:18:30 +00:00
goto skip_segment ;
2018-06-26 14:43:43 +00:00
}
lsck - > setReuseAddr ( 1 ) ;
lsck - > setReusePort ( 1 ) ;
if ( lsck - > bind ( sockaddr ) < = - 1 | | lsck - > listen ( ) < = - 1 )
{
2019-06-14 05:53:24 +00:00
int xerrno = errno ;
2020-09-14 04:19:57 +00:00
this - > logfmt ( QSE_LOG_ERROR , QSE_T ( " [l=%d] unable to bind/listen on %.*js - %hs \n " ) , ( int ) lsck - > getHandle ( ) , ( int ) addr_len , addr_ptr , strerror ( xerrno ) ) ;
2019-06-14 05:53:24 +00:00
this - > setErrorFmt ( syserr_to_errnum ( xerrno ) , QSE_T ( " %hs " ) , strerror ( xerrno ) ) ;
2019-06-13 10:18:30 +00:00
goto skip_segment ;
2018-06-26 14:43:43 +00:00
}
QSE_MEMSET ( & ev , 0 , QSE_SIZEOF ( ev ) ) ;
2018-06-28 09:43:34 +00:00
ev . hnd = lsck - > getHandle ( ) ;
ev . mask = QSE_MUX_IN ;
ev . data = lsck ;
if ( qse_mux_insert ( mux , & ev ) < = - 1 )
{
2020-09-14 04:19:57 +00:00
this - > logfmt ( QSE_LOG_ERROR , QSE_T ( " [l=%d] unable to register listener on %.*js to multiplexer \n " ) , ( int ) ev . hnd , ( int ) addr_len , addr_ptr ) ;
2019-06-13 10:18:30 +00:00
goto skip_segment ;
2018-06-28 09:43:34 +00:00
}
2018-06-26 14:43:43 +00:00
2020-09-14 04:19:57 +00:00
this - > logfmt ( QSE_LOG_INFO , QSE_T ( " [l=%d] listening on %.*js \n " ) , ( int ) ev . hnd , ( int ) addr_len , addr_ptr ) ;
2018-06-26 14:43:43 +00:00
lsck - > address = sockaddr ;
2019-06-14 08:35:11 +00:00
lsck - > next_listener = this - > _listener_list . head ;
this - > _listener_list . head = lsck ;
this - > _listener_list . count + + ;
2019-06-13 10:18:30 +00:00
goto segment_done ; // lsck has been added to the listener list. i must not close and destroy it
skip_segment :
if ( lsck )
{
lsck - > close ( ) ;
QSE_CPP_DELETE_WITH_MMGR ( lsck , Listener , this - > getMmgr ( ) ) ;
lsck = QSE_NULL ;
}
2018-06-26 14:43:43 +00:00
2019-06-13 10:18:30 +00:00
segment_done :
2018-06-26 14:43:43 +00:00
if ( ! comma ) break ;
addr_ptr = comma + 1 ;
}
2019-06-14 08:35:11 +00:00
if ( ! this - > _listener_list . head )
2019-06-13 10:18:30 +00:00
{
2019-06-14 03:34:39 +00:00
if ( this - > getErrorNumber ( ) = = E_ENOERR )
2019-06-13 10:18:30 +00:00
{
this - > setErrorFmt ( E_EINVAL , QSE_T ( " unable to create liteners with %js " ) , addrs ) ;
}
else
{
const qse_char_t * emb = this - > backupErrorMsg ( ) ;
this - > setErrorFmt ( E_EINVAL , QSE_T ( " unable to create liteners with %js - %js " ) , addrs , emb ) ;
}
goto oops ;
}
2019-06-14 08:35:11 +00:00
this - > _listener_list . mux = mux ;
this - > _listener_list . mux_pipe [ 0 ] = pfd [ 0 ] ;
this - > _listener_list . mux_pipe [ 1 ] = pfd [ 1 ] ;
2018-06-26 14:43:43 +00:00
2018-06-25 10:47:27 +00:00
return 0 ;
2018-06-26 14:43:43 +00:00
oops :
2019-06-14 08:35:11 +00:00
if ( this - > _listener_list . head ) this - > free_all_listeners ( ) ;
2018-06-26 14:43:43 +00:00
if ( pfd [ 0 ] > = 0 ) close ( pfd [ 0 ] ) ;
if ( pfd [ 1 ] > = 0 ) close ( pfd [ 1 ] ) ;
2018-06-28 09:43:34 +00:00
if ( mux ) qse_mux_close ( mux ) ;
2018-06-26 14:43:43 +00:00
return - 1 ;
2018-06-25 10:47:27 +00:00
}
2019-11-12 07:55:32 +00:00
int TcpServer : : execute ( const qse_char_t * addrs ) QSE_CPP_NOEXCEPT
2018-06-25 10:47:27 +00:00
{
2018-06-26 15:27:52 +00:00
int xret = 0 ;
2019-06-14 08:35:11 +00:00
this - > _server_serving = true ;
2019-11-13 06:33:43 +00:00
this - > setHaltRequested ( false ) ;
2018-06-25 10:47:27 +00:00
try
{
2018-06-26 14:43:43 +00:00
if ( this - > setup_listeners ( addrs ) < = - 1 )
2018-06-25 10:47:27 +00:00
{
2019-06-14 08:35:11 +00:00
this - > _server_serving = false ;
2019-11-13 06:33:43 +00:00
this - > setHaltRequested ( false ) ;
2018-06-25 10:47:27 +00:00
return - 1 ;
}
2019-06-14 08:35:11 +00:00
mux_xtn_t * mux_xtn = ( mux_xtn_t * ) qse_mux_getxtn ( this - > _listener_list . mux ) ;
2018-06-28 14:07:35 +00:00
2019-11-13 06:33:43 +00:00
while ( ! this - > isHaltRequested ( ) )
2018-06-25 10:47:27 +00:00
{
2018-06-26 15:27:52 +00:00
int n ;
2018-06-25 10:47:27 +00:00
2018-06-28 14:07:35 +00:00
mux_xtn - > first_time = true ;
2018-06-28 09:43:34 +00:00
2019-06-14 08:35:11 +00:00
n = qse_mux_poll ( this - > _listener_list . mux , QSE_NULL ) ;
2018-06-26 15:27:52 +00:00
if ( n < = - 1 )
2018-06-25 10:47:27 +00:00
{
2019-06-14 08:35:11 +00:00
qse_mux_errnum_t merr = qse_mux_geterrnum ( this - > _listener_list . mux ) ;
2019-06-11 09:10:09 +00:00
if ( merr ! = QSE_MUX_EINTR )
{
2019-06-14 03:34:39 +00:00
this - > setErrorNumber ( E_ESYSERR ) ; // TODO: proper error code conversion
2019-06-11 09:10:09 +00:00
xret = - 1 ;
break ;
}
2018-06-25 10:47:27 +00:00
}
}
2019-06-14 08:35:11 +00:00
this - > delete_all_connections ( Connection : : LIVE ) ;
this - > delete_all_connections ( Connection : : DEAD ) ;
2018-06-25 10:47:27 +00:00
}
catch ( . . . )
{
2019-06-14 08:35:11 +00:00
this - > delete_all_connections ( Connection : : LIVE ) ;
this - > delete_all_connections ( Connection : : DEAD ) ;
2018-06-25 10:47:27 +00:00
2019-06-14 03:34:39 +00:00
this - > setErrorNumber ( E_EEXCEPT ) ;
2019-06-14 08:35:11 +00:00
this - > _server_serving = false ;
2019-11-13 06:33:43 +00:00
this - > setHaltRequested ( false ) ;
2018-06-26 15:27:52 +00:00
this - > free_all_listeners ( ) ;
2019-11-13 06:33:43 +00:00
this - > free_wid_map ( ) ;
2018-06-25 10:47:27 +00:00
return - 1 ;
}
2019-06-14 08:35:11 +00:00
this - > _server_serving = false ;
2019-11-13 06:33:43 +00:00
this - > setHaltRequested ( false ) ;
2018-06-26 15:27:52 +00:00
this - > free_all_listeners ( ) ;
2019-11-13 06:33:43 +00:00
this - > free_wid_map ( ) ;
2018-06-26 15:27:52 +00:00
return xret ;
2018-06-25 10:47:27 +00:00
}
2019-11-12 07:55:32 +00:00
int TcpServer : : halt ( ) QSE_CPP_NOEXCEPT
2018-06-25 10:47:27 +00:00
{
2019-06-14 08:35:11 +00:00
if ( this - > _server_serving )
2018-06-26 15:27:52 +00:00
{
2019-11-13 06:33:43 +00:00
// set halt request before writing "Q" to avoid race condition.
2018-10-28 15:49:46 +00:00
// after qse_mux_poll() detects activity for "Q" written,
// it loops over to another qse_mux_poll(). the stop request
// test is done in between. if this looping is faster than
// setting stop request after "Q" writing, the second qse_mux_poll()
// doesn't see it set to true yet.
2019-11-13 06:33:43 +00:00
this - > setHaltRequested ( true ) ;
2018-10-28 15:49:46 +00:00
2019-06-14 08:35:11 +00:00
this - > _listener_list . mux_pipe_spl . lock ( ) ;
if ( this - > _listener_list . mux_pipe [ 1 ] > = 0 )
2018-06-26 15:27:52 +00:00
{
2019-06-14 08:35:11 +00:00
: : write ( this - > _listener_list . mux_pipe [ 1 ] , " Q " , 1 ) ;
2018-06-26 15:27:52 +00:00
}
2019-06-14 08:35:11 +00:00
this - > _listener_list . mux_pipe_spl . unlock ( ) ;
2018-06-26 15:27:52 +00:00
}
2018-06-25 10:47:27 +00:00
return 0 ;
}
2019-06-14 08:35:11 +00:00
void TcpServer : : delete_all_connections ( Connection : : State state ) QSE_CPP_NOEXCEPT
2018-06-25 10:47:27 +00:00
{
2019-06-14 08:35:11 +00:00
Connection * connection ;
2018-06-27 11:18:20 +00:00
2018-07-01 11:21:00 +00:00
while ( 1 )
2018-06-25 10:47:27 +00:00
{
2019-06-14 08:35:11 +00:00
this - > _connection_list_spl . lock ( ) ;
connection = this - > _connection_list [ state ] . getHead ( ) ;
if ( connection )
2018-06-25 10:47:27 +00:00
{
2019-06-14 08:35:11 +00:00
this - > _connection_list [ state ] . remove ( connection ) ;
connection - > claimed = true ;
connection - > stop ( ) ;
2018-06-25 10:47:27 +00:00
}
2019-06-14 08:35:11 +00:00
this - > _connection_list_spl . unlock ( ) ;
if ( ! connection ) break ;
2018-07-01 13:57:37 +00:00
2019-06-14 08:35:11 +00:00
connection - > join ( ) ;
2018-07-01 13:57:37 +00:00
2019-06-14 08:35:11 +00:00
this - > release_wid ( connection ) ;
QSE_CPP_DELETE_WITH_MMGR ( connection , Connection , this - > getMmgr ( ) ) ; // delete connection
2018-07-01 13:57:37 +00:00
}
}
int TcpServer : : prepare_to_acquire_wid ( ) QSE_CPP_NOEXCEPT
{
qse_size_t new_capa ;
qse_size_t i , j ;
2019-06-14 08:35:11 +00:00
_wid_map_data_t * tmp ;
2018-07-01 13:57:37 +00:00
2019-06-14 08:35:11 +00:00
QSE_ASSERT ( this - > _wid_map . free_first = = _wid_map_t : : WID_INVALID ) ;
QSE_ASSERT ( this - > _wid_map . free_last = = _wid_map_t : : WID_INVALID ) ;
2018-07-01 13:57:37 +00:00
2019-06-14 08:35:11 +00:00
new_capa = QSE_ALIGNTO_POW2 ( this - > _wid_map . capa + 1 , WID_MAP_ALIGN ) ;
2018-07-01 13:57:37 +00:00
if ( new_capa > WID_MAX )
{
2019-06-14 08:35:11 +00:00
if ( this - > _wid_map . capa > = WID_MAX )
2018-07-01 13:57:37 +00:00
{
2019-06-14 03:34:39 +00:00
this - > setErrorNumber ( E_ENOMEM ) ; // TODO: proper error code
2018-07-01 13:57:37 +00:00
return - 1 ;
}
new_capa = WID_MAX ;
}
2019-06-14 08:35:11 +00:00
tmp = ( _wid_map_data_t * ) this - > getMmgr ( ) - > reallocate ( this - > _wid_map . ptr , QSE_SIZEOF ( * tmp ) * new_capa , false ) ;
2018-07-01 13:57:37 +00:00
if ( ! tmp )
{
2019-06-14 03:34:39 +00:00
this - > setErrorNumber ( E_ENOMEM ) ;
2018-07-01 13:57:37 +00:00
return - 1 ;
}
2019-06-14 08:35:11 +00:00
this - > _wid_map . free_first = this - > _wid_map . capa ;
for ( i = this - > _wid_map . capa , j = this - > _wid_map . capa + 1 ; j < new_capa ; i + + , j + + )
2018-07-01 13:57:37 +00:00
{
tmp [ i ] . used = 0 ;
tmp [ i ] . u . next = j ;
}
tmp [ i ] . used = 0 ;
2019-06-14 08:35:11 +00:00
tmp [ i ] . u . next = _wid_map_t : : WID_INVALID ;
this - > _wid_map . free_last = i ;
2018-07-01 13:57:37 +00:00
2019-06-14 08:35:11 +00:00
this - > _wid_map . ptr = tmp ;
this - > _wid_map . capa = new_capa ;
2018-07-01 13:57:37 +00:00
return 0 ;
}
2019-06-14 08:35:11 +00:00
void TcpServer : : acquire_wid ( Connection * connection ) QSE_CPP_NOEXCEPT
2018-07-01 13:57:37 +00:00
{
qse_size_t wid ;
2018-06-25 10:47:27 +00:00
2019-06-14 08:35:11 +00:00
wid = this - > _wid_map . free_first ;
connection - > wid = wid ;
2018-07-01 13:57:37 +00:00
2019-06-14 08:35:11 +00:00
this - > _wid_map . free_first = this - > _wid_map . ptr [ wid ] . u . next ;
if ( this - > _wid_map . free_first = = _wid_map_t : : WID_INVALID ) this - > _wid_map . free_last = _wid_map_t : : WID_INVALID ;
2018-07-01 13:57:37 +00:00
2019-06-14 08:35:11 +00:00
this - > _wid_map . ptr [ wid ] . used = 1 ;
this - > _wid_map . ptr [ wid ] . u . connection = connection ;
2018-07-01 13:57:37 +00:00
}
2019-06-14 08:35:11 +00:00
void TcpServer : : release_wid ( Connection * connection ) QSE_CPP_NOEXCEPT
2018-07-01 13:57:37 +00:00
{
qse_size_t wid ;
2019-06-14 08:35:11 +00:00
wid = connection - > wid ;
QSE_ASSERT ( wid < this - > _wid_map . capa & & wid ! = _wid_map_t : : WID_INVALID ) ;
2018-07-01 13:57:37 +00:00
2019-06-14 08:35:11 +00:00
this - > _wid_map . ptr [ wid ] . used = 0 ;
this - > _wid_map . ptr [ wid ] . u . next = _wid_map_t : : WID_INVALID ;
if ( this - > _wid_map . free_last = = _wid_map_t : : WID_INVALID )
2018-07-01 13:57:37 +00:00
{
2019-06-14 08:35:11 +00:00
QSE_ASSERT ( this - > _wid_map . free_first < = _wid_map_t : : WID_INVALID ) ;
this - > _wid_map . free_first = wid ;
2018-07-01 13:57:37 +00:00
}
else
{
2019-06-14 08:35:11 +00:00
this - > _wid_map . ptr [ this - > _wid_map . free_last ] . u . next = wid ;
2018-07-01 13:57:37 +00:00
}
2019-06-14 08:35:11 +00:00
this - > _wid_map . free_last = wid ;
connection - > wid = _wid_map_t : : WID_INVALID ;
2018-07-01 13:57:37 +00:00
}
2019-11-13 06:33:43 +00:00
void TcpServer : : free_wid_map ( ) QSE_CPP_NOEXCEPT
2018-07-01 13:57:37 +00:00
{
2019-06-14 08:35:11 +00:00
if ( this - > _wid_map . ptr )
2018-07-01 13:57:37 +00:00
{
2019-06-14 08:35:11 +00:00
this - > getMmgr ( ) - > dispose ( this - > _wid_map . ptr ) ;
this - > _wid_map . capa = 0 ;
this - > _wid_map . free_first = _wid_map_t : : WID_INVALID ;
this - > _wid_map . free_last = _wid_map_t : : WID_INVALID ;
2018-06-25 10:47:27 +00:00
}
}
QSE_END_NAMESPACE ( QSE )