aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrumeet <yuuta@yuuta.moe>2021-07-08 21:20:11 -0700
committerTrumeet <yuuta@yuuta.moe>2021-07-08 21:20:11 -0700
commit097ddb404f2a67398821c6a27f24db5cb939b79d (patch)
treefd3f9325e8c33ada2aefcebf645f73425f38af12
parent2fe493287c572ea988d6e79981f1fba02891a01f (diff)
downloadextmc-master.tar
extmc-master.tar.gz
extmc-master.tar.bz2
extmc-master.zip
feat: require a string unique ID as plugin identificationHEADmaster
This greatly simplifies the management of plugins, but no longer supports loading the same plugin twice.
-rw-r--r--main.c27
-rw-r--r--plugin/plugin.h5
-rw-r--r--plugin_registry.c68
-rw-r--r--plugin_registry.h9
-rw-r--r--plugins.c43
-rw-r--r--plugins.h8
-rw-r--r--sample/main.c33
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 <ID>\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;
}