From afe428938de4a3d4f10283147897e14d45b8c5d2 Mon Sep 17 00:00:00 2001 From: niubinghui Date: Fri, 16 Aug 2024 16:16:16 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E3=80=91example?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/Makefile | 8 +- example/conf/lua_plugin_manage.toml | 10 + example/conf/plugin_manage.toml | 4 + example/example_plugin-2.lua | 30 --- example/example_plugin_manage.c | 95 ++++++++++ example/include/plugin_manager.h | 22 +++ example/include/plugin_manager_gtest_mock.h | 103 ++++++++++ example/include/plugin_manager_interna.h | 199 ++++++++++++++++++++ example/include/stellar_internal.h | 27 +++ example/{ => plugin}/example_plugin-1.lua | 10 +- example/plugin/example_plugin-2.lua | 38 ++++ example/plugin/simple_stellar_plugin.so | Bin 0 -> 43312 bytes 12 files changed, 507 insertions(+), 39 deletions(-) create mode 100644 example/conf/lua_plugin_manage.toml create mode 100644 example/conf/plugin_manage.toml delete mode 100644 example/example_plugin-2.lua create mode 100644 example/example_plugin_manage.c create mode 100644 example/include/plugin_manager.h create mode 100644 example/include/plugin_manager_gtest_mock.h create mode 100644 example/include/plugin_manager_interna.h create mode 100644 example/include/stellar_internal.h rename example/{ => plugin}/example_plugin-1.lua (73%) create mode 100644 example/plugin/example_plugin-2.lua create mode 100755 example/plugin/simple_stellar_plugin.so diff --git a/example/Makefile b/example/Makefile index 47a4b3d..2582e10 100644 --- a/example/Makefile +++ b/example/Makefile @@ -5,15 +5,15 @@ TARGET=example EXAMPLE_FLAG = -DLUAPLUGIN_EXAMPLE -SRC := example.c +SRC := example_plugin_manage.c -OBJECTS := example.o +OBJECTS := example_plugin_manage.o -INCLUDE = -I$(TOPDIR)/output/include -I$(TOPDIR)/dependence/include +INCLUDE = -I$(TOPDIR)/output/include -I$(TOPDIR)/dependence/include -I$(TOPDIR)/example/include CFLAGS = -g -Wextra -Wall -O0 -fPIC # CFLAGS += -pedantic -fsanitize=address # LDLIBS = -L$(TOPDIR)/output/lib -llua -ldl -lm -LDLIBS += -L$(TOPDIR)/output/libs -lluaplugin -L$(TOPDIR)/dependence/lib -ltoml +LDLIBS += -L$(TOPDIR)/output/libs -lluaplugin -L$(TOPDIR)/dependence/lib -ltoml -lbitmap -lplugin_manager all:$(OBJECTS) $(CC) $(CFLAGS) -o $(TARGET) $(OBJECTS) $(LDLIBS) diff --git a/example/conf/lua_plugin_manage.toml b/example/conf/lua_plugin_manage.toml new file mode 100644 index 0000000..4e58824 --- /dev/null +++ b/example/conf/lua_plugin_manage.toml @@ -0,0 +1,10 @@ +# config.toml +[[plugin]] +path = "./plugin/example_plugin-1.lua" +init = "plugin_load" +exit = "plugin_unload" + +[[plugin]] +path = "./plugin/example_plugin-2.lua" +init = "plugin_load" +exit = "plugin_unload" \ No newline at end of file diff --git a/example/conf/plugin_manage.toml b/example/conf/plugin_manage.toml new file mode 100644 index 0000000..bd1fb72 --- /dev/null +++ b/example/conf/plugin_manage.toml @@ -0,0 +1,4 @@ +[[plugin]] +path = "./plugin/simple_stellar_plugin.so" +init = "simple_plugin_sub_session_stat_init" +exit = "simple_plugin_sub_session_stat_exit" \ No newline at end of file diff --git a/example/example_plugin-2.lua b/example/example_plugin-2.lua deleted file mode 100644 index 94e0578..0000000 --- a/example/example_plugin-2.lua +++ /dev/null @@ -1,30 +0,0 @@ -function plugin_ctx_new(sess, plug_env, sess_context) - print("now begin to create new ctx context example-2") - print(plug_env.data) - local sessid = session.getid(sess) - sess_context.id = 200 - print("session id is ", sessid) - session.setid(sess, 50000) -end - -function plugin_ctx_free(sess, sess_context, plug_env) - print(sess_context.id) - print("now begin to free ctx context example-2") -end - -function plugin_load(stellar, plug_env) - print("now begin to load plugin example-2") - plug_env.data = "my example-2 plugin env" - plug_env.newid = 2000 - id = plugin_manage.register(stellar, plugin_ctx_new, plugin_ctx_free, plug_env) - print(id) - plug_env.messid = 200 -end - -function plugin_unload(plug_env) - print("now running unload plugin example-2 function") - print(plug_env.penv_pointer) - print(plug_env.data) - print(plug_env.newid) - print(plug_env.messid) -end \ No newline at end of file diff --git a/example/example_plugin_manage.c b/example/example_plugin_manage.c new file mode 100644 index 0000000..3e8667e --- /dev/null +++ b/example/example_plugin_manage.c @@ -0,0 +1,95 @@ +#include "plugin_manager_gtest_mock.h" +#include "lua_plugin_manage.h" + +#include +#include +#include +#include +#include +#include + +#define PLUGIN_CONFIG_PATH "./conf/plugin_manage.toml" +#define LUA_CONFIG_PATH "./conf/lua_plugin_manage.toml" + +static struct lua_config_specific *config_load(const char *config_file_name, int *specific_num); +static void debug_plugin_manage_schema(struct plugin_manager_schema *schema); + +int main() +{ + struct stellar st; + memset(&st, 0, sizeof(st)); + + int num = 0; + struct lua_config_specific *specific = config_load(LUA_CONFIG_PATH, &num); + struct plugin_manager_schema *plug_mgr = plugin_manager_init(&st, PLUGIN_CONFIG_PATH); + struct lua_plugin_manage_schema *lua_schema = lua_plugin_manage_init(&st, num, specific); + st.lua_plug_mgr = lua_schema; + debug_plugin_manage_schema(plug_mgr); + + lua_plugin_manage_exit(lua_schema); + return 0; +} + +static struct lua_config_specific *config_load(const char *config_file_name, int *specific_count) +{ + if (__glibc_unlikely(!config_file_name)) + return NULL; + int specific_num = 0; + char errbuff[256] = {0}; + + if (access(config_file_name, F_OK)) + return NULL; + FILE *fp = fopen(config_file_name, "r"); + if (!fp) + return NULL; + toml_table_t *conf = toml_parse_file(fp, errbuff, sizeof(errbuff)); + if (fp) + fclose(fp); + if (!conf) + { + printf("parse config file failed, filename %s, err %s\n", config_file_name, errbuff); + return NULL; + } + + toml_array_t *plugin_array = toml_array_in(conf, "plugin"); + if (!plugin_array) + return NULL; + + specific_num = toml_array_nelem(plugin_array); + struct lua_config_specific *new_spec = (struct lua_config_specific *)calloc(specific_num, sizeof(struct lua_config_specific)); + if (!new_spec) + return NULL; + struct lua_config_specific *specific = NULL; + + for (int i = 0; i < specific_num; ++i) + { + toml_table_t *plugin = toml_table_at(plugin_array, i); + const char *raw_filepath = toml_raw_in(plugin, "path"); + const char *raw_load_func_name = toml_raw_in(plugin, "init"); + const char *raw_unload_func_name = toml_raw_in(plugin, "exit"); + specific = &new_spec[i]; + + if (toml_rtos(raw_filepath, &specific->config_specific_file) || + toml_rtos(raw_load_func_name, &specific->config_specific_load_func) || + toml_rtos(raw_unload_func_name, &specific->config_specific_unload_func)) + { + toml_free(conf); + free(specific); + return NULL; + } + } + *specific_count = specific_num; + + return new_spec; +} + +static void debug_plugin_manage_schema(struct plugin_manager_schema *schema) +{ + struct registered_session_plugin_schema * plugin = NULL; + for (int i = 0; i < (int)utarray_len(schema->registered_session_plugin_array); ++i) { + plugin = (struct registered_session_plugin_schema *)utarray_eltptr(schema->registered_session_plugin_array, (unsigned int)i); + printf("plugin[%d]: new func %p, free func %p, env %p\n", i, plugin->on_ctx_new, plugin->on_ctx_free, plugin->plugin_env); + } + return; +} + diff --git a/example/include/plugin_manager.h b/example/include/plugin_manager.h new file mode 100644 index 0000000..cf07167 --- /dev/null +++ b/example/include/plugin_manager.h @@ -0,0 +1,22 @@ +#pragma once + +#include "stellar/stellar.h" + +struct plugin_manager_schema; +struct plugin_manager_runtime; + +struct plugin_manager_schema *plugin_manager_init(struct stellar *st, const char *plugin_spec_file_path); +void plugin_manager_exit(struct plugin_manager_schema *plug_mgr); + +void plugin_manager_on_packet_ingress(struct plugin_manager_schema *plug_mgr, struct packet *pkt); +void plugin_manager_on_packet_egress(struct plugin_manager_schema *plug_mgr, struct packet *pkt); +//return polling work state, 0: idle, 1: working +int plugin_manager_on_polling(struct plugin_manager_schema *plug_mgr); + +//publish and dispatch session msg(msg, pkt) on session_mq +void plugin_manager_on_session_ingress(struct session *sess,struct packet *pkt); +void plugin_manager_on_session_egress(struct session *sess,struct packet *pkt); +void plugin_manager_on_session_closing(struct session *sess); + +struct plugin_manager_runtime *plugin_manager_session_runtime_new(struct plugin_manager_schema *plug_mgr, struct session *sess); +void plugin_manager_session_runtime_free(struct plugin_manager_runtime *plug_mgr_rt); diff --git a/example/include/plugin_manager_gtest_mock.h b/example/include/plugin_manager_gtest_mock.h new file mode 100644 index 0000000..7580499 --- /dev/null +++ b/example/include/plugin_manager_gtest_mock.h @@ -0,0 +1,103 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "plugin_manager_interna.h" +#include "stellar_internal.h" +#include "stellar/session.h" +#include "lua_plugin_manage.h" + + +//mock stellar +struct stellar +{ + struct plugin_manager_schema *plug_mgr; + struct lua_plugin_manage_schema * lua_plug_mgr; +}; + +struct packet +{ + struct stellar *st; + enum packet_type type; + unsigned char ip_proto; +}; + +struct session +{ + struct plugin_manager_runtime *plug_mgr_rt; + enum session_type type; + enum session_state state; + int sess_pkt_cnt; +}; +enum session_state session_get_current_state(struct session *sess) +{ + return sess->state; +} + +enum session_type session_get_type(struct session *sess) +{ + return sess->type; +} + + + +int session_get_current_plugin_id(struct session *sess) +{ + return sess->plug_mgr_rt->current_session_plugin_id; +} + +struct plugin_manager_schema * stellar_plugin_manager_schema_get(struct stellar *st) +{ + return st->plug_mgr; +} + +int stellar_plugin_manager_schema_set(struct stellar *st, struct plugin_manager_schema *pm) +{ + st->plug_mgr=pm; + return 0; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +int session_get_current_thread_id(struct session *sess) +{ + return 0; +} + +int stellar_get_worker_thread_num(struct stellar *st) +{ + return 16; +} + +int stellar_get_current_thread_id(struct stellar *st) +{ + return 0; +} +#pragma GCC diagnostic pop + +struct stellar * packet_stellar_get(struct packet *pkt) +{ + return pkt->st; +} + +struct plugin_manager_runtime * session_plugin_manager_runtime_get(struct session *sess) +{ + return sess->plug_mgr_rt; +} + +unsigned char packet_get_ip_protocol(struct packet *pkt) +{ + return pkt->ip_proto; +} + + +enum packet_type packet_get_type(const struct packet *pkt) +{ + return pkt->type; +} + + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/example/include/plugin_manager_interna.h b/example/include/plugin_manager_interna.h new file mode 100644 index 0000000..e579e03 --- /dev/null +++ b/example/include/plugin_manager_interna.h @@ -0,0 +1,199 @@ +#include "plugin_manager.h" + +#include "stellar/stellar.h" + +#include "stellar/session_exdata.h" +#include "stellar/session_mq.h" + + +#include "stellar/packet_exdata.h" +#include "stellar/packet_mq.h" + + +#include "bitmap.h" +#include "utarray.h" + +struct per_thread_exdata_array +{ + struct stellar_exdata *exdata_array; +}; + +struct stellar_message; + +struct plugin_manger_per_thread_data +{ + struct per_thread_exdata_array per_thread_pkt_exdata_array; + struct stellar_message *priority_mq[SESSION_MQ_PRIORITY_MAX];// message list + struct stellar_message *dealth_letter_queue;// dlq list + long long pub_packet_msg_cnt; +}; + + + +struct plugin_manager_schema +{ + struct stellar *st; + UT_array *plugin_load_specs_array; + UT_array *packet_exdata_schema_array; + UT_array *session_exdata_schema_array; + UT_array *stellar_mq_schema_array; + UT_array *registered_session_plugin_array; + UT_array *registered_packet_plugin_array; + UT_array *registered_polling_plugin_array; + int packet_mq_topic_num; + int session_mq_topic_num; + int packet_topic_subscriber_num; + int session_topic_subscriber_num; + int tcp_topic_id; + int tcp_stream_topic_id; + int udp_topic_id; + int egress_topic_id; + int control_packet_topic_id; + int max_message_dispatch; + struct plugin_manger_per_thread_data *per_thread_data; +}__attribute__((aligned(sizeof(void*)))); + +enum plugin_exdata_state +{ INIT, ACTIVE, EXIT }; + +struct stellar_exdata +{ + void *exdata; + enum plugin_exdata_state state; +}; + + + +struct stellar_exdata_schema +{ + char *name; + union + { + void *free_func; + session_exdata_free *sess_free_func; + packet_exdata_free *pkt_free_func; + }; + + void *free_arg; + int idx; +}__attribute__((aligned(sizeof(void*)))); + + +enum stellar_topic_type +{ + ON_SESSION_TOPIC, + ON_PACKET_TOPIC, +}; + +struct stellar_message +{ + struct + { + int topic_id; + enum stellar_topic_type type; + enum session_mq_priority priority; + } header; + void *body; + struct stellar_message *next, *prev; +} __attribute__((aligned(sizeof(void *)))); + +typedef struct stellar_mq_subscriber +{ + int topic_subscriber_idx; + int plugin_idx; + union + { + on_session_msg_cb_func *sess_msg_cb; + on_packet_msg_cb_func *pkt_msg_cb; + void *msg_cb; + }; + struct stellar_mq_subscriber *next, *prev; +}stellar_mq_subscriber __attribute__((aligned(sizeof(void*)))); + + +struct stellar_mq_topic_schema +{ + char *topic_name; + void *free_cb_arg; + int topic_id; + int subscriber_cnt; + int is_destroyed; + union + { + void *free_cb; + session_msg_free_cb_func *sess_msg_free_cb; + packet_msg_free_cb_func *pkt_msg_free_cb; + }; + struct stellar_mq_subscriber *subscribers; +}__attribute__((aligned(sizeof(void*)))); + + + +struct session_plugin_ctx_runtime +{ + enum plugin_exdata_state state; + int session_plugin_id; + void *plugin_ctx; +}__attribute__((aligned(sizeof(void*)))); + + + +struct plugin_manager_runtime +{ + struct plugin_manager_schema *plug_mgr; + struct session *sess; + struct bitmap *session_mq_status; //N * M bits, N topic, M subscriber + struct bitmap *session_topic_status; //N bits, N topic + struct stellar_exdata *sess_exdata_array; + struct session_plugin_ctx_runtime *plugin_ctx_array;//N plugins TODO: call alloc and free + int current_session_plugin_id; + int pub_session_msg_cnt; +}__attribute__((aligned(sizeof(void*)))); + +struct registered_packet_plugin_schema +{ + char ip_protocol; + plugin_on_packet_func *on_packet; + void *plugin_env; + UT_array *registed_packet_mq_subscriber_info; +}__attribute__((aligned(sizeof(void*)))); + +struct registered_polling_plugin_schema +{ + plugin_on_polling_func *on_polling; + void *plugin_env; +}__attribute__((aligned(sizeof(void*)))); + +struct stellar_mq_subscriber_info +{ + int topic_id; + int subscriber_idx; +}__attribute__((aligned(sizeof(void*)))); + +struct registered_session_plugin_schema +{ + session_ctx_new_func *on_ctx_new; + session_ctx_free_func *on_ctx_free; + void *plugin_env; + UT_array *registed_session_mq_subscriber_info; +}__attribute__((aligned(sizeof(void*)))); + +#define SESSION_PULGIN_ID_BASE 0x00000 +#define PACKET_PULGIN_ID_BASE 0x10000 +#define POLLING_PULGIN_ID_BASE 0x20000 + +/******************************* + * PLUGIN MANAGER INIT & EXIT * + *******************************/ + +#define MAX_MSG_PER_DISPATCH 128 + +#include + +struct plugin_specific +{ + char plugin_name[256]; + plugin_on_load_func *load_cb; + plugin_on_unload_func *unload_cb; + void *plugin_ctx; +}__attribute__((aligned(sizeof(void*)))); \ No newline at end of file diff --git a/example/include/stellar_internal.h b/example/include/stellar_internal.h new file mode 100644 index 0000000..e42dfed --- /dev/null +++ b/example/include/stellar_internal.h @@ -0,0 +1,27 @@ +#pragma once + +#include "stellar/stellar.h" + +struct plugin_manager_schema; +struct plugin_manager_runtime; + + +int stellar_plugin_manager_schema_set(struct stellar *st, struct plugin_manager_schema *pm); +struct plugin_manager_schema * stellar_plugin_manager_schema_get(struct stellar *st); +struct plugin_manager_runtime * session_plugin_manager_runtime_get(struct session *sess); + + +enum packet_type +{ + UNKNOWN, + IPv4, + IPv6, + UDP, + TCP, + TCP_STREAM, + CONTROL, +}; + +enum packet_type packet_get_type(const struct packet *pkt); + +struct stellar * packet_stellar_get(struct packet *pkt); \ No newline at end of file diff --git a/example/example_plugin-1.lua b/example/plugin/example_plugin-1.lua similarity index 73% rename from example/example_plugin-1.lua rename to example/plugin/example_plugin-1.lua index 52b0500..b185921 100644 --- a/example/example_plugin-1.lua +++ b/example/plugin/example_plugin-1.lua @@ -13,14 +13,14 @@ function plugin_load(stellar, plug_env) print("now begin to load plugin example-1") plug_env.data = "my example-1 plugin env" plug_env.newid = 1000 - plugin_manage.register(stellar, plugin_ctx_new, plugin_ctx_free, plug_env) + plug_env.id = plugin_manage.register(stellar, plugin_ctx_new, plugin_ctx_free, plug_env) plug_env.messid = 100 end function plugin_unload(plug_env) print("now running unload plugin example-1 function") - print(plug_env.__penv_pointer) - print(plug_env.data) - print(plug_env.newid) - print(plug_env.messid) + -- print(plug_env.__penv_pointer) + -- print(plug_env.data) + -- print(plug_env.newid) + -- print(plug_env.messid) end \ No newline at end of file diff --git a/example/plugin/example_plugin-2.lua b/example/plugin/example_plugin-2.lua new file mode 100644 index 0000000..faffe5b --- /dev/null +++ b/example/plugin/example_plugin-2.lua @@ -0,0 +1,38 @@ +function plugin_ctx_new(sess, plug_env, sess_context) + print("now create new ctx example-2, plugin id ", plug_env.id) + local sessid = session.getid(sess) + sess_context.id = 200 + print("session id is ", sessid) + session.setid(sess, 50000) +end + +function plugin_ctx_free(sess, sess_context, plug_env) + print(sess_context.id) + print("now begin to free ctx context example-2") +end + +function free_message() + print("free message") +end + +function plugin_load(stellar, plug_env) + print("now begin to load plugin example-2") + plug_env.id = plugin_manage.register(stellar, plugin_ctx_new, plugin_ctx_free, plug_env) + topic_id = message.gettopicid(stellar, "TOPIC_SESSION_STAT") + print("get topic id is ", topic_id) + create_id = message.gettopicid(stellar, "TOPIC_LUA_SESSION_TEST") + if (create_id < 0) + then + print("no topic, create new one") + create_table = {} + create_id = message.createtopic(stellar, "TOPIC_LUA_SESSION_TEST", free_message, create_table) + print("create topic is ", create_id) + else + print("has created, id is ", create_id) + end +end + +function plugin_unload(plug_env) + print("now running unload plugin example-2 function, plugin id is ", plug_env.id) + +end \ No newline at end of file diff --git a/example/plugin/simple_stellar_plugin.so b/example/plugin/simple_stellar_plugin.so new file mode 100755 index 0000000000000000000000000000000000000000..a374a8282620c026ab53b2ae8f0b01ff98695f9e GIT binary patch literal 43312 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 A?*IS* literal 0 HcmV?d00001