diff --git a/application/app.cpp b/application/app.cpp index 24a823d..240eacb 100644 --- a/application/app.cpp +++ b/application/app.cpp @@ -8,6 +8,84 @@ using namespace motor::application ; +class motor::application::app::_app_client_handler_wrapper : public motor::network::iclient_handler +{ + motor::network::iclient_handler_mtr_t _handler ; + motor::application::app_ptr_t _app ; + + bool_t _shutdown = false ; + +public: + + _app_client_handler_wrapper( motor::application::app_ptr_t owner, motor::network::iclient_handler_ptr_t hnd ) noexcept : + _handler( hnd ), _app( owner ) {} + + _app_client_handler_wrapper( _app_client_handler_wrapper && rhv ) noexcept : + _handler( motor::move( rhv._handler ) ), _app( motor::move( rhv._app ) ) {} + + virtual ~_app_client_handler_wrapper( void_t ) noexcept + { + motor::memory::release_ptr( _handler ) ; + } + + virtual motor::network::user_decision on_connect( motor::network::connect_result const res, size_t const tries ) noexcept + { + auto const ret_res = _handler->on_connect( res, tries ) ; + if ( ret_res == motor::network::user_decision::shutdown ) + { + _app->remove( this ) ; + } + return ret_res ; + } + + virtual motor::network::user_decision on_sync( void_t ) noexcept + { + auto const ret_res = _handler->on_sync() ; + if ( ret_res == motor::network::user_decision::shutdown ) + { + _app->remove( this ) ; + } + return ret_res ; + } + + virtual motor::network::user_decision on_update( void_t ) noexcept + { + auto const ret_res = _handler->on_update() ; + if ( ret_res == motor::network::user_decision::shutdown || + _shutdown ) + { + _app->remove( this ) ; + return motor::network::user_decision::shutdown ; + } + return ret_res ; + } + + virtual void_t on_receive( byte_cptr_t buffer, size_t const sib ) noexcept + { + _handler->on_receive( buffer, sib ) ; + } + + virtual void_t on_received( void_t ) noexcept + { + _handler->on_received() ; + } + + virtual void_t on_send( byte_cptr_t & buffer, size_t & num_sib ) noexcept + { + _handler->on_send( buffer, num_sib ) ; + } + + virtual void_t on_sent( motor::network::transmit_result const res ) noexcept + { + _handler->on_sent( res ) ; + } + + void_t shutdown( void_t ) noexcept + { + _shutdown = true ; + } +}; + //************************************************************************************************************** app::app( void_t ) noexcept { @@ -329,25 +407,36 @@ bool_t app::carrier_shutdown( void_t ) noexcept _shutdown_called = true ; } - for( auto & d : _destruction_queue ) { - if( !this_t::clear_out_window_data( d ) ) + for ( auto & d : _destruction_queue ) { - return false ; + if ( !this_t::clear_out_window_data( d ) ) + { + return false ; + } } - } - _destruction_queue.clear() ; + _destruction_queue.clear() ; - for( auto & d : _windows ) - { - if( !this_t::clear_out_window_data( d ) ) + for ( auto & d : _windows ) { - return false ; + if ( !this_t::clear_out_window_data( d ) ) + { + return false ; + } } + + _windows.clear() ; } - _windows.clear() ; + // clear out network clients + { + for( auto & ns : _networks ) + { + ns.wrapper->shutdown() ; + motor::memory::release_ptr( motor::move( ns.wrapper ) ) ; + } + } return true ; } @@ -562,65 +651,6 @@ void_t app::display_profiling_data( void_t ) noexcept _engine_profiling.display() ; } -class motor::application::app::_app_client_handler_wrapper : public motor::network::iclient_handler -{ - motor::network::iclient_handler_mtr_t _handler ; - motor::application::app_ptr_t _app ; - -public: - - _app_client_handler_wrapper( motor::application::app_ptr_t owner, motor::network::iclient_handler_ptr_t hnd ) noexcept : - _handler( hnd ), _app( owner ) {} - - _app_client_handler_wrapper( _app_client_handler_wrapper && rhv ) noexcept : - _handler( motor::move(rhv._handler) ), _app( motor::move(rhv._app) ) {} - - ~_app_client_handler_wrapper( void_t ) noexcept - { - motor::memory::release_ptr( _handler ) ; - } - - virtual motor::network::user_decision on_connect( motor::network::connect_result const res, size_t const tries ) noexcept - { - if ( res == motor::network::connect_result::closed ) - { - // need to remove from network list - //_app->remove... - } - return _handler->on_connect( res, tries ) ; - } - - virtual motor::network::user_decision on_sync( void_t ) noexcept - { - return _handler->on_sync() ; - } - - virtual motor::network::user_decision on_update( void_t ) noexcept - { - return _handler->on_update() ; - } - - virtual void_t on_receive( byte_cptr_t buffer, size_t const sib ) noexcept - { - _handler->on_receive( buffer, sib ) ; - } - - virtual void_t on_received( void_t ) noexcept - { - _handler->on_received() ; - } - - virtual void_t on_send( byte_cptr_t & buffer, size_t & num_sib ) noexcept - { - _handler->on_send( buffer, num_sib ) ; - } - - virtual void_t on_sent( motor::network::transmit_result const res ) noexcept - { - _handler->on_sent( res ) ; - } -}; - //********************************************************************** void_t app::create_tcp_client( motor::string_in_t name, motor::network::ipv4::binding_point_host_in_t bp, motor::network::iclient_handler_mtr_rref_t handler ) noexcept @@ -629,15 +659,31 @@ void_t app::create_tcp_client( motor::string_in_t name, motor::network::ipv4::bi { _app_client_handler_wrapper * wrapper = motor::shared( _app_client_handler_wrapper( this, motor::move(handler) ), - "[app::create_tcp_client] : network_handler_wrapper" ) ; + "[app::create_tcp_client] : network_client_handler_wrapper" ) ; auto const sid = mod->create_tcp_client( { name, bp, motor::share( wrapper ) } ) ; if( sid != motor::network::socket_id_t( -1 ) ) { - _networks.emplace_back( this_t::network_store{ sid, motor::share(mod), wrapper } ) ; + std::lock_guard< std::mutex > lk( _mtx_networks ) ; + _networks.emplace_back( this_t::network_store{ sid, wrapper } ) ; return true ; } return false ; } ) ; +} + +//********************************************************************** +void_t app::remove( _app_client_handler_wrapper * handler ) noexcept +{ + std::lock_guard< std::mutex > lk( _mtx_networks ) ; + + auto const iter = std::find_if( _networks.begin(), _networks.end(), [&]( this_t::network_store const & d ) + { + return d.wrapper == handler ; + } ) ; + + if( iter == _networks.end() ) return ; + motor::memory::release_ptr( iter->wrapper ) ; + _networks.erase( iter ) ; } \ No newline at end of file diff --git a/application/app.h b/application/app.h index 6a0e008..49c2a27 100644 --- a/application/app.h +++ b/application/app.h @@ -93,14 +93,18 @@ namespace motor private: // netork class _app_client_handler_wrapper ; + friend class _app_client_handler_wrapper ; + struct network_store { motor::network::socket_id_t sid ; - motor::network::imodule_mtr_t mod ; _app_client_handler_wrapper * wrapper ; }; motor::vector< network_store > _networks ; + std::mutex _mtx_networks ; + void_t remove( _app_client_handler_wrapper * ) noexcept ; + public: // profiling motor::tool::engine_profiling_t _engine_profiling ; diff --git a/network/imodule.h b/network/imodule.h index 8b252ba..aa362d4 100644 --- a/network/imodule.h +++ b/network/imodule.h @@ -22,6 +22,8 @@ namespace motor{ namespace network virtual motor::network::transmit_result on_send( motor::network::client_id_t const, byte_cptr_t & buffer, size_t & num_sib ) noexcept = 0 ; + + virtual motor::network::server_decision on_update( motor::network::client_id_t const ) noexcept = 0 ; }; motor_typedef( iserver_handler ) ; @@ -33,8 +35,13 @@ namespace motor{ namespace network }; motor_typedef( create_tcp_server_info ) ; - class iclient_handler + class MOTOR_NETWORK_API iclient_handler { + + public: + + virtual ~iclient_handler( void_t ) noexcept {} + public: virtual motor::network::user_decision on_connect( motor::network::connect_result const, size_t const tries ) noexcept = 0 ; @@ -59,6 +66,10 @@ namespace motor{ namespace network class MOTOR_NETWORK_API imodule { + public: + + virtual ~imodule( void_t ) noexcept {} + public: virtual socket_id_t create_tcp_client( motor::network::create_tcp_client_info_rref_t ) noexcept = 0 ; diff --git a/network/system.cpp b/network/system.cpp index 450dffa..4ab8eb5 100644 --- a/network/system.cpp +++ b/network/system.cpp @@ -17,6 +17,10 @@ system::system( this_rref_t rhv ) noexcept //******************************************************************* system::~system( void_t ) noexcept { + for( auto * mod : _mods ) + { + motor::memory::release_ptr( mod ) ; + } } //******************************************************************* diff --git a/network/typedefs.h b/network/typedefs.h index 45b9294..86c3d5f 100644 --- a/network/typedefs.h +++ b/network/typedefs.h @@ -30,6 +30,7 @@ namespace motor { initial, established, + refused, closed, failed }; @@ -37,7 +38,7 @@ namespace motor static motor::string_t to_string( connect_result const res ) noexcept { static char const * const __connect_result_strings[] = - { "initial", "established", "closed", "failed" } ; + { "initial", "established", "refused", "closed", "failed" } ; return __connect_result_strings[ size_t( res ) ] ; } @@ -61,6 +62,12 @@ namespace motor shutdown }; + enum class server_decision + { + keep_going, + shutdown, + shutdown_client + }; static const size_t send_buffer_sib = 2048 ; diff --git a/platform/network/win32/win32_net_module.cpp b/platform/network/win32/win32_net_module.cpp index 3172540..160d688 100644 --- a/platform/network/win32/win32_net_module.cpp +++ b/platform/network/win32/win32_net_module.cpp @@ -180,6 +180,8 @@ motor::network::socket_id_t win32_net_module::create_tcp_server( size_t idx = 0 ; for ( auto & ci : tcpd->clients ) { + if( ci.s == INVALID_SOCKET ) continue ; + // send { byte_cptr_t buffer = nullptr ; @@ -197,9 +199,21 @@ motor::network::socket_id_t win32_net_module::create_tcp_server( auto const has_sent = send( ci.s, (const char *) buffer, int( sib ), 0 ) ; if ( has_sent == SOCKET_ERROR ) { + auto const err_code = WSAGetLastError() ; + motor::log::global::error( "[win32_net_module::server_thread] : send" ) ; motor::log::global::error( "[win32_net_module::server_thread] : WSAGetLastError " + - motor::to_string( has_sent ) ) ; + motor::to_string( err_code ) ) ; + + switch( err_code ) + { + case WSAENOTCONN: + case WSAESHUTDOWN: + case WSAETIMEDOUT: + ci.s = INVALID_SOCKET ; + break ; + + } } if ( has_sent != sib ) { @@ -226,25 +240,54 @@ motor::network::socket_id_t win32_net_module::create_tcp_server( if ( received == 0 ) { tcpd->handler->on_close( idx ) ; + auto const cs_res = closesocket( ci.s ) ; + if ( cs_res == SOCKET_ERROR ) + { + auto const err_code = WSAGetLastError() ; + motor::log::global::error( "[win32_net_module::server_thread] : send" ) ; + motor::log::global::error( "[win32_net_module::server_thread] : WSAGetLastError " + + motor::to_string( err_code ) ) ; + } + ci.s = INVALID_SOCKET ; break ; } // timeout and others - if ( received == -1 ) + if ( received != -1 ) { - //std::this_thread::sleep_for( std::chrono::milliseconds( 5 ) ) ; - continue ; + auto const res = tcpd->handler->on_receive( idx, (byte_cptr_t) buffer, received ) ; + if ( res == motor::network::receive_result::close ) break ; } + } - auto const res = tcpd->handler->on_receive( idx, (byte_cptr_t) buffer, received ) ; - if ( res == motor::network::receive_result::close ) break ; + // update + { + auto const res = tcpd->handler->on_update( idx ) ; + switch( res ) + { + case motor::network::server_decision::keep_going: break ; + case motor::network::server_decision::shutdown: break ; + case motor::network::server_decision::shutdown_client: + { + auto const cs_res = closesocket( ci.s ) ; + if( cs_res == SOCKET_ERROR ) + { + auto const err_code = WSAGetLastError() ; + motor::log::global::error( "[win32_net_module::server_thread] : send" ) ; + motor::log::global::error( "[win32_net_module::server_thread] : WSAGetLastError " + + motor::to_string( err_code ) ) ; + } + motor::log::global::status( "[win32_net_module] : socket closed" ) ; + ci.s = INVALID_SOCKET ; + break ; + } + } } ++idx ; } } - std::this_thread::sleep_for( std::chrono::milliseconds( 5 ) ) ; } } ) ; @@ -254,8 +297,10 @@ motor::network::socket_id_t win32_net_module::create_tcp_server( } //***************************************************************** -SOCKET win32_net_module::connect_client( motor::network::ipv4::binding_point_host const & bp ) const noexcept +SOCKET win32_net_module::connect_client( motor::network::ipv4::binding_point_host const & bp, motor::network::connect_result & res_out ) const noexcept { + res_out = motor::network::connect_result::failed ; + SOCKET s = INVALID_SOCKET ; addrinfo * result = NULL ; addrinfo * ptr = NULL ; @@ -294,9 +339,22 @@ SOCKET win32_net_module::connect_client( motor::network::ipv4::binding_point_hos } // Connect to server. - auto const con_res = connect( s, ptr->ai_addr, (int) ptr->ai_addrlen ); + auto const con_res = connect( s, ptr->ai_addr, (int) ptr->ai_addrlen ) ; if ( con_res == SOCKET_ERROR ) { + auto const con_wsa_res = WSAGetLastError() ; + + if( con_wsa_res == WSAECONNREFUSED ) + { + res_out = motor::network::connect_result::refused ; + } + else + { + motor::log::global::error( "[win32_net_module::connect_client] : connect" ) ; + motor::log::global::error( "[win32_net_module::connect_client] : WSAGetLastError " + + motor::to_string( con_wsa_res ) ) ; + } + closesocket( s ); s = INVALID_SOCKET; continue; @@ -309,10 +367,6 @@ SOCKET win32_net_module::connect_client( motor::network::ipv4::binding_point_hos if ( s == INVALID_SOCKET ) { - motor::log::global::error( "[win32_net_module::connect_client] : connect" ) ; - motor::log::global::error( "[win32_net_module::connect_client] : WSAGetLastError " + - motor::to_string( WSAGetLastError() ) ) ; - return motor::network::socket_id_t( -1 ) ; } @@ -342,6 +396,7 @@ SOCKET win32_net_module::connect_client( motor::network::ipv4::binding_point_hos } } + res_out = motor::network::connect_result::established ; return s ; } @@ -371,19 +426,14 @@ motor::network::socket_id_t win32_net_module::create_tcp_client( motor::network::connect_result connection_state = motor::network::connect_result::initial ; size_t connection_tryouts = 0 ; - - while ( true ) + + while ( tcpd->run ) { // try connect loop { if ( tcpd->s == INVALID_SOCKET ) { - tcpd->s = this_t::connect_client( tcpd->bp ) ; - - if ( tcpd->s == INVALID_SOCKET ) - connection_state = motor::network::connect_result::failed ; - else - connection_state = motor::network::connect_result::established ; + tcpd->s = this_t::connect_client( tcpd->bp, connection_state ) ; auto const what_to_do = tcpd->handler->on_connect( connection_state, ++connection_tryouts ) ; if ( what_to_do == motor::network::user_decision::shutdown ) @@ -451,6 +501,7 @@ motor::network::socket_id_t win32_net_module::create_tcp_client( tcpd->handler->on_connect( motor::network::connect_result::closed, 0 ) ; closesocket( tcpd->s ) ; tcpd->s = INVALID_SOCKET ; + tcpd->run = false ; break ; } @@ -463,6 +514,7 @@ motor::network::socket_id_t win32_net_module::create_tcp_client( if( received < buflen ) break ; } + if( !tcpd->run ) break ; if( tcpd->s == INVALID_SOCKET ) continue ; if( something_received ) tcpd->handler->on_received() ; @@ -476,12 +528,17 @@ motor::network::socket_id_t win32_net_module::create_tcp_client( #endif } - if( tcpd->s != INVALID_SOCKET ) + if ( tcpd->s != INVALID_SOCKET ) { closesocket( tcpd->s ) ; tcpd->handler->on_connect( motor::network::connect_result::closed, 0 ) ; + } + + { motor::release( motor::move( tcpd->handler ) ) ; tcpd->used = false ; + + motor::log::global_t::status("[win32_net_module] : client shutdown") ; } } ) ; } @@ -548,8 +605,15 @@ size_t win32_net_module::create_tcp_server_id( SOCKET s ) noexcept //***************************************************************** void_t win32_net_module::release_all_tcp( void_t ) noexcept { - for ( auto * ptr : _tcp_clients ) + for ( auto * tcpd : _tcp_clients ) { - + if( tcpd->run ) + { + tcpd->run = false ; + if( tcpd->t.joinable() ) + tcpd->t.join() ; + } + motor::memory::release_ptr( tcpd->handler ) ; + motor::memory::global_t::dealloc( tcpd ) ; } } \ No newline at end of file diff --git a/platform/network/win32/win32_net_module.h b/platform/network/win32/win32_net_module.h index 0bb23e8..8752d79 100644 --- a/platform/network/win32/win32_net_module.h +++ b/platform/network/win32/win32_net_module.h @@ -85,6 +85,7 @@ namespace motor { namespace platform { namespace win32 motor::network::ipv4::binding_point_host bp ; bool_t used = true ; + bool_t run = true ; motor::network::iclient_handler_mtr_t handler ; @@ -117,7 +118,7 @@ namespace motor { namespace platform { namespace win32 win32_net_module( void_t ) noexcept ; win32_net_module( this_cref_t ) = delete ; win32_net_module( this_rref_t ) noexcept ; - ~win32_net_module( void_t ) noexcept ; + virtual ~win32_net_module( void_t ) noexcept ; public: // interface @@ -134,7 +135,7 @@ namespace motor { namespace platform { namespace win32 size_t create_tcp_client_id( void_t ) noexcept ; size_t create_tcp_server_id( SOCKET ) noexcept ; - SOCKET connect_client( motor::network::ipv4::binding_point_host const & bp ) const noexcept ; + SOCKET connect_client( motor::network::ipv4::binding_point_host const & bp, motor::network::connect_result & ) const noexcept ; void_t release_all_tcp( void_t ) noexcept ; };