summaryrefslogtreecommitdiff
path: root/minecproxy/server.c
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-30 08:10:04 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-30 08:10:04 +0200
commita89a0f918925a662503c1bcb28bdb06ab9b7ef25 (patch)
tree733b4c1ff841f99eeb3840c5948fef6c5bf76109 /minecproxy/server.c
parent8f29a4d23dd13a80aa26951b17e2a71f4e651cb1 (diff)
Share config parsing fully between server and cmdline tool
Diffstat (limited to 'minecproxy/server.c')
-rw-r--r--minecproxy/server.c388
1 files changed, 121 insertions, 267 deletions
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 : "<undefined>");
- verbose(" * Announce port: %" PRIu16, server->announce_port);
+ server->scfg.pretty_name ? server->scfg.pretty_name : "<undefined>");
+ 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;