2024-01-09 18:03:24 +08:00
|
|
|
#include <unistd.h>
|
2024-06-25 10:32:51 +08:00
|
|
|
#include <pthread.h>
|
2024-01-30 18:07:08 +08:00
|
|
|
#include <sys/prctl.h>
|
2024-01-09 18:03:24 +08:00
|
|
|
|
2024-10-23 10:01:20 +08:00
|
|
|
#include "stellar/stellar.h"
|
2024-11-05 09:39:10 +08:00
|
|
|
#include "stellar/module.h"
|
2024-10-23 10:01:20 +08:00
|
|
|
|
2024-08-23 18:44:17 +08:00
|
|
|
#include "packet_io.h"
|
2024-10-23 10:01:20 +08:00
|
|
|
#include "log_internal.h"
|
|
|
|
|
#include "utils_internal.h"
|
2024-10-23 10:10:20 +08:00
|
|
|
#include "packet_internal.h"
|
2024-10-25 13:19:58 +08:00
|
|
|
#include "packet_manager.h"
|
2024-01-30 18:07:08 +08:00
|
|
|
|
2024-08-23 18:44:17 +08:00
|
|
|
#define CORE_LOG_FATAL(format, ...) STELLAR_LOG_FATAL(__thread_local_logger, "core", format, ##__VA_ARGS__)
|
|
|
|
|
#define CORE_LOG_ERROR(format, ...) STELLAR_LOG_ERROR(__thread_local_logger, "core", format, ##__VA_ARGS__)
|
|
|
|
|
#define CORE_LOG_DEBUG(format, ...) STELLAR_LOG_DEBUG(__thread_local_logger, "core", format, ##__VA_ARGS__)
|
2024-06-25 10:32:51 +08:00
|
|
|
|
2024-08-16 10:43:00 +08:00
|
|
|
#ifdef STELLAR_GIT_VERSION
|
|
|
|
|
static __attribute__((__used__)) const char *version = STELLAR_GIT_VERSION;
|
|
|
|
|
#else
|
|
|
|
|
static __attribute__((__used__)) const char *version = "Unknown";
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-10-23 10:01:20 +08:00
|
|
|
struct thread
|
2024-05-28 10:26:29 +08:00
|
|
|
{
|
|
|
|
|
pthread_t tid;
|
|
|
|
|
uint16_t idx;
|
|
|
|
|
uint64_t is_runing;
|
2024-08-19 17:28:45 +08:00
|
|
|
struct stellar *st;
|
2024-05-28 10:26:29 +08:00
|
|
|
};
|
|
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
struct stellar
|
2024-05-28 10:26:29 +08:00
|
|
|
{
|
2024-09-20 18:41:07 +08:00
|
|
|
uint16_t thread_num;
|
2024-05-28 10:26:29 +08:00
|
|
|
uint64_t need_exit;
|
2024-08-23 18:44:17 +08:00
|
|
|
struct logger *logger;
|
2024-09-20 18:41:07 +08:00
|
|
|
struct packet_io *pkt_io;
|
2024-11-05 09:39:10 +08:00
|
|
|
struct module_manager *mod_mgr;
|
2024-10-23 10:01:20 +08:00
|
|
|
struct thread threads[MAX_THREAD_NUM];
|
2024-09-02 16:03:08 +08:00
|
|
|
};
|
2024-09-02 15:04:55 +08:00
|
|
|
|
2024-08-29 18:31:09 +08:00
|
|
|
static void *worker_thread(void *arg)
|
2024-01-09 18:03:24 +08:00
|
|
|
{
|
2024-10-23 10:01:20 +08:00
|
|
|
int nr_recv = 0;
|
2024-09-20 18:41:07 +08:00
|
|
|
char thread_name[16] = {0};
|
2024-04-18 14:20:28 +08:00
|
|
|
struct packet *pkt = NULL;
|
2024-10-23 10:01:20 +08:00
|
|
|
struct packet *pkts[RX_BURST_MAX] = {NULL};
|
|
|
|
|
struct thread *thread = (struct thread *)arg;
|
2024-09-20 18:41:07 +08:00
|
|
|
uint16_t thread_id = thread->idx;
|
2024-08-19 17:28:45 +08:00
|
|
|
struct stellar *st = thread->st;
|
2024-09-20 18:41:07 +08:00
|
|
|
struct packet_io *pkt_io = st->pkt_io;
|
2024-11-05 09:39:10 +08:00
|
|
|
struct module_manager *mod_mgr = st->mod_mgr;
|
2024-11-05 16:14:02 +08:00
|
|
|
struct module *pkt_mgr_mod = module_manager_get_module(mod_mgr, PACKET_MANAGER_MODULE_NAME);
|
2024-11-05 09:39:10 +08:00
|
|
|
struct packet_manager *pkt_mgr = module_to_packet_manager(pkt_mgr_mod);
|
2024-09-14 12:18:26 +08:00
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
snprintf(thread_name, sizeof(thread_name), "stellar:%d", thread_id);
|
|
|
|
|
prctl(PR_SET_NAME, (unsigned long long)thread_name, NULL, NULL, NULL);
|
2024-08-23 15:21:07 +08:00
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
__thread_local_logger = st->logger;
|
2024-11-26 14:44:44 +08:00
|
|
|
module_manager_register_thread(mod_mgr, thread_id);
|
2024-04-18 14:20:28 +08:00
|
|
|
|
|
|
|
|
ATOMIC_SET(&thread->is_runing, 1);
|
2024-09-20 18:41:07 +08:00
|
|
|
CORE_LOG_FATAL("worker thread %d runing", thread_id);
|
2024-01-09 18:03:24 +08:00
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
while (ATOMIC_READ(&st->need_exit) == 0)
|
2024-01-09 18:03:24 +08:00
|
|
|
{
|
2024-10-23 10:01:20 +08:00
|
|
|
nr_recv = packet_io_recv(pkt_io, thread_id, pkts, RX_BURST_MAX);
|
|
|
|
|
for (int i = 0; i < nr_recv; i++)
|
2024-01-10 10:19:47 +08:00
|
|
|
{
|
2024-10-23 10:01:20 +08:00
|
|
|
packet_manager_ingress(pkt_mgr, thread_id, pkts[i]);
|
2024-01-10 10:19:47 +08:00
|
|
|
}
|
2024-01-09 18:03:24 +08:00
|
|
|
|
2024-10-23 10:01:20 +08:00
|
|
|
packet_manager_dispatch(pkt_mgr, thread_id);
|
|
|
|
|
while ((pkt = packet_manager_egress(pkt_mgr, thread_id)))
|
2024-02-28 16:30:03 +08:00
|
|
|
{
|
2024-11-21 11:39:34 +08:00
|
|
|
packet_io_send(pkt_io, thread_id, &pkt, 1);
|
2024-03-09 19:28:14 +08:00
|
|
|
}
|
2024-10-31 18:26:21 +08:00
|
|
|
packet_io_clean(pkt_io, thread_id);
|
2024-02-28 16:30:03 +08:00
|
|
|
|
2024-11-25 19:23:01 +08:00
|
|
|
module_manager_polling_dispatch(mod_mgr);
|
2024-10-31 18:26:21 +08:00
|
|
|
|
2024-10-23 10:01:20 +08:00
|
|
|
if (nr_recv == 0)
|
2024-04-18 14:20:28 +08:00
|
|
|
{
|
2024-09-20 18:41:07 +08:00
|
|
|
packet_io_yield(pkt_io, thread_id);
|
2024-08-27 16:19:20 +08:00
|
|
|
}
|
|
|
|
|
}
|
2024-10-23 10:01:20 +08:00
|
|
|
|
2024-11-18 18:33:19 +08:00
|
|
|
CORE_LOG_FATAL("worker thread %d cleaning", thread_id);
|
|
|
|
|
|
2024-11-05 09:39:10 +08:00
|
|
|
module_manager_unregister_thread(mod_mgr, thread_id);
|
2024-09-14 12:18:26 +08:00
|
|
|
|
2024-04-18 14:20:28 +08:00
|
|
|
ATOMIC_SET(&thread->is_runing, 0);
|
2024-09-20 18:41:07 +08:00
|
|
|
CORE_LOG_FATAL("worker thread %d exit", thread_id);
|
2024-01-09 18:03:24 +08:00
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2023-12-08 11:16:23 +08:00
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
static int stellar_thread_run(struct stellar *st)
|
2024-01-29 14:15:33 +08:00
|
|
|
{
|
2024-10-23 10:01:20 +08:00
|
|
|
for (uint64_t i = 0; i < st->thread_num; i++)
|
2024-01-29 14:15:33 +08:00
|
|
|
{
|
2024-10-23 10:01:20 +08:00
|
|
|
struct thread *thread = &st->threads[i];
|
2024-04-18 14:20:28 +08:00
|
|
|
thread->idx = i;
|
|
|
|
|
thread->is_runing = 0;
|
2024-09-02 16:53:02 +08:00
|
|
|
thread->st = st;
|
2024-08-29 18:31:09 +08:00
|
|
|
if (pthread_create(&thread->tid, NULL, worker_thread, (void *)thread) < 0)
|
2024-01-29 14:15:33 +08:00
|
|
|
{
|
2024-08-23 18:44:17 +08:00
|
|
|
CORE_LOG_ERROR("unable to create worker thread, error %d: %s", errno, strerror(errno));
|
2024-01-29 14:15:33 +08:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-19 17:28:45 +08:00
|
|
|
static void stellar_thread_join(struct stellar *st)
|
2024-01-29 14:15:33 +08:00
|
|
|
{
|
2024-10-23 10:01:20 +08:00
|
|
|
for (uint64_t i = 0; i < st->thread_num; i++)
|
2024-01-29 14:15:33 +08:00
|
|
|
{
|
2024-09-20 18:41:07 +08:00
|
|
|
if (st->threads[i].is_runing == 0)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2024-09-02 16:53:02 +08:00
|
|
|
|
2024-10-23 10:01:20 +08:00
|
|
|
struct thread *thread = &st->threads[i];
|
2024-09-20 18:41:07 +08:00
|
|
|
pthread_join(thread->tid, NULL);
|
2024-01-29 14:15:33 +08:00
|
|
|
}
|
|
|
|
|
}
|
2024-05-28 10:26:29 +08:00
|
|
|
|
2024-11-26 14:37:05 +08:00
|
|
|
#include "stellar/monitor.h"
|
|
|
|
|
#include "stellar/session.h"
|
2024-11-26 18:59:55 +08:00
|
|
|
#include "stellar/lpi_plus.h"
|
2024-11-26 14:37:05 +08:00
|
|
|
|
|
|
|
|
struct module_hooks mod_hooks[] = {
|
2024-11-27 16:53:15 +08:00
|
|
|
{monitor_on_init, monitor_on_exit, NULL, NULL},
|
|
|
|
|
{packet_manager_on_init, packet_manager_on_exit, packet_manager_on_thread_init, packet_manager_on_thread_exit},
|
|
|
|
|
{session_manager_on_init, session_manager_on_exit, session_manager_on_thread_init, session_manager_on_thread_exit},
|
|
|
|
|
{session_debugger_on_init, session_debugger_on_exit, NULL, NULL},
|
|
|
|
|
{session_monitor_on_init, session_monitor_on_exit, NULL, NULL},
|
|
|
|
|
{lpi_plus_init, lpi_plus_exit, NULL, NULL},
|
|
|
|
|
};
|
2024-11-26 14:37:05 +08:00
|
|
|
|
|
|
|
|
struct packet_node_spec
|
|
|
|
|
{
|
|
|
|
|
const char *module_name;
|
|
|
|
|
const char *node_name;
|
|
|
|
|
enum packet_stage stage;
|
|
|
|
|
uint64_t interested_tag_key_bits;
|
|
|
|
|
uint64_t interested_tag_val_bits;
|
|
|
|
|
on_packet_callback *cb;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct packet_node_spec packet_nodes[] = {
|
2024-11-27 16:53:15 +08:00
|
|
|
// PACKET_STAGE_FORWARD
|
|
|
|
|
{SESSION_MANAGER_MODULE_NAME, "session_manager", PACKET_STAGE_FORWARD, PKT_TAG_KEY_IPPROTO, PKT_TAG_VAL_IPPROTO_TCP | PKT_TAG_VAL_IPPROTO_UDP, session_manager_on_packet_forward},
|
|
|
|
|
{SESSION_DEBUGGER_MODULE_NAME, "session_debugger", PACKET_STAGE_FORWARD, PKT_TAG_KEY_SESS, PKT_TAG_VAL_SESS_ALL, session_debugger_on_packet_forward},
|
|
|
|
|
{LPI_PLUS_MODULE_NAME, "lpi_plus", PACKET_STAGE_FORWARD, PKT_TAG_KEY_IPPROTO, PKT_TAG_VAL_IPPROTO_TCP | PKT_TAG_VAL_IPPROTO_UDP, lpi_plus_on_packet},
|
|
|
|
|
// PACKET_STAGE_OUTPUT
|
|
|
|
|
{SESSION_MANAGER_MODULE_NAME, "session_manager", PACKET_STAGE_OUTPUT, PKT_TAG_KEY_IPPROTO, PKT_TAG_VAL_IPPROTO_TCP | PKT_TAG_VAL_IPPROTO_UDP, session_manager_on_packet_output},
|
2024-11-26 14:37:05 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2024-11-27 14:30:10 +08:00
|
|
|
static int register_packet_node_for_module(struct module_manager *mod_mgr, struct packet_node_spec *specs, size_t n_specs)
|
2024-11-26 14:37:05 +08:00
|
|
|
{
|
|
|
|
|
struct module *pkt_mgr_mod = module_manager_get_module(mod_mgr, PACKET_MANAGER_MODULE_NAME);
|
2024-11-27 16:53:15 +08:00
|
|
|
struct packet_manager *pkt_mgr = module_to_packet_manager(pkt_mgr_mod);
|
2024-11-26 14:37:05 +08:00
|
|
|
|
|
|
|
|
struct module *mod = NULL;
|
|
|
|
|
|
2024-11-27 16:53:15 +08:00
|
|
|
for (size_t i = 0; i < n_specs; i++)
|
2024-11-26 14:37:05 +08:00
|
|
|
{
|
2024-11-27 16:53:15 +08:00
|
|
|
mod = module_manager_get_module(mod_mgr, specs[i].module_name);
|
|
|
|
|
if (mod == NULL)
|
2024-11-26 14:37:05 +08:00
|
|
|
{
|
2024-11-27 14:46:53 +08:00
|
|
|
CORE_LOG_FATAL("%s unable to get module %s", __FUNCTION__, specs[i].module_name);
|
|
|
|
|
continue;
|
2024-11-26 14:37:05 +08:00
|
|
|
}
|
2024-11-27 16:53:15 +08:00
|
|
|
if (packet_manager_register_node(pkt_mgr,
|
|
|
|
|
specs[i].node_name,
|
|
|
|
|
specs[i].stage,
|
|
|
|
|
specs[i].interested_tag_key_bits,
|
|
|
|
|
specs[i].interested_tag_val_bits,
|
|
|
|
|
specs[i].cb,
|
|
|
|
|
mod) < 0)
|
2024-11-26 14:37:05 +08:00
|
|
|
{
|
2024-11-27 14:46:53 +08:00
|
|
|
CORE_LOG_FATAL("%s failed to register node:%s for module:%s in stage:%d", __FUNCTION__, specs[i].node_name, specs[i].module_name, specs[i].stage);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CORE_LOG_FATAL("%s success to register node:%s for module:%s in stage:%d", __FUNCTION__, specs[i].node_name, specs[i].module_name, specs[i].stage);
|
2024-11-26 14:37:05 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-09 10:01:20 +08:00
|
|
|
struct stellar *stellar_new(const char *toml_file)
|
2024-05-28 10:26:29 +08:00
|
|
|
{
|
2024-10-09 10:01:20 +08:00
|
|
|
if (toml_file == NULL)
|
2024-08-19 17:28:45 +08:00
|
|
|
{
|
|
|
|
|
printf("stellar config file is null\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct stellar *st = (struct stellar *)calloc(1, sizeof(struct stellar));
|
|
|
|
|
if (st == NULL)
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2024-05-28 10:26:29 +08:00
|
|
|
|
2024-10-09 10:01:20 +08:00
|
|
|
st->logger = log_new(toml_file);
|
2024-09-20 18:41:07 +08:00
|
|
|
if (st->logger == NULL)
|
2024-05-28 10:26:29 +08:00
|
|
|
{
|
2024-08-23 18:44:17 +08:00
|
|
|
printf("unable to create logger");
|
2024-05-28 10:26:29 +08:00
|
|
|
goto error_out;
|
|
|
|
|
}
|
2024-09-02 15:04:55 +08:00
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
__thread_local_logger = st->logger;
|
|
|
|
|
CORE_LOG_FATAL("stellar start (version: %s)", version);
|
2024-05-28 10:26:29 +08:00
|
|
|
|
2024-10-23 10:01:20 +08:00
|
|
|
if (load_toml_integer_config(toml_file, "packet_io.thread_num", (uint64_t *)&st->thread_num, 1, MAX_THREAD_NUM) != 0)
|
2024-05-28 10:26:29 +08:00
|
|
|
{
|
2024-09-20 18:41:07 +08:00
|
|
|
CORE_LOG_ERROR("unable to get thread number from config file");
|
2024-05-28 10:26:29 +08:00
|
|
|
goto error_out;
|
|
|
|
|
}
|
2024-09-02 16:03:08 +08:00
|
|
|
|
2024-11-27 16:53:15 +08:00
|
|
|
st->mod_mgr = module_manager_new(mod_hooks, count_of(mod_hooks), st->thread_num, toml_file, st->logger);
|
2024-09-20 18:41:07 +08:00
|
|
|
if (st->mod_mgr == NULL)
|
2024-05-28 10:26:29 +08:00
|
|
|
{
|
2024-10-11 06:08:50 +00:00
|
|
|
CORE_LOG_ERROR("unable to create packet manager");
|
2024-05-28 10:26:29 +08:00
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-09 10:01:20 +08:00
|
|
|
st->pkt_io = packet_io_new(toml_file);
|
2024-09-20 18:41:07 +08:00
|
|
|
if (st->pkt_io == NULL)
|
2024-05-28 10:26:29 +08:00
|
|
|
{
|
2024-09-20 18:41:07 +08:00
|
|
|
CORE_LOG_ERROR("unable to create packet io");
|
2024-05-28 10:26:29 +08:00
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-27 14:30:10 +08:00
|
|
|
if(register_packet_node_for_module(st->mod_mgr, packet_nodes, count_of(packet_nodes)) != 0)
|
2024-11-26 14:37:05 +08:00
|
|
|
{
|
|
|
|
|
CORE_LOG_ERROR("unable to register packet node");
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-19 17:28:45 +08:00
|
|
|
return st;
|
|
|
|
|
|
|
|
|
|
error_out:
|
2024-09-20 18:41:07 +08:00
|
|
|
stellar_free(st);
|
2024-08-19 17:28:45 +08:00
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stellar_run(struct stellar *st)
|
|
|
|
|
{
|
|
|
|
|
if (st == NULL)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stellar_thread_run(st) != 0)
|
2024-05-28 10:26:29 +08:00
|
|
|
{
|
2024-08-23 18:44:17 +08:00
|
|
|
CORE_LOG_ERROR("unable to create worker thread");
|
2024-08-19 17:28:45 +08:00
|
|
|
return;
|
2024-05-28 10:26:29 +08:00
|
|
|
}
|
|
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
while (!ATOMIC_READ(&st->need_exit))
|
2024-05-28 10:26:29 +08:00
|
|
|
{
|
|
|
|
|
usleep(1000); // 1ms
|
|
|
|
|
|
2024-08-30 10:21:44 +08:00
|
|
|
// only available in pcap mode
|
2024-10-31 16:25:37 +08:00
|
|
|
if (packet_io_is_done(st->pkt_io))
|
2024-05-28 10:26:29 +08:00
|
|
|
{
|
2024-09-20 18:41:07 +08:00
|
|
|
ATOMIC_SET(&st->need_exit, 1);
|
2024-08-27 16:19:20 +08:00
|
|
|
break;
|
2024-05-28 10:26:29 +08:00
|
|
|
}
|
|
|
|
|
}
|
2024-08-26 18:09:45 +08:00
|
|
|
|
2024-08-27 16:19:20 +08:00
|
|
|
stellar_thread_join(st);
|
2024-08-19 17:28:45 +08:00
|
|
|
}
|
2024-05-28 10:26:29 +08:00
|
|
|
|
2024-08-19 17:28:45 +08:00
|
|
|
void stellar_free(struct stellar *st)
|
|
|
|
|
{
|
|
|
|
|
if (st)
|
|
|
|
|
{
|
2024-09-20 18:41:07 +08:00
|
|
|
packet_io_free(st->pkt_io);
|
2024-11-05 09:39:10 +08:00
|
|
|
module_manager_free(st->mod_mgr);
|
2024-09-02 16:03:08 +08:00
|
|
|
|
2024-08-23 18:44:17 +08:00
|
|
|
CORE_LOG_FATAL("stellar exit\n");
|
2024-09-20 18:41:07 +08:00
|
|
|
log_free(st->logger);
|
2024-08-23 17:19:05 +08:00
|
|
|
|
|
|
|
|
free(st);
|
|
|
|
|
st = NULL;
|
2024-08-19 17:28:45 +08:00
|
|
|
}
|
|
|
|
|
}
|
2024-05-28 10:26:29 +08:00
|
|
|
|
2024-08-19 17:28:45 +08:00
|
|
|
void stellar_loopbreak(struct stellar *st)
|
|
|
|
|
{
|
|
|
|
|
if (st)
|
|
|
|
|
{
|
2024-09-20 18:41:07 +08:00
|
|
|
ATOMIC_SET(&st->need_exit, 1);
|
2024-08-19 17:28:45 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stellar_reload_log_level(struct stellar *st)
|
|
|
|
|
{
|
|
|
|
|
if (st)
|
|
|
|
|
{
|
2024-09-20 18:41:07 +08:00
|
|
|
log_reload_level(st->logger);
|
2024-08-19 17:28:45 +08:00
|
|
|
}
|
2024-05-28 10:26:29 +08:00
|
|
|
}
|
|
|
|
|
|
2024-08-23 18:44:17 +08:00
|
|
|
struct logger *stellar_get_logger(struct stellar *st)
|
|
|
|
|
{
|
|
|
|
|
if (st)
|
|
|
|
|
{
|
2024-09-20 18:41:07 +08:00
|
|
|
return st->logger;
|
2024-08-23 18:44:17 +08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2024-11-26 18:59:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct module_manager *stellar_get_module_manager(struct stellar *st)
|
|
|
|
|
{
|
|
|
|
|
if (st)
|
|
|
|
|
{
|
|
|
|
|
return st->mod_mgr;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2024-06-27 15:07:54 +08:00
|
|
|
}
|