From 097ddb404f2a67398821c6a27f24db5cb939b79d Mon Sep 17 00:00:00 2001 From: Trumeet Date: Thu, 8 Jul 2021 21:20:11 -0700 Subject: feat: require a string unique ID as plugin identification This greatly simplifies the management of plugins, but no longer supports loading the same plugin twice. --- main.c | 27 ++++++---------------- plugin/plugin.h | 5 +++- plugin_registry.c | 68 ++++++++++++++++++++++++++++--------------------------- plugin_registry.h | 9 ++++---- plugins.c | 43 +++++++++++++++++++++++++---------- plugins.h | 8 ++++--- sample/main.c | 33 ++++++++++++++------------- 7 files changed, 104 insertions(+), 89 deletions(-) diff --git a/main.c b/main.c index 608c10f..591d022 100644 --- a/main.c +++ b/main.c @@ -95,9 +95,8 @@ static int autoload(const char *config_path) current_path[strlen(current_path) - 1] = '\0'; if(strlen(current_path) > 0) { - int id = 0; - if(!plugin_registry_load(2, current_path, &id)) - printf(_("Autoload: loaded %s with ID %d.\n"), current_path, id); + if(!plugin_registry_load(2, current_path)) + printf(_("Autoload: loaded %s.\n"), current_path); } free(current_path); } @@ -182,7 +181,7 @@ static int main_handle_cmd(const int out, int argc, char **argv) for(int i = 0; i < plugin_size(); i ++) { const struct plugin *plug = plugin_get_by_index(i); - dprintf(out, _("%d\t%s\n"), plug->id, plug->name); + dprintf(out, _("%s\t%s\n"), plug->id, plug->name); } return 0; } @@ -196,12 +195,7 @@ static int main_handle_cmd(const int out, int argc, char **argv) dprintf(out, _("Waiting until the processing is done.\n")); exclusive_section_enter(); thpool_wait(thpool); - int id = -1; - int r = plugin_registry_load(out, argv[1], &id); - if(!r) - { - dprintf(out, _("ID: %d\n"), id); - } + int r = plugin_registry_load(out, argv[1]); exclusive_section_leave(); return r; } @@ -212,14 +206,7 @@ static int main_handle_cmd(const int out, int argc, char **argv) dprintf(out, _("unload expects one argument: unload \n")); return 64; } - char *endptr; - intmax_t num = strtoimax(argv[1], &endptr, 10); - if(strcmp(endptr, "") || (num == INTMAX_MAX && errno == ERANGE) || num > INT_MAX || num < INT_MIN) - { - dprintf(out, _("Invalid ID: %s\n"), argv[1]); - return 64; - } - int id = (int)num; + char *id = argv[1]; dprintf(out, _("Waiting until the processing is done.\n")); int r = 0; exclusive_section_enter(); @@ -228,7 +215,7 @@ static int main_handle_cmd(const int out, int argc, char **argv) if(plug == NULL) { r = 1; - dprintf(out, _("Cannot find plugin ID: %d\n"), id); + dprintf(out, _("Cannot find plugin ID: %s\n"), id); } else { @@ -657,7 +644,7 @@ cleanup: if(autoload_setup) {} // Plugins are always unloaded. DEBUG("main.c#main_daemon: Unloading plugins...\n"); const int size = plugin_size(); - int *plugins = calloc(size, sizeof(int)); + const char **plugins = calloc(size, sizeof(char*)); for(int i = 0; i < size; i ++) plugins[i] = plugin_get_by_index(i)->id; for(int i = 0; i < size; i ++) diff --git a/plugin/plugin.h b/plugin/plugin.h index bfed63d..e52c62f 100644 --- a/plugin/plugin.h +++ b/plugin/plugin.h @@ -17,10 +17,13 @@ extern const uint32_t epg_version; /* Plugin display name. */ extern const char *epg_name; +/* NULL terminated unique ID */ +extern const char *epg_id; + /* Current session handle. */ struct epg_handle { /* Unique ID. */ - int id; + const char *id; /* Send rcon command. */ int (*rcon_send)(int, char *); int (*rcon_recv)(int *, char *); diff --git a/plugin_registry.c b/plugin_registry.c index b6b0dbd..b6ace57 100644 --- a/plugin_registry.c +++ b/plugin_registry.c @@ -12,31 +12,21 @@ #define PLUGIN_ID_GEN_MAX_RETRY 1 static int plugin_count = 0; +/* TODO: May use hashing to improve search preformance */ +/* TODO: May use sorting + binary search to improve search performance */ +static const char **id_arr = NULL; static struct plugin *plugin_arr = NULL; static pthread_key_t key_plugin; -static int plugin_generate_id() -{ - int retry_count = 0; - goto gen; -gen: - if(retry_count > PLUGIN_ID_GEN_MAX_RETRY) return -1; - int rand_val = rand(); - for(int i = 0; i < plugin_count; i ++) - { - if(plugin_get_by_index(i)->id == rand_val) - { - retry_count ++; - goto gen; - } - } - return rand_val; -} - static void arr_resize(int new_size) { if(new_size == 0) { + if(id_arr != NULL) + { + free(id_arr); + id_arr = NULL; + } if(plugin_arr != NULL) { free(plugin_arr); @@ -44,6 +34,10 @@ static void arr_resize(int new_size) } return; } + if(id_arr == NULL) + id_arr = calloc(new_size, sizeof(char *)); + else + id_arr = realloc(id_arr, new_size * sizeof(char *)); if(plugin_arr == NULL) plugin_arr = calloc(new_size, sizeof(struct plugin)); else @@ -68,17 +62,17 @@ int plugin_size() return plugin_count; } -static int plugin_id_to_index(int id) +static int plugin_id_to_index(const char *id) { for(int i = 0; i < plugin_count; i ++) { - if(plugin_arr[i].id == id) + if(!strcmp(id_arr[i], id)) return i; } return -1; } -struct plugin *plugin_get(int id) +struct plugin *plugin_get(const char *id) { const int index = plugin_id_to_index(id); if(index < 0) @@ -91,7 +85,7 @@ struct plugin *plugin_get_by_index(int index) return &plugin_arr[index]; } -int plugin_registry_unload(int stderr_fd, int id) +int plugin_registry_unload(int stderr_fd, const char *id) { int r = 0; const int index = plugin_id_to_index(id); @@ -103,30 +97,38 @@ int plugin_registry_unload(int stderr_fd, int id) struct plugin *plug = plugin_get_by_index(index); r = plugin_unload(stderr_fd, plug); if(r) goto cleanup; + r = plugin_unload_meta(stderr_fd, plug); + if(r) goto cleanup; memcpy(plug, &plugin_arr[index + 1], (plugin_count - 1 - index) * sizeof(struct plugin)); + memcpy((char **)id_arr[index], &id_arr[index + 1], (plugin_count - 1 - index) * sizeof(char *)); arr_resize(-- plugin_count); goto cleanup; cleanup: return r; } -int plugin_registry_load(int stderr_fd, const char *path, int *id) +int plugin_registry_load(int stderr_fd, const char *path) { int r = 0; - const int id_gen = plugin_generate_id(); - if(id_gen <= 0) + struct plugin plugin; + r = plugin_load_meta(stderr_fd, path, &plugin); + if(r) goto cleanup; + if(plugin_get(plugin.id) != NULL) { - r = EPLUGINEXCEED; + dprintf(stderr_fd, _("Plugin '%s' exists.\n"), plugin.id); + plugin_unload_meta(stderr_fd, &plugin); + r = EPLUGINEXISTS; goto cleanup; } - arr_resize(++ plugin_count); - r = plugin_load(stderr_fd, path, id_gen, &plugin_arr[plugin_count - 1]); + r = plugin_load(stderr_fd, &plugin); if(r) { - arr_resize(-- plugin_count); + plugin_unload_meta(stderr_fd, &plugin); goto cleanup; } - *id = id_gen; + arr_resize(++ plugin_count); + id_arr[plugin_count - 1] = plugin.id; + memcpy(&plugin_arr[plugin_count - 1], &plugin, sizeof(struct plugin)); goto cleanup; cleanup: return r; @@ -136,7 +138,7 @@ static int api_rcon_send_wrapper(int pkt_id, char *command) { int r = 0; const struct plugin *plug = pthread_getspecific(key_plugin); - printf(_("[rcon#%d] -> '%s' (%d)\n"), + printf(_("[rcon#%s] -> '%s' (%d)\n"), plug->id, command, pkt_id); @@ -154,7 +156,7 @@ static int api_rcon_recv_wrapper(int *pkt_id, char *out) // TODO: The plugin identity may have future usages. r = rcon_host_recv(pkt_id, out); if(!r) - printf(_("[rcon#%d] <- %s (%d)\n"), + printf(_("[rcon#%s] <- %s (%d)\n"), plug->id, out, *pkt_id); @@ -163,7 +165,7 @@ cleanup: return r; } -void plugcall_setup_handle(struct plugin *plugin, struct epg_handle *handle) +void plugcall_setup_handle(const struct plugin *plugin, struct epg_handle *handle) { pthread_setspecific(key_plugin, plugin); handle->id = plugin->id; diff --git a/plugin_registry.h b/plugin_registry.h index a38808e..bc0ed18 100644 --- a/plugin_registry.h +++ b/plugin_registry.h @@ -5,17 +5,18 @@ #define EPLUGINEXCEED 10 #define EPLUGINNOTFOUND 74 +#define EPLUGINEXISTS 117 int plugin_registry_init(); void plugin_registry_free(); int plugin_size(); -struct plugin *plugin_get(int id); +struct plugin *plugin_get(const char *id); struct plugin *plugin_get_by_index(int index); -int plugin_registry_unload(int stderr_fd, int id); -int plugin_registry_load(int stderr_fd, const char *path, int *id); +int plugin_registry_unload(int stderr_fd, const char *id); +int plugin_registry_load(int stderr_fd, const char *path); -void plugcall_setup_handle(struct plugin *plugin, struct epg_handle *handle); +void plugcall_setup_handle(const struct plugin *plugin, struct epg_handle *handle); void plugcall_player_join(void *arg); void plugcall_player_leave(void *arg); diff --git a/plugins.c b/plugins.c index ec8b727..d7d81a1 100644 --- a/plugins.c +++ b/plugins.c @@ -26,7 +26,17 @@ static const void *plugin_dlsym(int stderr_fd, void *handle, const bool mandator return sym; } -int plugin_unload(int stderr_fd, struct plugin *plugin) +int plugin_unload_meta(int stderr_fd, struct plugin *plugin) +{ + if(plugin->handle != NULL) + { + dlclose(plugin->handle); + plugin->handle = NULL; + } + return 0; +} + +int plugin_unload(int stderr_fd, const struct plugin *plugin) { if(plugin->fc_unload != NULL) { @@ -39,11 +49,6 @@ int plugin_unload(int stderr_fd, struct plugin *plugin) return unload_r; } } - if(plugin->handle != NULL) - { - dlclose(plugin->handle); - plugin->handle = NULL; - } return 0; } @@ -51,6 +56,13 @@ static int plugin_load_v1(int stderr_fd, struct plugin *out) { int r = 0; const void *sym; + sym = plugin_dlsym(stderr_fd, out->handle, true, "epg_id"); + if(sym == NULL) + { + r = 64; + goto cleanup; + } + out->id = *(char**)sym; sym = plugin_dlsym(stderr_fd, out->handle, true, "epg_name"); if(sym == NULL) { @@ -75,10 +87,9 @@ cleanup: return r; } -int plugin_load(int stderr_fd, const char *path, const int id, struct plugin *out) +int plugin_load_meta(int stderr_fd, const char *path, struct plugin *out) { int r = 0; - out->id = id; out->path = path; out->handle = NULL; out->name = NULL; @@ -121,16 +132,24 @@ int plugin_load(int stderr_fd, const char *path, const int id, struct plugin *ou dprintf(stderr_fd, _("Unsupported plugin %s: Incompatible with version %u.\n"), path, out->version); break; } + goto cleanup; +cleanup: + if(r) plugin_unload_meta(stderr_fd, out); + return r; +} + +int plugin_load(int stderr_fd, const struct plugin *plugin) +{ + int r = 0; struct epg_handle hdl; - plugcall_setup_handle(out, &hdl); - r = out->fc_load(&hdl); + plugcall_setup_handle(plugin, &hdl); + r = plugin->fc_load(&hdl); if(r) { dprintf(stderr_fd, _("Cannot load plugin: it returned an error: %d.\n"), r); goto cleanup; } - goto cleanup; cleanup: - if(r) plugin_unload(stderr_fd, out); + if(r) plugin_unload(stderr_fd, plugin); return r; } diff --git a/plugins.h b/plugins.h index 64ab0bb..6ce4707 100644 --- a/plugins.h +++ b/plugins.h @@ -13,7 +13,7 @@ struct plugin_call_job_args { }; struct plugin { - int id; + const char *id; const char *path; void *handle; char *name; @@ -32,7 +32,9 @@ struct plugin { int (*fc_server_started)(struct epg_handle *, char *); }; -int plugin_load(int stderr_fd, const char *path, const int id, struct plugin *out); -int plugin_unload(int stderr_fd, struct plugin *plugin); +int plugin_load_meta(int stderr_fd, const char *path, struct plugin *out); +int plugin_load(int stderr_fd, const struct plugin *plugin); +int plugin_unload_meta(int stderr_fd, struct plugin *plugin); +int plugin_unload(int stderr_fd, const struct plugin *plugin); #endif // _PLUGINS_H diff --git a/sample/main.c b/sample/main.c index 710d245..27e5bc3 100644 --- a/sample/main.c +++ b/sample/main.c @@ -7,38 +7,39 @@ const uint32_t epg_version = 1; const char *epg_name = "Test Plugin"; +const char *epg_id = "test"; int epg_load(struct epg_handle *handle) { - printf("[%d]: Loaded.\n", handle->id); + printf("[%s]: Loaded.\n", handle->id); int r = 0; r = handle->rcon_send(11, "list uuid"); - printf("[%d]: rcon_send: %d\n", handle->id, r); + printf("[%s]: rcon_send: %d\n", handle->id, r); int id = -1; char out[RCON_DATA_BUFFSIZE]; r = handle->rcon_recv(&id, out); - printf("[%d]: rcon_recv: %d. ID: %d, out: '%s'.\n", handle->id, r, id, out); + printf("[%s]: rcon_recv: %d. ID: %d, out: '%s'.\n", handle->id, r, id, out); return 0; } int epg_unload(struct epg_handle *handle) { - printf("[%d]: Unloading.\n", handle->id); + printf("[%s]: Unloading.\n", handle->id); return 0; } int epg_player_join(struct epg_handle *handle, char *player) { - printf("[%d]: %s joined.\n", handle->id, player); + printf("[%s]: %s joined.\n", handle->id, player); sleep(10); int r = 0; r = handle->rcon_send(11, "list"); - printf("[%d]: rcon_send: %d\n", handle->id, r); + printf("[%s]: rcon_send: %d\n", handle->id, r); int id = -1; char out[RCON_DATA_BUFFSIZE]; r = handle->rcon_recv(&id, out); - printf("[%d]: rcon_recv: %d. ID: %d, out: '%s'.\n", handle->id, r, id, out); + printf("[%s]: rcon_recv: %d. ID: %d, out: '%s'.\n", handle->id, r, id, out); return 0; } @@ -46,7 +47,7 @@ int epg_player_leave(struct epg_handle *handle, char *player, char *reason) { - printf("[%d]: %s left: %s.\n", handle->id, player, reason); + printf("[%s]: %s left: %s.\n", handle->id, player, reason); return 0; } @@ -54,7 +55,7 @@ int epg_player_say(struct epg_handle *handle, char *player, char *content) { - printf("[%d]: %s said: %s.\n", handle->id, player, content); + printf("[%s]: %s said: %s.\n", handle->id, player, content); return 0; } @@ -62,7 +63,7 @@ int epg_player_die(struct epg_handle *handle, char *player, char *source) { - printf("[%d]: %s died because of %s.\n", handle->id, player, source); + printf("[%s]: %s died because of %s.\n", handle->id, player, source); return 0; } @@ -70,7 +71,7 @@ int epg_player_achievement(struct epg_handle *handle, char *player, char *achievement) { - printf("[%d]: %s achieved %s.\n", handle->id, player, achievement); + printf("[%s]: %s achieved %s.\n", handle->id, player, achievement); return 0; } @@ -78,7 +79,7 @@ int epg_player_challenge(struct epg_handle *handle, char *player, char *challenge) { - printf("[%d]: %s made the challenge: %s.\n", handle->id, player, challenge); + printf("[%s]: %s made the challenge: %s.\n", handle->id, player, challenge); return 0; } @@ -86,26 +87,26 @@ int epg_player_goal(struct epg_handle *handle, char *player, char *goal) { - printf("[%d]: %s made the goal: %s.\n", handle->id, player, goal); + printf("[%s]: %s made the goal: %s.\n", handle->id, player, goal); return 0; } int epg_server_stopping(struct epg_handle *handle) { - printf("[%d]: Server stopped.\n", handle->id); + printf("[%s]: Server stopped.\n", handle->id); return 0; } int epg_server_starting(struct epg_handle *handle, char *version) { - printf("[%d]: Server is starting, version: %s.\n", handle->id, version); + printf("[%s]: Server is starting, version: %s.\n", handle->id, version); return 0; } int epg_server_started(struct epg_handle *handle, char *took) { - printf("[%d]: Server started, took: %s.\n", handle->id, took); + printf("[%s]: Server started, took: %s.\n", handle->id, took); return 0; } -- cgit v1.2.3