From a89a0f918925a662503c1bcb28bdb06ab9b7ef25 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Tue, 30 Jun 2020 08:10:04 +0200 Subject: Share config parsing fully between server and cmdline tool --- minecproxy/server.c | 388 ++++++++++++++++------------------------------------ 1 file changed, 121 insertions(+), 267 deletions(-) (limited to 'minecproxy/server.c') diff --git a/minecproxy/server.c b/minecproxy/server.c index 8c521cf..81d148b 100644 --- a/minecproxy/server.c +++ b/minecproxy/server.c @@ -14,26 +14,12 @@ #include "uring.h" #include "ptimer.h" #include "server.h" +#include "server-config.h" #include "server-proxy.h" #include "server-rcon.h" -#include "config-parser.h" #include "idle.h" #include "systemd.h" -static bool set_property(struct server *server, char **property, - const char *value) -{ - assert_return(server && !*property && !empty_str(value), false); - - *property = xstrdup(value); - if (!*property) { - error("strdup: %m"); - return false; - } - - return true; -} - void server_refdump(struct server *server) { struct server_local *local; @@ -45,7 +31,7 @@ void server_refdump(struct server *server) uring_task_refdump(&server->exec_task); uring_task_refdump(&server->ann_task); uring_task_refdump(&server->idle_task); - list_for_each_entry(local, &server->locals, list) + list_for_each_entry(local, &server->listenings, list) local_refdump(local); list_for_each_entry(proxy, &server->proxys, list) proxy_refdump(proxy); @@ -60,12 +46,6 @@ static void server_free(struct uring_task *task) debug(DBG_SRV, "freeing server %s (%p)", server->name, server); list_del(&server->list); - xfree(server->pretty_name); - xfree(server->start_exec); - xfree(server->stop_exec); - xfree(server->systemd_service); - xfree(server->systemd_obj); - xfree(server->rcon_password); xfree(server->name); xfree(server); } @@ -74,10 +54,6 @@ void server_delete(struct server *server) { struct server_local *local, *ltmp; struct server_proxy *proxy, *ptmp; - struct saddr *remote; - struct saddr *rcon; - struct saddr *tmp; - struct dns_async *dns, *dtmp; assert_return(server); @@ -86,40 +62,28 @@ void server_delete(struct server *server) rcon_delete(server); - list_for_each_entry_safe(local, ltmp, &server->locals, list) + list_for_each_entry_safe(local, ltmp, &server->listenings, list) local_delete(local); list_for_each_entry_safe(proxy, ptmp, &server->proxys, list) proxy_delete(proxy); - list_for_each_entry_safe(rcon, tmp, &server->rcons, list) { - list_del(&rcon->list); - xfree(rcon); - } - - list_for_each_entry_safe(remote, tmp, &server->remotes, list) { - list_del(&remote->list); - xfree(remote); - } - - list_for_each_entry_safe(dns, dtmp, &server->dnslookups, list) - gai_cancel(&dns->gcb); - uring_task_destroy(&server->idle_task); uring_poll_cancel(&server->exec_task); uring_task_put(&server->exec_task); uring_task_destroy(&server->task); uring_task_put(&server->ann_task); + scfg_delete(&server->scfg); } -void server_delete_by_name(const char *name) +void server_delete_by_filename(const char *filename) { struct server *server; - assert_return(!empty_str(name)); + assert_return(!empty_str(filename)); list_for_each_entry(server, &cfg->servers, list) { - if (streq(server->name, name)) { + if (streq(server->scfg.filename, filename)) { server_delete(server); return; } @@ -135,7 +99,7 @@ static void server_dump(struct server *server) assert_return(server); verbose("Server %s:", server->name); - switch (server->type) { + switch (server->scfg.type) { case SERVER_TYPE_ANNOUNCE: verbose(" * Type: announce"); break; @@ -147,24 +111,24 @@ static void server_dump(struct server *server) break; } verbose(" * Name: %s", - server->pretty_name ? server->pretty_name : ""); - verbose(" * Announce port: %" PRIu16, server->announce_port); + server->scfg.pretty_name ? server->scfg.pretty_name : ""); + verbose(" * Announce port: %" PRIu16, server->scfg.announce_port); - if (!list_empty(&server->locals)) { + if (!list_empty(&server->listenings)) { verbose(" * Local:"); - list_for_each_entry(local, &server->locals, list) + list_for_each_entry(local, &server->listenings, list) verbose(" * %s", local->local.addrstr); } - if (!list_empty(&server->remotes)) { + if (!list_empty(&server->scfg.remotes)) { verbose(" * Remote:"); - list_for_each_entry(remote, &server->remotes, list) + list_for_each_entry(remote, &server->scfg.remotes, list) verbose(" * %s", remote->addrstr); } - if (!list_empty(&server->rcons)) { + if (!list_empty(&server->scfg.rcons)) { verbose(" * RCon:"); - list_for_each_entry(rcon, &server->rcons, list) + list_for_each_entry(rcon, &server->scfg.rcons, list) verbose(" * %s", rcon->addrstr); } @@ -253,7 +217,7 @@ static bool server_check_running(struct server *server) assert_return(server, false); /* FIXME: other methods, rcon? */ - if (server->systemd_service) { + if (server->scfg.systemd_service) { verbose("%s: checking if systemd service is running", server->name); if (systemd_service_running(server)) { @@ -273,14 +237,16 @@ bool server_start(struct server *server) assert_return(server, false); assert_task_alive_or(DBG_SRV, &server->task, return false); - switch (server->start_method) { + switch (server->scfg.start_method) { case SERVER_START_METHOD_EXEC: - verbose("Starting server %s via external cmd", server->name); - return server_exec(server, server->start_exec); + verbose("Starting server %s via external cmd", + server->name); + return server_exec(server, server->scfg.start_exec); case SERVER_START_METHOD_SYSTEMD: - verbose("Starting server %s via systemd (%s)", server->name, - server->systemd_service); + verbose("Starting server %s via systemd (%s)", + server->name, + server->scfg.systemd_service); if (systemd_service_start(server)) { server->state = SERVER_STATE_RUNNING; @@ -301,14 +267,16 @@ bool server_stop(struct server *server) assert_return(server, false); assert_task_alive_or(DBG_SRV, &server->task, return false); - switch (server->stop_method) { + switch (server->scfg.stop_method) { case SERVER_STOP_METHOD_EXEC: - verbose("Stopping server %s via external cmd", server->name); - return server_exec(server, server->stop_exec); + verbose("Stopping server %s via external cmd", + server->name); + return server_exec(server, server->scfg.stop_exec); case SERVER_STOP_METHOD_SYSTEMD: - verbose("Stopping server %s via systemd (%s)", server->name, - server->systemd_service); + verbose("Stopping server %s via systemd (%s)", + server->name, + server->scfg.systemd_service); if (systemd_service_stop(server)) { server->state = SERVER_STATE_STOPPED; return true; @@ -340,7 +308,8 @@ void server_set_active_players(struct server *server, int count) assert_return(server); assert_task_alive(DBG_IDLE, &server->idle_task); - debug(DBG_IDLE, "%s: currently %i active players", server->name, count); + debug(DBG_IDLE, "%s: currently %i active players", + server->name, count); if (count < 0) return; @@ -351,12 +320,24 @@ void server_set_active_players(struct server *server, int count) else if (count == 0) server->idle_count++; - if (server->idle_count > server->idle_timeout) { + if (server->idle_count > server->scfg.idle_timeout) { verbose("stopping idle server %s", server->name); server_stop(server); } } +void server_async_dns_update(struct server_config *scfg, bool done) +{ + struct server *server = container_of(scfg, struct server, scfg); + + if (done) { + uring_task_put(&server->task); + server_commit(server); + } else { + uring_task_get(&server->task); + } +} + static void server_idle_connected_cb(struct connection *conn, bool connected) { struct server *server = container_of(conn, struct server, idle_conn); @@ -385,10 +366,10 @@ bool server_idle_check(struct server *server) server->state == SERVER_STATE_DEAD) return false; - if (server->idle_timeout < 1) + if (server->scfg.idle_timeout < 1) return false; - if (list_empty(&server->remotes)) + if (list_empty(&server->scfg.remotes)) return false; if (!list_empty(&server->proxys)) { @@ -396,8 +377,8 @@ bool server_idle_check(struct server *server) return true; } - connect_any(&server->idle_task, &server->remotes, &server->idle_conn, - server_idle_connected_cb); + connect_any(&server->idle_task, &server->scfg.remotes, + &server->idle_conn, server_idle_connected_cb); return true; } @@ -440,7 +421,7 @@ bool server_announce(struct server *server, int fd) bool server_commit(struct server *server) { - struct server_local *local; + struct saddr *saddr, *tmp; uint16_t port; int r; @@ -457,70 +438,67 @@ bool server_commit(struct server *server) return false; } - if (!list_empty(&server->dnslookups)) { + if (!list_empty(&server->scfg.dnslookups)) { debug(DBG_SRV, "called with pending DNS requests"); return true; } - if (server->stop_method == SERVER_STOP_METHOD_RCON && - list_empty(&server->rcons)) { + if (server->scfg.stop_method == SERVER_STOP_METHOD_RCON && + list_empty(&server->scfg.rcons)) { error("%s: rcon stop method missing rcon address", server->name); return false; } - if (server->stop_method == SERVER_STOP_METHOD_RCON && - !server->rcon_password) { + if (server->scfg.stop_method == SERVER_STOP_METHOD_RCON && + !server->scfg.rcon_password) { error("%s: rcon stop method missing rcon password", server->name); return false; } - if ((server->start_method == SERVER_START_METHOD_SYSTEMD || - server->stop_method == SERVER_STOP_METHOD_SYSTEMD) && - !server->systemd_service) { + if ((server->scfg.start_method == SERVER_START_METHOD_SYSTEMD || + server->scfg.stop_method == SERVER_STOP_METHOD_SYSTEMD) && + !server->scfg.systemd_service) { error("%s: systemd start/stop method missing systemd service", server->name); return false; } - if (server->systemd_service && !server->systemd_obj) { - server->systemd_obj = - systemd_object_path(server->systemd_service); - if (!server->systemd_obj) { - error("%s: failed to create systemd object path (%s)", - server->name, server->systemd_service); - return false; - } + if ((server->scfg.systemd_service && !server->scfg.systemd_obj) || + (!server->scfg.systemd_service && server->scfg.systemd_obj)) { + error("%s: systemd service but no object path or vice versa", + server->name); + return false; } - if (server->idle_timeout > 0 && - server->stop_method == SERVER_STOP_METHOD_UNDEFINED) { + if (server->scfg.idle_timeout > 0 && + server->scfg.stop_method == SERVER_STOP_METHOD_UNDEFINED) { error("%s: idle_timeout set but missing stop method", server->name); return false; } - switch (server->type) { + switch (server->scfg.type) { case SERVER_TYPE_ANNOUNCE: - if (server->announce_port < 1) { + if (server->scfg.announce_port == 0) { error("%s: missing announce port", server->name); return false; } - if (server->start_method != SERVER_START_METHOD_UNDEFINED) { + if (server->scfg.start_method != SERVER_START_METHOD_UNDEFINED) { error("%s: can't set start_method for announce server", server->name); return false; } - if (!list_empty(&server->locals)) { + if (!list_empty(&server->scfg.locals)) { error("%s: can't set local addresses for announce server", server->name); return false; } - if (!list_empty(&server->remotes)) { + if (!list_empty(&server->scfg.remotes)) { error("%s: can't set remote addresses for announce server", server->name); return false; @@ -529,42 +507,42 @@ bool server_commit(struct server *server) break; case SERVER_TYPE_PROXY: - if (server->announce_port >= 1) { + if (server->scfg.announce_port == 0) { error("%s: can't set announce port for proxy server", server->name); return false; } - if (list_empty(&server->locals)) { + if (list_empty(&server->scfg.locals)) { error("%s: missing local addresses for proxy server", server->name); return false; } - if (list_empty(&server->remotes)) { + if (list_empty(&server->scfg.remotes)) { error("%s: missing remote addresses for proxy server", server->name); return false; } - list_for_each_entry(local, &server->locals, list) { - port = saddr_port(&local->local); + list_for_each_entry(saddr, &server->scfg.locals, list) { + port = saddr_port(saddr); if (port == 0) { error("%s: invalid local port", server->name); return false; } - if (server->announce_port < 1) - server->announce_port = port; + if (server->scfg.announce_port == 0) + server->scfg.announce_port = port; - if (server->announce_port != port) { + if (server->scfg.announce_port != port) { error("%s: multiple local ports", server->name); return false; } } - if (server->announce_port < 1) { + if (server->scfg.announce_port == 0) { error("%s: can't determine which port to announce", server->name); return false; @@ -577,7 +555,7 @@ bool server_commit(struct server *server) return false; } - if (!server->pretty_name) { + if (!server->scfg.pretty_name) { char *suffix; suffix = strrchr(server->name, '.'); @@ -586,9 +564,9 @@ bool server_commit(struct server *server) return false; } - server->pretty_name = + server->scfg.pretty_name = xstrndup(server->name, suffix - server->name); - if (!server->pretty_name) { + if (!server->scfg.pretty_name) { error("failed to create display name: %s", server->name); return false; @@ -596,8 +574,9 @@ bool server_commit(struct server *server) } r = snprintf(server->ann_buf.buf, sizeof(server->ann_buf.buf), - "[MOTD]%s[/MOTD][AD]%" PRIu16 "[/AD]", server->pretty_name, - server->announce_port); + "[MOTD]%s[/MOTD][AD]%" PRIu16 "[/AD]", + server->scfg.pretty_name, + server->scfg.announce_port); if (r < 1 || r >= sizeof(server->ann_buf.buf)) { error("%s: unable to create announce msg: %i\n", server->name, r); @@ -609,8 +588,15 @@ bool server_commit(struct server *server) * available before this is called */ server_dump(server); - list_for_each_entry(local, &server->locals, list) + list_for_each_entry_safe(saddr, tmp, &server->scfg.locals, list) { + struct server_local *local; + + /* FIXME: error checks */ + list_del(&saddr->list); + local = local_new(server, saddr); local_open(local); + list_add(&local->list, &server->listenings); + } server->state = SERVER_STATE_CFG_OK; @@ -620,177 +606,48 @@ bool server_commit(struct server *server) return true; } -bool server_add_remote(struct server *server, struct saddr *remote) -{ - assert_return(server && remote, false); - assert_task_alive_or(DBG_SRV, &server->task, return false); - - debug(DBG_SRV, "adding remote: %s", remote->addrstr); - list_add(&remote->list, &server->remotes); - return true; -} - -bool server_add_local(struct server *server, struct saddr *saddr) -{ - struct server_local *local; - - assert_return(server && saddr, false); - assert_task_alive_or(DBG_SRV, &server->task, return false); - - local = local_new(server, saddr); - if (!local) - return false; - - list_add(&local->list, &server->locals); - return true; -} - -bool server_add_rcon(struct server *server, struct saddr *rcon) -{ - assert_return(server && rcon, false); - assert_task_alive_or(DBG_SRV, &server->task, return false); - - debug(DBG_SRV, "adding rcon: %s", rcon->addrstr); - list_add(&rcon->list, &server->rcons); - return true; -} - -bool server_set_rcon_password(struct server *server, const char *password) -{ - assert_return(server && !empty_str(password), false); - - return set_property(server, &server->rcon_password, password); -} - -bool server_set_systemd_service(struct server *server, const char *service) -{ - const char *suffix; - char *tmp; - - assert_return(server && !empty_str(service) && !server->systemd_service, - false); - - suffix = strrchr(service, '.'); - if (!suffix || !streq(suffix, ".service")) { - tmp = zmalloc(strlen(service) + STRLEN(".service") + 1); - if (tmp) - sprintf(tmp, "%s.service", service); - } else - tmp = xstrdup(service); - - if (!tmp) { - error("malloc/strdup: %m"); - return false; - } - - server->systemd_service = tmp; - return true; -} - -bool server_set_stop_method(struct server *server, - enum server_stop_method stop_method) -{ - assert_return(server->stop_method == SERVER_STOP_METHOD_UNDEFINED && - stop_method != SERVER_STOP_METHOD_UNDEFINED, - false); - - server->stop_method = stop_method; - return true; -} - -bool server_set_start_method(struct server *server, - enum server_start_method start_method) -{ - assert_return(server->start_method == SERVER_START_METHOD_UNDEFINED && - start_method != SERVER_START_METHOD_UNDEFINED, - false); - - server->start_method = start_method; - return true; -} - -bool server_set_stop_exec(struct server *server, const char *cmd) -{ - assert_return(server && !empty_str(cmd), false); - - return set_property(server, &server->stop_exec, cmd); -} - -bool server_set_start_exec(struct server *server, const char *cmd) -{ - assert_return(server && !empty_str(cmd), false); - - return set_property(server, &server->start_exec, cmd); -} - -bool server_set_idle_timeout(struct server *server, uint16_t timeout) -{ - assert_return(server && timeout > 0 && server->idle_timeout == 0, - false); - - server->idle_timeout = timeout; - return true; -} - -bool server_set_port(struct server *server, uint16_t port) -{ - assert_return(server && port > 0 && server->announce_port == 0, false); - - server->announce_port = htons(port); - return true; -} - -bool server_set_type(struct server *server, enum server_type type) -{ - assert_return(server && type != SERVER_TYPE_UNDEFINED, false); - - switch (type) { - case SERVER_TYPE_ANNOUNCE: - server->type = SERVER_TYPE_ANNOUNCE; - break; - case SERVER_TYPE_PROXY: - server->type = SERVER_TYPE_PROXY; - break; - default: - return false; - } - - return true; -} - -bool server_set_pretty_name(struct server *server, const char *pretty_name) -{ - assert_return(server && !empty_str(pretty_name), false); - - return set_property(server, &server->pretty_name, pretty_name); -} - -struct server *server_new(const char *name) +struct server *server_new(const char *filename) { struct server *server; + const char *suffix; - assert_return(!empty_str(name), NULL); + assert_return(!empty_str(filename), NULL); list_for_each_entry(server, &cfg->servers, list) { - if (!streq(name, server->name)) + if (!streq(filename, server->name)) continue; - error("attempt to add duplicate server: %s", name); + error("attempt to add duplicate server: %s", filename); return server; } - verbose("Adding server %s", name); + verbose("Adding server %s", filename); server = zmalloc(sizeof(*server)); if (!server) { error("malloc: %m"); return NULL; } + suffix = strrchr(filename, '.'); + if (!suffix || suffix == filename) { + error("invalid filename: %s", filename); + xfree(server); + return NULL; + } + + server->name = xstrndup(filename, suffix - filename); + if (!server->name) { + error("failed to create server name: %s", filename); + xfree(server); + return NULL; + } + + if (!scfg_init(&server->scfg, filename)) { + xfree(server->name); + xfree(server); + return NULL; + } + server->state = SERVER_STATE_INIT; - server->type = SERVER_TYPE_UNDEFINED; - server->name = xstrdup(name); - server->stop_method = SERVER_STOP_METHOD_UNDEFINED; - server->start_method = SERVER_START_METHOD_UNDEFINED; - server->idle_timeout = 0; uring_task_init(&server->task, server->name, uring_parent(), server_free); @@ -811,11 +668,8 @@ struct server *server_new(const char *name) rcon_init(server); - INIT_LIST_HEAD(&server->remotes); - INIT_LIST_HEAD(&server->locals); + INIT_LIST_HEAD(&server->listenings); INIT_LIST_HEAD(&server->proxys); - INIT_LIST_HEAD(&server->rcons); - INIT_LIST_HEAD(&server->dnslookups); list_add(&server->list, &cfg->servers); return server; -- cgit v1.2.3