2022-07-27 15:51:07 +08:00
# include <assert.h>
2022-07-27 18:32:22 +08:00
# include <errno.h>
2022-07-27 15:51:07 +08:00
2022-08-03 19:46:43 +08:00
# include "uthash/uthash.h"
# include "session_manager.h"
# include "plugin_manager_module.h"
2022-07-27 15:51:07 +08:00
/******************************************************************************
2022-07-27 18:32:22 +08:00
* CallBack Runtime ( For Per Session )
2022-07-27 15:51:07 +08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-07-20 20:20:31 +08:00
2022-08-03 19:46:43 +08:00
struct callback_runtime
2022-07-06 23:18:13 +08:00
{
2022-07-27 18:32:22 +08:00
int skip ;
void * cb_args ;
2022-07-27 15:51:07 +08:00
enum session_event_type event ;
2022-08-03 19:46:43 +08:00
fn_session_event_callback * event_cb ;
fn_session_error_callback * error_cb ;
2022-07-06 23:18:13 +08:00
} ;
2022-07-27 18:32:22 +08:00
struct session_plugin_ctx
{
2022-08-03 19:46:43 +08:00
int callback_index ;
int callback_num ;
struct callback_runtime * callbacks ;
2022-07-27 15:51:07 +08:00
} ;
2022-07-06 23:18:13 +08:00
2022-07-27 15:51:07 +08:00
/******************************************************************************
2022-07-27 18:32:22 +08:00
* CallBack Static ( For Per Plugin Manager )
2022-07-27 15:51:07 +08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-08-03 19:46:43 +08:00
struct callback_static
2022-07-06 23:18:13 +08:00
{
2022-07-27 15:51:07 +08:00
enum session_event_type event ;
2022-08-03 19:46:43 +08:00
fn_session_event_callback * event_cb ;
fn_session_error_callback * error_cb ;
2022-07-06 23:18:13 +08:00
} ;
2022-07-27 18:32:22 +08:00
struct plugin_manager_eventcb
2022-07-06 23:18:13 +08:00
{
2022-07-27 18:32:22 +08:00
char session_name [ MAX_SESSION_NAME_LENGTH ] ; // key
2022-08-03 19:46:43 +08:00
int callback_num ; // val size
struct callback_static * callbacks ; // val: dynamic array
2022-07-27 18:32:22 +08:00
UT_hash_handle hh ;
2022-07-06 23:18:13 +08:00
} ;
2022-07-27 15:51:07 +08:00
/******************************************************************************
2022-07-27 18:32:22 +08:00
* Struct plugin_manager
2022-07-27 15:51:07 +08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-07-06 23:18:13 +08:00
2022-07-27 15:51:07 +08:00
struct plugin_manager
2022-07-27 14:11:29 +08:00
{
2022-07-27 18:32:22 +08:00
int used_module_num ;
int used_config_num ;
int used_evencb_num ; // only plugin register eventcb numbers
struct plugin_manager_module * modules [ MAX_PLUGIN_NUM ] ;
struct plugin_manager_config * configs [ MAX_PLUGIN_NUM ] ;
struct plugin_manager_eventcb * evcb_htable ;
2022-07-27 14:11:29 +08:00
} ;
2022-07-27 15:51:07 +08:00
/******************************************************************************
2022-07-27 18:32:22 +08:00
* Create / Destory plugin ctx ( per session )
2022-07-27 15:51:07 +08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-07-27 18:32:22 +08:00
static struct session_plugin_ctx * plugin_manager_create_plugin_ctx ( struct plugin_manager * plug_mgr , const char * session_name )
2022-07-24 23:59:00 +08:00
{
2022-07-27 18:32:22 +08:00
if ( session_name = = NULL | | strlen ( session_name ) = = 0 )
{
plugin_manager_log ( ERROR , " invalid parameter, session name is empty " ) ;
return NULL ;
}
2022-07-24 23:59:00 +08:00
2022-07-27 18:32:22 +08:00
struct plugin_manager_eventcb * elem ;
HASH_FIND_STR ( plug_mgr - > evcb_htable , session_name , elem ) ;
if ( elem = = NULL )
{
plugin_manager_log ( ERROR , " can't find event callback for session name '%s' " , session_name ) ;
return NULL ;
}
else
{
struct session_plugin_ctx * plug_ctx = safe_alloc ( struct session_plugin_ctx , 1 ) ;
2022-08-03 19:46:43 +08:00
plug_ctx - > callback_num = elem - > callback_num ;
plug_ctx - > callbacks = safe_alloc ( struct callback_runtime , plug_ctx - > callback_num ) ;
2022-07-27 18:32:22 +08:00
2022-08-03 19:46:43 +08:00
for ( int i = 0 ; i < plug_ctx - > callback_num ; i + + )
2022-07-27 18:32:22 +08:00
{
2022-08-03 19:46:43 +08:00
plug_ctx - > callbacks [ i ] . skip = 0 ;
plug_ctx - > callbacks [ i ] . event = elem - > callbacks [ i ] . event ;
plug_ctx - > callbacks [ i ] . event_cb = elem - > callbacks [ i ] . event_cb ;
plug_ctx - > callbacks [ i ] . error_cb = elem - > callbacks [ i ] . error_cb ;
plug_ctx - > callbacks [ i ] . cb_args = NULL ;
2022-07-27 18:32:22 +08:00
}
return plug_ctx ;
}
2022-07-27 15:51:07 +08:00
}
2022-07-27 18:32:22 +08:00
static void plugin_manager_destory_plugin_ctx ( struct session_plugin_ctx * plug_ctx )
2022-07-27 15:51:07 +08:00
{
2022-07-27 18:32:22 +08:00
if ( plug_ctx )
{
2022-08-03 19:46:43 +08:00
safe_free ( plug_ctx - > callbacks ) ;
2022-07-27 18:32:22 +08:00
safe_free ( plug_ctx ) ;
}
2022-07-27 15:51:07 +08:00
}
/******************************************************************************
2022-07-27 18:32:22 +08:00
* Tools for managing plugins
2022-07-27 15:51:07 +08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-08-03 19:46:43 +08:00
static int plugin_manager_parse_plugins ( struct plugin_manager * plug_mgr , const char * file )
2022-07-27 15:51:07 +08:00
{
2022-07-27 18:32:22 +08:00
char line_buffer [ 4096 ] = { 0 } ;
2022-08-03 19:46:43 +08:00
2022-07-27 18:32:22 +08:00
if ( strlen ( file ) < = 0 )
{
plugin_manager_log ( ERROR , " Invalid parameter, plugin config file name cannot be empty " ) ;
return - 1 ;
}
2022-07-27 15:51:07 +08:00
2022-08-03 19:46:43 +08:00
FILE * fp = fopen ( file , " r " ) ;
2022-07-27 18:32:22 +08:00
if ( fp = = NULL )
{
2022-08-03 19:46:43 +08:00
plugin_manager_log ( ERROR , " can't open %s, %s " , file , strerror ( errno ) ) ;
2022-07-27 18:32:22 +08:00
return - 1 ;
}
while ( fgets ( line_buffer , sizeof ( line_buffer ) , fp ) )
{
if ( ' # ' = = line_buffer [ 0 ] | | ' \n ' = = line_buffer [ 0 ] )
{
memset ( line_buffer , 0 , sizeof ( line_buffer ) ) ;
continue ;
}
2022-08-03 19:46:43 +08:00
line_buffer [ strcspn ( line_buffer , " \r \n " ) ] = 0 ;
2022-07-27 18:32:22 +08:00
if ( plug_mgr - > used_config_num > = MAX_PLUGIN_NUM )
{
plugin_manager_log ( ERROR , " the number of registered plugins exceeds the limit and cannot exceed %d " , MAX_PLUGIN_NUM ) ;
goto err ;
}
struct plugin_manager_config * config = plugin_mangager_config_create ( ) ;
2022-08-03 19:46:43 +08:00
if ( plugin_mangager_config_parse ( config , line_buffer ) = = - 1 )
2022-07-27 18:32:22 +08:00
{
plugin_mangager_config_destory ( config ) ;
goto err ;
}
plug_mgr - > configs [ plug_mgr - > used_config_num ] = config ;
plug_mgr - > used_config_num + + ;
memset ( line_buffer , 0 , sizeof ( line_buffer ) ) ;
}
fclose ( fp ) ;
return 0 ;
err :
if ( fp )
{
fclose ( fp ) ;
fp = NULL ;
}
return - 1 ;
2022-07-27 15:51:07 +08:00
}
2022-07-27 18:32:22 +08:00
static int plugin_manager_open_plugins ( struct plugin_manager * plug_mgr )
2022-07-27 15:51:07 +08:00
{
2022-07-27 18:32:22 +08:00
for ( int i = 0 ; i < plug_mgr - > used_config_num ; i + + )
{
struct plugin_manager_config * config = plug_mgr - > configs [ i ] ;
struct plugin_manager_module * module = plugin_manager_module_open ( config ) ;
if ( module = = NULL )
{
return - 1 ;
}
2022-08-03 19:46:43 +08:00
plugin_manager_module_dump ( module , config ) ;
2022-07-27 18:32:22 +08:00
plug_mgr - > modules [ plug_mgr - > used_module_num ] = module ;
plug_mgr - > used_module_num + + ;
}
return 0 ;
}
static int plugin_manager_register_plugins ( struct plugin_manager * plug_mgr )
{
for ( int i = 0 ; i < plug_mgr - > used_module_num ; i + + )
{
struct plugin_manager_module * module = plug_mgr - > modules [ i ] ;
if ( plugin_manager_module_register ( plug_mgr , module ) = = - 1 )
{
return - 1 ;
}
plug_mgr - > used_evencb_num + + ;
}
return 0 ;
}
static int plugin_manager_init_plugins ( struct plugin_manager * plug_mgr )
{
for ( int i = 0 ; i < plug_mgr - > used_module_num ; i + + )
{
struct plugin_manager_module * module = plug_mgr - > modules [ i ] ;
if ( plugin_manager_module_init ( module ) = = - 1 )
{
return - 1 ;
}
double percentage = ( ( double ) ( i + 1 ) ) / ( ( double ) plug_mgr - > used_module_num ) * ( ( double ) 100 ) ;
2022-08-05 10:45:28 +08:00
plugin_manager_log ( INFO , " Plugin initialization progress: [%.2f%%] " , percentage ) ;
2022-07-27 18:32:22 +08:00
}
return 0 ;
}
static void plugin_manager_exit_plugins ( struct plugin_manager * plug_mgr )
{
if ( plug_mgr & & plug_mgr - > used_module_num )
{
for ( int i = 0 ; i < plug_mgr - > used_module_num ; i + + )
{
struct plugin_manager_module * module = plug_mgr - > modules [ i ] ;
plugin_manager_module_exit ( module ) ;
}
}
}
static void plugin_manager_close_plugins ( struct plugin_manager * plug_mgr )
{
if ( plug_mgr & & plug_mgr - > used_module_num )
{
for ( int i = 0 ; i < plug_mgr - > used_module_num ; i + + )
{
struct plugin_manager_module * module = plug_mgr - > modules [ i ] ;
plugin_manager_module_close ( module ) ;
}
plug_mgr - > used_module_num = 0 ;
}
}
// deparse for destory parse
static void plugin_manager_deparse_plugins ( struct plugin_manager * plug_mgr )
{
if ( plug_mgr & & plug_mgr - > used_config_num )
2022-07-27 15:51:07 +08:00
{
2022-07-27 18:32:22 +08:00
for ( int i = 0 ; i < plug_mgr - > used_config_num ; i + + )
{
struct plugin_manager_config * config = plug_mgr - > configs [ i ] ;
plugin_mangager_config_destory ( config ) ;
}
plug_mgr - > used_config_num = 0 ;
2022-07-27 15:51:07 +08:00
}
}
2022-07-27 18:32:22 +08:00
/******************************************************************************
* Public API for managing plugins
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-08-03 19:46:43 +08:00
int plugin_manager_load ( struct plugin_manager * plug_mgr , const char * file )
2022-07-24 23:59:00 +08:00
{
2022-08-03 19:46:43 +08:00
if ( plugin_manager_parse_plugins ( plug_mgr , file ) = = - 1 )
2022-07-27 18:32:22 +08:00
{
return - 1 ;
}
if ( plugin_manager_open_plugins ( plug_mgr ) = = - 1 )
{
return - 1 ;
}
if ( plugin_manager_register_plugins ( plug_mgr ) = = - 1 )
{
return - 1 ;
}
if ( plugin_manager_init_plugins ( plug_mgr ) = = - 1 )
{
return - 1 ;
}
2022-07-24 23:59:00 +08:00
return 0 ;
}
2022-07-27 15:51:07 +08:00
void plugin_manager_unload ( struct plugin_manager * plug_mgr )
{
2022-07-27 18:32:22 +08:00
plugin_manager_exit_plugins ( plug_mgr ) ;
plugin_manager_close_plugins ( plug_mgr ) ;
plugin_manager_deparse_plugins ( plug_mgr ) ;
2022-07-27 15:51:07 +08:00
}
2022-07-27 18:32:22 +08:00
struct plugin_manager * plugin_manager_create ( )
{
struct plugin_manager * plug_mgr = safe_alloc ( struct plugin_manager , 1 ) ;
plug_mgr - > used_module_num = 0 ;
plug_mgr - > used_config_num = 0 ;
plug_mgr - > used_evencb_num = 0 ;
plug_mgr - > evcb_htable = NULL ;
return plug_mgr ;
}
void plugin_manager_destory ( struct plugin_manager * plug_mgr )
2022-07-06 23:18:13 +08:00
{
2022-07-27 18:32:22 +08:00
if ( plug_mgr )
{
if ( plug_mgr - > evcb_htable )
{
struct plugin_manager_eventcb * elem ;
struct plugin_manager_eventcb * tmp ;
HASH_ITER ( hh , plug_mgr - > evcb_htable , elem , tmp )
{
HASH_DEL ( plug_mgr - > evcb_htable , elem ) ;
2022-08-03 19:46:43 +08:00
safe_free ( elem - > callbacks ) ;
2022-07-27 18:32:22 +08:00
safe_free ( elem ) ;
}
plug_mgr - > evcb_htable = NULL ;
plug_mgr - > used_evencb_num = 0 ;
}
plugin_manager_unload ( plug_mgr ) ;
safe_free ( plug_mgr ) ;
}
}
2022-08-03 19:46:43 +08:00
int plugin_manager_register ( struct plugin_manager * plug_mgr , const char * session_name , enum session_event_type event , fn_session_event_callback * event_cb , fn_session_error_callback * error_cb )
2022-07-27 18:32:22 +08:00
{
if ( strlen ( session_name ) < = 0 )
{
plugin_manager_log ( ERROR , " invalid parameter, session name is empty " ) ;
return - 1 ;
}
if ( strlen ( session_name ) > MAX_SESSION_NAME_LENGTH )
{
plugin_manager_log ( ERROR , " invalid parameter, session name '%s' is too long and exceeds '%d' bytes " , session_name , MAX_SESSION_NAME_LENGTH ) ;
return - 1 ;
}
2022-08-03 19:46:43 +08:00
if ( event_cb = = NULL )
2022-07-27 18:32:22 +08:00
{
2022-08-03 19:46:43 +08:00
plugin_manager_log ( ERROR , " invalid parameter, the event callback corresponding to the session name '%s' is null " , session_name ) ;
return - 1 ;
}
if ( error_cb = = NULL )
{
plugin_manager_log ( ERROR , " invalid parameter, the error callback corresponding to the session name '%s' is null " , session_name ) ;
2022-07-27 18:32:22 +08:00
return - 1 ;
}
struct plugin_manager_eventcb * elem ;
HASH_FIND_STR ( plug_mgr - > evcb_htable , session_name , elem ) ;
2022-08-03 19:46:43 +08:00
// session_name exists, add a new cb to the end of the callbacks dynamic array
2022-07-27 18:32:22 +08:00
if ( elem )
{
2022-08-03 19:46:43 +08:00
elem - > callbacks = ( struct callback_static * ) realloc ( elem - > callbacks , ( elem - > callback_num + 1 ) * sizeof ( struct callback_static ) ) ;
2022-07-27 18:32:22 +08:00
2022-08-03 19:46:43 +08:00
elem - > callbacks [ elem - > callback_num ] . event = event ;
elem - > callbacks [ elem - > callback_num ] . event_cb = event_cb ;
elem - > callbacks [ elem - > callback_num ] . error_cb = error_cb ;
2022-07-27 18:32:22 +08:00
2022-08-03 19:46:43 +08:00
elem - > callback_num + + ;
2022-07-27 18:32:22 +08:00
}
// session_name does not exist, allocate a new node elem, and add elem to the hash table
else
{
elem = safe_alloc ( struct plugin_manager_eventcb , 1 ) ;
memcpy ( elem - > session_name , session_name , strlen ( session_name ) ) ;
2022-08-03 19:46:43 +08:00
elem - > callbacks = ( struct callback_static * ) realloc ( elem - > callbacks , ( elem - > callback_num + 1 ) * sizeof ( struct callback_static ) ) ;
2022-07-27 18:32:22 +08:00
2022-08-03 19:46:43 +08:00
elem - > callbacks [ elem - > callback_num ] . event = event ;
elem - > callbacks [ elem - > callback_num ] . event_cb = event_cb ;
elem - > callbacks [ elem - > callback_num ] . error_cb = error_cb ;
2022-07-27 18:32:22 +08:00
2022-08-03 19:46:43 +08:00
elem - > callback_num + + ;
2022-07-27 18:32:22 +08:00
HASH_ADD_STR ( plug_mgr - > evcb_htable , session_name , elem ) ;
}
2022-07-20 20:20:31 +08:00
return 0 ;
}
2022-07-27 15:51:07 +08:00
void plugin_manager_dispatch ( struct plugin_manager * plug_mgr , struct stellar_event * event )
2022-07-20 20:20:31 +08:00
{
2022-07-27 18:32:22 +08:00
const struct stellar_session * seesion = stellar_event_get_session ( event ) ;
struct session_plugin_ctx * plug_ctx = stellar_event_get_plugin_ctx ( event ) ;
enum session_event_type event_type = stellar_event_get_type ( event ) ;
const char * session_name = stellar_event_get_session_name ( event ) ;
struct stellar_packet * packet = stellar_event_get_packet ( event ) ;
uint16_t payload_len = stellar_event_get_payload_length ( event ) ;
const char * payload = stellar_event_get_payload ( event ) ;
assert ( seesion ) ;
assert ( session_name ) ;
2022-08-03 19:46:43 +08:00
char event_str_buffer [ 1024 ] = { 0 } ;
session_event_type_int2str ( event_type , event_str_buffer , 1024 ) ;
2022-07-27 18:32:22 +08:00
// the same session may trigger multi times opening events
if ( event_type & SESSION_EVENT_OPENING )
{
if ( plug_ctx = = NULL )
{
plug_ctx = plugin_manager_create_plugin_ctx ( plug_mgr , session_name ) ;
if ( plug_ctx = = NULL )
{
2022-08-05 10:45:28 +08:00
plugin_manager_log ( ERROR , " can't create runtime plugin ctx for session '%s', Please check whether the callback is registered in the current session " , session_name ) ;
2022-07-27 18:32:22 +08:00
return ;
}
stellar_event_set_plugin_ctx ( event , plug_ctx ) ;
}
}
if ( plug_ctx )
{
2022-08-03 19:46:43 +08:00
for ( int i = 0 ; i < plug_ctx - > callback_num ; i + + )
2022-07-27 18:32:22 +08:00
{
2022-08-03 19:46:43 +08:00
struct callback_runtime * runtime = & plug_ctx - > callbacks [ i ] ;
if ( runtime - > skip = = 1 )
2022-07-27 18:32:22 +08:00
{
2022-08-03 19:46:43 +08:00
plugin_manager_log ( DEBUG , " dispatch, skip event_cb: %p, session: %s, event: (%d, %s) " , runtime - > event_cb , session_name , event_type , event_str_buffer ) ;
2022-07-27 18:32:22 +08:00
continue ;
}
if ( runtime - > event & event_type )
{
2022-08-03 19:46:43 +08:00
plug_ctx - > callback_index = i ;
plugin_manager_log ( DEBUG , " dispatch, run event_cb: %p, session: %s, event: (%d, %s) " , runtime - > event_cb , session_name , event_type , event_str_buffer ) ;
runtime - > event_cb ( seesion , event_type , packet , payload , payload_len , & runtime - > cb_args ) ;
2022-07-27 18:32:22 +08:00
}
}
}
else
{
plugin_manager_log ( ERROR , " session '%s' runtime plugin ctx is null when running event callback " , session_name ) ;
abort ( ) ;
}
if ( event_type & SESSION_EVENT_CLOSING )
{
plugin_manager_destory_plugin_ctx ( plug_ctx ) ;
stellar_event_set_plugin_ctx ( event , NULL ) ;
}
}
2022-08-03 19:46:43 +08:00
/******************************************************************************
* Public API For Plugin
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void pm_session_dettach_me ( const struct stellar_session * session )
{
struct session_plugin_ctx * plugin_ctx = stellar_session_get_plugin_ctx ( session ) ;
assert ( plugin_ctx ) ;
struct callback_runtime * runtime_me = & plugin_ctx - > callbacks [ plugin_ctx - > callback_index ] ;
/*
* Just set the skip flag and don ' t call this event callback next .
* The plugin is closed before calling pm_session_dettach_me .
*/
runtime_me - > skip = 1 ;
plugin_manager_log ( DEBUG , " %p dettach me, disable event_cb: %p, session: %s " , runtime_me - > event_cb , runtime_me - > event_cb , stellar_session_get_name ( session ) ) ;
}
void pm_session_dettach_others ( const struct stellar_session * session )
{
struct session_plugin_ctx * plugin_ctx = stellar_session_get_plugin_ctx ( session ) ;
assert ( plugin_ctx ) ;
struct callback_runtime * runtime_me = & plugin_ctx - > callbacks [ plugin_ctx - > callback_index ] ;
for ( int i = 0 ; i < plugin_ctx - > callback_num ; i + + )
{
if ( i ! = plugin_ctx - > callback_index )
{
struct callback_runtime * runtime_other = & plugin_ctx - > callbacks [ i ] ;
runtime_other - > skip = 1 ;
plugin_manager_log ( DEBUG , " %p dettach others, run error_cb: %p, session: %s " , runtime_me - > event_cb , runtime_other - > error_cb , stellar_session_get_name ( session ) ) ;
runtime_other - > error_cb ( session , ERROR_EVENT_DETTACH , & runtime_other - > cb_args ) ;
}
}
}
/******************************************************************************
* Util For Gtest
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void * pm_session_get_plugin_pme ( const struct stellar_session * session )
{
struct session_plugin_ctx * plugin_ctx = stellar_session_get_plugin_ctx ( session ) ;
assert ( plugin_ctx ) ;
struct callback_runtime * runtime_me = & plugin_ctx - > callbacks [ plugin_ctx - > callback_index ] ;
return runtime_me - > cb_args ;
}
2022-07-27 18:32:22 +08:00
/******************************************************************************
* Suppport LUA plugins
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// TODO