summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-07-12 02:30:31 +0200
committerDavid Härdeman <david@hardeman.nu>2020-07-12 02:30:31 +0200
commitf06ff46151c38b2259c5ee4ae83d38c6f6fc0c8c (patch)
tree44f6d00604a153300eb3be9dcec96d17030727b8
parentd198326ef6ec3031afbe7ee47b727cc52fc1198a (diff)
Teach minecctl to create proper mcserver files, auto-generate systemd service names as necessary
-rw-r--r--examples/meson.build21
-rw-r--r--minecctl/minecctl.c8
-rw-r--r--minecctl/misc-commands.c118
-rw-r--r--minecctl/misc.c2
-rw-r--r--minecctl/rcon-commands.c26
-rw-r--r--minecctl/server.c21
-rw-r--r--minecctl/server.h1
-rw-r--r--minecproxy/server-config.c14
-rw-r--r--minecproxy/server-proxy.c36
-rw-r--r--minecproxy/server-rcon.c26
-rw-r--r--minecproxy/server.c71
-rw-r--r--minecproxy/server.h1
-rw-r--r--shared/config-parser.c71
-rw-r--r--shared/config-parser.h1
-rw-r--r--shared/utils.c34
-rw-r--r--shared/utils.h2
16 files changed, 257 insertions, 196 deletions
diff --git a/examples/meson.build b/examples/meson.build
index 5d3564b..7b525f6 100644
--- a/examples/meson.build
+++ b/examples/meson.build
@@ -1,8 +1,7 @@
# SPDX-License-Identifier: GPL-2
-example_files = [
+xxd_files = [
'eula.txt',
- 'example.mcserver',
'minecctl.conf',
'minecproxy.conf',
'minecproxy.service',
@@ -14,16 +13,24 @@ xxd = find_program('xxd')
xxd_cmd = [xxd, '-i', '@INPUT@', '@OUTPUT@']
-foreach example_file: example_files
- example_output = example_file + '.h'
+foreach xxd_file: xxd_files
+ xxd_output = xxd_file + '.h'
file = custom_target(
- example_output,
- input: example_file,
- output: example_output,
+ xxd_output,
+ input: xxd_file,
+ output: xxd_output,
command: xxd_cmd,
build_by_default: true,
)
endforeach
+install_files = [
+ 'example.mcserver',
+ 'minecctl.conf',
+ 'minecproxy.conf',
+ 'minecproxy.service',
+ 'minecserver@.service',
+]
+
diff --git a/minecctl/minecctl.c b/minecctl/minecctl.c
index 4a6bf0f..c2d6c19 100644
--- a/minecctl/minecctl.c
+++ b/minecctl/minecctl.c
@@ -28,7 +28,7 @@ static void dump_server(struct server *server)
info("│");
info("│ ▷ server");
info("│ ┌─────");
- info("│ │ name : %s", server->name);
+ info("│ │ name : %s", server->scfg.name);
info("│ │ file_read : %s", server->file_read ? "yes" : "no");
info("│ │ filename : %s", server->scfg.filename);
@@ -237,7 +237,7 @@ static bool create_server_from_cmdline_args(struct cfg *cfg)
if (!str_to_addrs(cfg->rcon_addrstr, &server->scfg.rcons))
goto error;
- server->name = cfg->rcon_addrstr;
+ server->scfg.name = cfg->rcon_addrstr;
cfg->rcon_addrstr = NULL;
}
@@ -245,8 +245,8 @@ static bool create_server_from_cmdline_args(struct cfg *cfg)
if (!str_to_addrs(cfg->mc_addrstr, &server->scfg.remotes))
goto error;
- if (!server->name)
- server->name = cfg->mc_addrstr;
+ if (!server->scfg.name)
+ server->scfg.name = cfg->mc_addrstr;
else
xfree(cfg->mc_addrstr);
diff --git a/minecctl/misc-commands.c b/minecctl/misc-commands.c
index 1133e55..34dd990 100644
--- a/minecctl/misc-commands.c
+++ b/minecctl/misc-commands.c
@@ -20,7 +20,6 @@
#include "misc.h"
#include "examples/eula.txt.h"
-#include "examples/example.mcserver.h"
#include "examples/minecctl.conf.h"
#include "examples/minecproxy.conf.h"
#include "examples/minecproxy.service.h"
@@ -142,10 +141,12 @@ static bool create_user_service(int xfd, const char *service,
return true;
}
-static bool create_server_cfg(struct cfg *cfg, const char *name,
- const char *filename,
- const unsigned char *properties,
- size_t properties_len)
+static bool write_server_cfg(struct cfg *cfg, const char *name,
+ const char *filename,
+ const unsigned char *properties,
+ size_t properties_len,
+ const unsigned char *mcserver,
+ size_t mcserver_len)
{
_cleanup_close_ int sfd = -1;
int cfd, dfd;
@@ -156,17 +157,15 @@ static bool create_server_cfg(struct cfg *cfg, const char *name,
cfd = dirfd(cfg->cfg_dir);
dfd = dirfd(cfg->data_dir);
- if (!write_cfg_file(cfd, filename,
- ___examples_example_mcserver,
- ___examples_example_mcserver_len))
- return false;
-
sfd = open_subdir(dfd, name, true);
if (sfd < 0) {
error("Failed to create server directory \"%s\"", name);
return false;
}
+ if (!write_cfg_file(cfd, filename, mcserver, mcserver_len))
+ return false;
+
if (!write_cfg_file(sfd, "eula.txt", ___examples_eula_txt,
___examples_eula_txt_len))
return false;
@@ -299,18 +298,37 @@ static bool generate_random_password(char *buf, size_t len)
}
*d = '\0';
- info("Hex = %s", buf);
return true;
}
+static unsigned char *create_mc_server(const char *name, uint16_t local_port,
+ size_t *len)
+{
+ char *mcserver;
+
+ /* FIXME: Add comments, commented out options */
+ mcserver = xsprintf(len,
+ "[server]\n"
+ "type = proxy\n"
+ "name = %s\n"
+ "local = %" PRIu16 "\n"
+ "idle_timeout = 600\n"
+ "start_method = systemd\n"
+ "stop_method = systemd\n",
+ name, local_port);
+ if (!mcserver)
+ error("xsprintf: %m");
+
+ return (unsigned char *)mcserver;
+}
+
static unsigned char *create_mc_properties(const char *name, uint16_t mc_port,
uint16_t rcon_port,
const char *rcon_password,
size_t *len)
{
char hexrnd[16 + 1];
- char *properties;
- int r;
+ char *prop;
if (!rcon_password) {
if (!generate_random_password(hexrnd, sizeof(hexrnd))) {
@@ -319,27 +337,24 @@ static unsigned char *create_mc_properties(const char *name, uint16_t mc_port,
}
}
- /* FIXME: server-ip= */
- r = asprintf(&properties,
- "#Minecraft server properties\n"
- "# This is a partial file, it will be replaced with a\n"
- "# fleshed out version the first time the Minecraft\n"
- "# server is executed.\n"
- "motd=%s\n"
- "server-port=%" PRIu16 "\n"
- "enable-rcon=true\n"
- "rcon.port=%" PRIu16 "\n"
- "rcon.password=%s",
- name, mc_port, rcon_port,
- rcon_password ? rcon_password : hexrnd);
- if (r < 0) {
- error("asprintf failed: %m");
- return NULL;
- }
-
- if (len)
- *len = r;
- return (unsigned char *)properties;
+ prop = xsprintf(len,
+ "#Minecraft server properties\n"
+ "# This is a partial file, it will be replaced with a\n"
+ "# fleshed out version the first time the Minecraft\n"
+ "# server is executed.\n"
+ "motd=%s\n"
+ "#maybe uncomment the next line if you use minecproxy\n"
+ "#server-ip=127.0.0.1\n"
+ "server-port=%" PRIu16 "\n"
+ "enable-rcon=true\n"
+ "rcon.port=%" PRIu16 "\n"
+ "rcon.password=%s\n",
+ name, mc_port, rcon_port,
+ rcon_password ? rcon_password : hexrnd);
+ if (!prop)
+ error("xsprintf: %m");
+
+ return (unsigned char *)prop;
}
static uint16_t get_port(struct list_head *list)
@@ -461,10 +476,12 @@ bool do_new(struct cfg *cfg)
const char *name = cfg->commands[0];
struct server *server;
struct server *defserver = NULL;
+ uint16_t local_port = 0, mc_port = 0, rcon_port = 0;
+ const char *rcon_password = NULL;
_cleanup_free_ unsigned char *properties = NULL;
size_t properties_len;
- uint16_t rcon_port = 0, mc_port = 0;
- const char *rcon_password = NULL;
+ _cleanup_free_ unsigned char *mcserver = NULL;
+ size_t mcserver_len;
if (!valid_name(name))
return false;
@@ -494,7 +511,6 @@ bool do_new(struct cfg *cfg)
}
if (defserver) {
- /* FIXME: check list empty and tailor error msg */
rcon_port = get_port(&defserver->scfg.rcons);
mc_port = get_port(&defserver->scfg.remotes);
rcon_password = defserver->scfg.rcon_password;
@@ -503,8 +519,8 @@ bool do_new(struct cfg *cfg)
dump_config(cfg);
- if (!select_free_ports(cfg, NULL, &mc_port, &rcon_port)) {
- error("Failed to find a free port");
+ if (!select_free_ports(cfg, &local_port, &mc_port, &rcon_port)) {
+ error("Failed to find free port(s)");
return false;
}
@@ -513,10 +529,13 @@ bool do_new(struct cfg *cfg)
if (!properties)
return false;
- error("Created config file (%zu):\n%s", properties_len, properties);
+ mcserver = create_mc_server(name, local_port, &mcserver_len);
+ if (!mcserver)
+ return false;
- if (!create_server_cfg(cfg, name, filename, properties,
- properties_len))
+ if (!write_server_cfg(cfg, name, filename,
+ properties, properties_len,
+ mcserver, mcserver_len))
return false;
info("Created server configuration %s", name);
@@ -532,7 +551,7 @@ bool do_list(struct cfg *cfg)
/* server->scfg.filename check excludes servers created from cmdline */
list_for_each_entry(server, &cfg->servers, list)
if (server->scfg.filename)
- info("• %s", server->name);
+ info("• %s", server->scfg.name);
return true;
}
@@ -598,22 +617,25 @@ bool do_lint(struct cfg *cfg)
a->scfg.announce_port == b->scfg.announce_port)
info("%sNote:%s %s and %s appear to have the "
"same announce port", ansi_red,
- ansi_normal, a->name, b->name);
+ ansi_normal, a->scfg.name, b->scfg.name);
if (saddr_match(&a->scfg.locals, &b->scfg.locals))
info("%sNote:%s %s and %s appear to share at "
"least one local address/port pair",
- ansi_red, ansi_normal, a->name, b->name);
+ ansi_red, ansi_normal, a->scfg.name,
+ b->scfg.name);
if (saddr_match(&a->scfg.remotes, &b->scfg.remotes))
info("%sNote:%s %s and %s appear to share at "
"least one remote address/port pair",
- ansi_red, ansi_normal, a->name, b->name);
+ ansi_red, ansi_normal, a->scfg.name,
+ b->scfg.name);
if (saddr_match(&a->scfg.rcons, &b->scfg.rcons))
info("%sNote:%s %s and %s appear to share at "
"least one rcon address/port pair",
- ansi_red, ansi_normal, a->name, b->name);
+ ansi_red, ansi_normal, a->scfg.name,
+ b->scfg.name);
ib++;
}
@@ -648,7 +670,7 @@ static bool do_one_status(struct cfg *cfg, struct server *server)
const char *error;
bool rv = true;
- info("• %s", server->name);
+ info("• %s", server->scfg.name);
if (list_empty(&server->scfg.rcons))
info(" rcon : not configured");
diff --git a/minecctl/misc.c b/minecctl/misc.c
index 26cbc86..90189dc 100644
--- a/minecctl/misc.c
+++ b/minecctl/misc.c
@@ -335,7 +335,7 @@ char *__xstrndup(const char *fn, int line, const char *s, size_t n)
"invalid arguments");
ptr = strndup(s, n);
- if (ptr)
+ if (!ptr)
die("strdup: %m");
return ptr;
}
diff --git a/minecctl/rcon-commands.c b/minecctl/rcon-commands.c
index cb6ea45..cdbf868 100644
--- a/minecctl/rcon-commands.c
+++ b/minecctl/rcon-commands.c
@@ -96,22 +96,22 @@ static int rcon_login(struct cfg *cfg, struct server *server)
assert_die(cfg && server, "invalid arguments");
if (list_empty(&server->scfg.rcons)) {
- error("%s: rcon address unknown", server->name);
+ error("%s: rcon address unknown", server->scfg.name);
goto error;
}
fd = connect_any(&server->scfg.rcons, &saddr, &error);
if (fd < 0) {
- verbose("%s: unable to connect - %s", server->name, error);
+ verbose("%s: unable to connect - %s", server->scfg.name, error);
goto error;
} else
- verbose("%s: connected to %s", server->name, saddr->addrstr);
+ verbose("%s: connected to %s", server->scfg.name, saddr->addrstr);
if (!server->scfg.rcon_password)
server->scfg.rcon_password = ask_password();
if (!server->scfg.rcon_password) {
- error("%s: can't login - password missing", server->name);
+ error("%s: can't login - password missing", server->scfg.name);
goto error;
}
@@ -123,10 +123,10 @@ static int rcon_login(struct cfg *cfg, struct server *server)
if (!rcon_protocol_verify_response(1, 1, RCON_PACKET_LOGIN,
rtype, &error)) {
- error("%s: invalid response - %s", server->name, error);
+ error("%s: invalid response - %s", server->scfg.name, error);
goto error;
} else
- verbose("%s: login ok", server->name);
+ verbose("%s: login ok", server->scfg.name);
return fd;
@@ -230,7 +230,7 @@ static bool do_one_info(struct cfg *cfg, struct server *server)
if (fd < 0)
return false;
- info("• %s", server->name);
+ info("• %s", server->scfg.name);
if (get_one_status(fd, buf, sizeof(buf), "seed", 1, "Seed : [ %[^]]]",
&reply, tbuf))
info(" Seed: %s", tbuf);
@@ -336,7 +336,7 @@ static bool stop_one_server(struct cfg *cfg, struct server *server)
fd = rcon_login(cfg, server);
if (fd < 0) {
info("• %s: %sfail%s - unable to login",
- server->name, ansi_red, ansi_normal);
+ server->scfg.name, ansi_red, ansi_normal);
return false;
}
@@ -345,17 +345,17 @@ static bool stop_one_server(struct cfg *cfg, struct server *server)
if (!get_player_count(fd, &current, NULL)) {
info("• %s: %sfail%s - unable to get player count",
- server->name, ansi_red, ansi_normal);
+ server->scfg.name, ansi_red, ansi_normal);
return false;
} else if (current > 0) {
info("• %s: %sfail%s - has active players "
"(use -f to force)",
- server->name, ansi_red, ansi_normal);
+ server->scfg.name, ansi_red, ansi_normal);
return false;
}
}
- info("• %s: sending stop command", server->name);
+ info("• %s: sending stop command", server->scfg.name);
rv = send_cmd(fd, "stop");
close(fd);
@@ -419,9 +419,9 @@ bool do_console(struct cfg *cfg)
return false;
prompt = alloca(strlen(program_invocation_short_name) + STRLEN(" (") +
- strlen(server->name) + STRLEN("): ") + 1);
+ strlen(server->scfg.name) + STRLEN("): ") + 1);
sprintf(prompt, "%s (%s): ", program_invocation_short_name,
- server->name);
+ server->scfg.name);
while (true) {
char *tmp;
diff --git a/minecctl/server.c b/minecctl/server.c
index 8bd7b51..3acc537 100644
--- a/minecctl/server.c
+++ b/minecctl/server.c
@@ -71,18 +71,12 @@ void server_load_all_known(struct cfg *cfg)
while ((dent = readdir(cfg->cfg_dir))) {
struct server *server;
- char *suffix;
if (!config_valid_server_filename(dent, NULL))
continue;
server = server_new(dent->d_name);
- suffix = strrchr(dent->d_name, '.');
- assert_die(suffix, "Error parsing filename");
- *suffix = '\0';
- server->name = xstrdup(dent->d_name);
-
list_add(&server->list, &cfg->servers);
}
}
@@ -153,7 +147,7 @@ bool server_read_config(struct cfg *cfg, struct server *server,
return false;
/* fill in missing parameters from server.properties */
- dfd = open_subdir(dirfd(cfg->data_dir), server->name, false);
+ dfd = open_subdir(dirfd(cfg->data_dir), server->scfg.name, false);
if (dfd < 0)
goto out;
@@ -193,21 +187,21 @@ bool server_read_all_configs(struct cfg *cfg, bool print_results)
if (!server_read_config(cfg, server, &lineno, &error)) {
if (lineno != 0 && print_results)
info("• %s: %sfail%s - line %u: %s",
- server->name, ansi_red, ansi_normal,
+ server->scfg.name, ansi_red, ansi_normal,
lineno, error);
else if (print_results)
info("• %s: %sfail%s - %s",
- server->name, ansi_red, ansi_normal,
+ server->scfg.name, ansi_red, ansi_normal,
error);
rv = false;
} else if (!scfg_validate(&server->scfg, &error) &&
print_results) {
info("• %s: %sfail%s - %s",
- server->name, ansi_red, ansi_normal,
+ server->scfg.name, ansi_red, ansi_normal,
error);
rv = false;
} else if (print_results) {
- info("• %s: %sok%s", server->name, ansi_green,
+ info("• %s: %sok%s", server->scfg.name, ansi_green,
ansi_normal);
}
}
@@ -226,7 +220,7 @@ struct server *server_get_default(struct cfg *cfg)
die("No servers defined");
if (!server_read_config(cfg, server, &lineno, &error)) {
- error("%s: server_read_config error - %s", server->name, error);
+ error("%s: server_read_config error - %s", server->scfg.name, error);
return NULL;
}
@@ -242,7 +236,7 @@ bool server_set_default(struct cfg *cfg, const char *name)
server_load_all_known(cfg);
list_for_each_entry(server, &cfg->servers, list) {
- if (streq(name, server->name)) {
+ if (streq(name, server->scfg.name)) {
list_rotate_to_front(&server->list, &cfg->servers);
cfg->default_set = true;
return true;
@@ -263,7 +257,6 @@ void server_free_all(struct cfg *cfg)
void server_free(struct server *server)
{
scfg_delete(&server->scfg);
- xfree(server->name);
xfree(server);
}
diff --git a/minecctl/server.h b/minecctl/server.h
index 4520d34..47682a5 100644
--- a/minecctl/server.h
+++ b/minecctl/server.h
@@ -8,7 +8,6 @@
struct server {
bool file_read;
- char *name;
struct server_config scfg;
struct list_head list;
};
diff --git a/minecproxy/server-config.c b/minecproxy/server-config.c
index 7009952..959f1d0 100644
--- a/minecproxy/server-config.c
+++ b/minecproxy/server-config.c
@@ -39,18 +39,18 @@ static void server_cfg_read_cb(struct uring_task *task, int res)
assert_task_alive(DBG_CFG, task);
if (res <= 0) {
- error("error reading config file for %s: %s", server->name,
+ error("error reading config file for %s: %s", server->scfg.name,
strerror(-res));
server_delete(server);
}
- debug(DBG_CFG, "%s: parsing cfg (%i bytes)", server->name, res);
+ debug(DBG_CFG, "%s: parsing cfg (%i bytes)", server->scfg.name, res);
uring_task_close_fd(&server->task);
if (!scfg_parse(&server->scfg, server->tbuf.buf, true,
&lineno, &error)) {
error("%s: failed to parse config file, line %u: %s",
- server->name, lineno, error);
+ server->scfg.name, lineno, error);
server_delete(server);
return;
}
@@ -74,12 +74,12 @@ static void server_cfg_open_cb(struct uring_task *task, int res)
assert_task_alive(DBG_CFG, task);
if (res < 0) {
- error("open(%s) failed: %s", server->name, strerror(-res));
+ error("open(%s) failed: %s", server->scfg.name, strerror(-res));
server_delete(server);
return;
}
- debug(DBG_CFG, "reading server cfg %s (fd %i)", server->name, res);
+ debug(DBG_CFG, "reading server cfg %s (fd %i)", server->scfg.name, res);
uring_task_set_fd(&server->task, res);
uring_tbuf_read_until_eof(&server->task, server_cfg_read_cb);
}
@@ -184,8 +184,8 @@ static void inotify_cb(struct uring_task *task, int res)
(IN_MOVED_TO | IN_CREATE | IN_CLOSE_WRITE)) {
server = server_new(event->name);
verbose("New server config file detected: %s",
- server->name);
- uring_openat(&server->task, server->name,
+ event->name);
+ uring_openat(&server->task, event->name,
server_cfg_open_cb);
} else
error("inotify: unknown event: 0x%08x", event->mask);
diff --git a/minecproxy/server-proxy.c b/minecproxy/server-proxy.c
index 9d7b59e..e486a73 100644
--- a/minecproxy/server-proxy.c
+++ b/minecproxy/server-proxy.c
@@ -70,7 +70,7 @@ static void proxy_free(struct uring_task *task)
assert_return(task);
- debug(DBG_PROXY, "server: %s, src: %s, dst: %s", proxy->server->name,
+ debug(DBG_PROXY, "server: %s, src: %s, dst: %s", proxy->server->scfg.name,
proxy->client_conn.remote.addrstr,
proxy->server_conn.remote.addrstr);
@@ -82,7 +82,7 @@ static void proxy_free(struct uring_task *task)
info("%s: proxy connection %s -> %s closed "
"(CtS: %s, StC: %s), duration %s",
- proxy->server->name, proxy->client_conn.remote.addrstr,
+ proxy->server->scfg.name, proxy->client_conn.remote.addrstr,
proxy->server_conn.remote.addrstr, cts, stc, duration);
}
@@ -97,7 +97,7 @@ static void proxy_client_free(struct uring_task *task)
assert_return(task);
- debug(DBG_PROXY, "%s: client connection closed", proxy->server->name);
+ debug(DBG_PROXY, "%s: client connection closed", proxy->server->scfg.name);
}
static void proxy_server_free(struct uring_task *task)
@@ -107,12 +107,12 @@ static void proxy_server_free(struct uring_task *task)
assert_return(task);
- debug(DBG_PROXY, "%s: server connection closed", proxy->server->name);
+ debug(DBG_PROXY, "%s: server connection closed", proxy->server->scfg.name);
}
void proxy_delete(struct server_proxy *proxy)
{
- debug(DBG_PROXY, "%s: shutting down proxy %p", proxy->server->name,
+ debug(DBG_PROXY, "%s: shutting down proxy %p", proxy->server->scfg.name,
proxy);
assert_return(proxy);
@@ -147,7 +147,7 @@ static void proxy_client_written_out(struct uring_task *task, int res)
assert_task_alive(DBG_PROXY, task);
if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
+ debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res);
proxy_delete(proxy);
return;
}
@@ -166,7 +166,7 @@ static void proxy_client_read_in(struct uring_task *task, int res)
assert_task_alive(DBG_PROXY, task);
if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
+ debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res);
proxy_delete(proxy);
return;
}
@@ -186,7 +186,7 @@ static void proxy_server_written_out(struct uring_task *task, int res)
assert_task_alive(DBG_PROXY, task);
if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
+ debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res);
proxy_delete(proxy);
return;
}
@@ -205,7 +205,7 @@ static void proxy_server_read_in(struct uring_task *task, int res)
assert_task_alive(DBG_PROXY, task);
if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
+ debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res);
proxy_delete(proxy);
return;
}
@@ -228,7 +228,7 @@ static void proxy_client_spliced_out(struct uring_task *task, int res)
assert_task_alive(DBG_PROXY, task);
if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
+ debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res);
proxy_delete(proxy);
return;
}
@@ -247,7 +247,7 @@ static void proxy_client_spliced_in(struct uring_task *task, int res)
assert_task_alive(DBG_PROXY, task);
if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
+ debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res);
proxy_delete(proxy);
return;
}
@@ -267,7 +267,7 @@ static void proxy_server_spliced_out(struct uring_task *task, int res)
assert_task_alive(DBG_PROXY, task);
if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
+ debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res);
proxy_delete(proxy);
return;
}
@@ -286,7 +286,7 @@ static void proxy_server_spliced_in(struct uring_task *task, int res)
assert_task_alive(DBG_PROXY, task);
if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
+ debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res);
proxy_delete(proxy);
return;
}
@@ -307,7 +307,7 @@ static void proxy_connected_cb(struct connection *conn, bool connected)
proxy->connecting = false;
if (!connected) {
error("%s: proxy connection to remote server failed",
- proxy->server->name);
+ proxy->server->scfg.name);
if (!proxy->ptask.active)
proxy_delete(proxy);
return;
@@ -316,7 +316,7 @@ static void proxy_connected_cb(struct connection *conn, bool connected)
ptimer_del_task(&proxy->ptask);
proxy->sfd = proxy->servertask.fd;
- verbose("%s: proxy connection %s -> %s opened", proxy->server->name,
+ verbose("%s: proxy connection %s -> %s opened", proxy->server->scfg.name,
proxy->client_conn.remote.addrstr,
proxy->server_conn.remote.addrstr);
proxy->begin = time(NULL);
@@ -439,7 +439,7 @@ static void local_accept(struct uring_task *task, int res)
assert_return(task);
assert_task_alive(DBG_PROXY, task);
- debug(DBG_PROXY, "task %p, res %i, server %s", task, res, server->name);
+ debug(DBG_PROXY, "task %p, res %i, server %s", task, res, server->scfg.name);
if (res < 0) {
error("res: %i", res);
@@ -448,7 +448,7 @@ static void local_accept(struct uring_task *task, int res)
saddr_set_addrstr(&local->client);
- verbose("%s: incoming proxy connection: %s -> %s", server->name,
+ verbose("%s: incoming proxy connection: %s -> %s", server->scfg.name,
local->client.addrstr, local->local.addrstr);
if (list_empty(&server->scfg.remotes)) {
@@ -571,7 +571,7 @@ struct server_local *local_new(struct server *server, struct saddr *saddr)
return NULL;
}
- debug(DBG_PROXY, "%s adding local: %s", server->name, saddr->addrstr);
+ debug(DBG_PROXY, "%s adding local: %s", server->scfg.name, saddr->addrstr);
local->local = *saddr;
local->server = server;
uring_task_init(&local->task, "local", &server->task, local_free);
diff --git a/minecproxy/server-rcon.c b/minecproxy/server-rcon.c
index c8a91c3..a728bab 100644
--- a/minecproxy/server-rcon.c
+++ b/minecproxy/server-rcon.c
@@ -32,14 +32,14 @@ static bool rcon_check_reply(struct uring_task *task, int res, int32_t *id,
const char *error;
if (res < 0) {
- error("rcon(%s): reading reply failed, res: %i", server->name,
- res);
+ error("rcon(%s): reading reply failed, res: %i",
+ server->scfg.name, res);
goto error;
}
if (!rcon_protocol_read_packet(task->tbuf->buf, task->tbuf->len, id,
type, msg, &error)) {
- error("rcon(%s): failed to parse packet: %s", server->name,
+ error("rcon(%s): failed to parse packet: %s", server->scfg.name,
error);
goto error;
}
@@ -66,10 +66,10 @@ static void rcon_stop_reply(struct uring_task *task, int res)
if (!rcon_protocol_verify_response(2, id, RCON_PACKET_COMMAND, type,
&error))
- error("rcon(%s): stop cmd failed - %s", server->name, error);
+ error("rcon(%s): stop cmd failed - %s", server->scfg.name, error);
else
verbose("rcon(%s): stop command sent, reply: %s",
- server->name, msg);
+ server->scfg.name, msg);
uring_task_close_fd(task);
}
@@ -83,12 +83,12 @@ static void rcon_stop_sent(struct uring_task *task, int res)
if (res != task->tbuf->len) {
error("rcon(%s): sending stop cmd failed, res: %i",
- server->name, res);
+ server->scfg.name, res);
uring_task_close_fd(task);
return;
}
- debug(DBG_RCON, "rcon(%s): stop cmd sent", server->name);
+ debug(DBG_RCON, "rcon(%s): stop cmd sent", server->scfg.name);
uring_tbuf_read_until(task, rcon_packet_complete, rcon_stop_reply);
}
@@ -107,11 +107,11 @@ static void rcon_login_reply(struct uring_task *task, int res)
if (!rcon_protocol_verify_response(1, id, RCON_PACKET_LOGIN, type,
&error)) {
- error("rcon(%s): login failed - %s", server->name, error);
+ error("rcon(%s): login failed - %s", server->scfg.name, error);
goto error;
}
- debug(DBG_RCON, "rcon(%s): login successful", server->name);
+ debug(DBG_RCON, "rcon(%s): login successful", server->scfg.name);
rcon_protocol_create_packet(task->tbuf->buf, sizeof(task->tbuf->buf),
&task->tbuf->len, 2, RCON_PACKET_COMMAND,
"stop");
@@ -130,13 +130,13 @@ static void rcon_login_sent(struct uring_task *task, int res)
assert_task_alive(DBG_RCON, task);
if (res != task->tbuf->len) {
- error("rcon(%s): sending login failed, res: %i", server->name,
+ error("rcon(%s): sending login failed, res: %i", server->scfg.name,
res);
uring_task_close_fd(task);
return;
}
- debug(DBG_RCON, "rcon(%s): login sent", server->name);
+ debug(DBG_RCON, "rcon(%s): login sent", server->scfg.name);
uring_tbuf_read_until(task, rcon_packet_complete, rcon_login_reply);
}
@@ -148,7 +148,7 @@ static void rcon_connected_cb(struct connection *conn, bool connected)
assert_task_alive(DBG_RCON, &server->rcon_task);
if (!connected) {
- error("rcon (%s): connection failed", server->name);
+ error("rcon (%s): connection failed", server->scfg.name);
return;
}
@@ -166,7 +166,7 @@ static void rcon_free(struct uring_task *task)
assert_return(task);
- debug(DBG_RCON, "task %p, server %s (%p)", task, server->name, server);
+ debug(DBG_RCON, "task %p, server %s (%p)", task, server->scfg.name, server);
}
void rcon_stop(struct server *server)
diff --git a/minecproxy/server.c b/minecproxy/server.c
index b1e9b05..7a992d1 100644
--- a/minecproxy/server.c
+++ b/minecproxy/server.c
@@ -46,9 +46,8 @@ static void server_free(struct uring_task *task)
assert_return(task);
- debug(DBG_SRV, "freeing server %s (%p)", server->name, server);
+ debug(DBG_SRV, "freeing server (%p)", server);
list_del(&server->list);
- xfree(server->name);
xfree(server);
}
@@ -59,7 +58,7 @@ void server_delete(struct server *server)
assert_return(server);
- verbose("Removing server %s", server->name);
+ verbose("Removing server %s", server->scfg.name);
server->state = SERVER_STATE_DEAD;
rcon_delete(server);
@@ -101,7 +100,7 @@ static void server_dump(struct server *server)
assert_return(server);
- verbose("Server %s:", server->name);
+ verbose("Server %s:", server->scfg.name);
verbose(" * Filename: %s", server->scfg.filename);
switch (server->scfg.type) {
case SERVER_TYPE_ANNOUNCE:
@@ -225,7 +224,7 @@ static bool server_check_running(struct server *server)
/* FIXME: other methods, rcon? */
if (server->scfg.systemd_service) {
verbose("%s: checking if systemd service is running",
- server->name);
+ server->scfg.name);
if (systemd_service_running(&server->scfg, &error)) {
server->state = SERVER_STATE_RUNNING;
return true;
@@ -246,12 +245,12 @@ bool server_start(struct server *server)
switch (server->scfg.start_method) {
case SERVER_START_METHOD_EXEC:
verbose("Starting server %s via external cmd",
- server->name);
+ server->scfg.name);
return server_exec(server, server->scfg.start_exec);
case SERVER_START_METHOD_SYSTEMD:
verbose("Starting server %s via systemd (%s)",
- server->name,
+ server->scfg.name,
server->scfg.systemd_service);
if (systemd_service_start(&server->scfg)) {
@@ -276,12 +275,12 @@ bool server_stop(struct server *server)
switch (server->scfg.stop_method) {
case SERVER_STOP_METHOD_EXEC:
verbose("Stopping server %s via external cmd",
- server->name);
+ server->scfg.name);
return server_exec(server, server->scfg.stop_exec);
case SERVER_STOP_METHOD_SYSTEMD:
verbose("Stopping server %s via systemd (%s)",
- server->name,
+ server->scfg.name,
server->scfg.systemd_service);
if (systemd_service_stop(&server->scfg)) {
server->state = SERVER_STATE_STOPPED;
@@ -290,7 +289,7 @@ bool server_stop(struct server *server)
return server_check_running(server);
case SERVER_STOP_METHOD_RCON:
- verbose("Stopping server %s via rcon", server->name);
+ verbose("Stopping server %s via rcon", server->scfg.name);
rcon_stop(server);
return true;
@@ -315,7 +314,7 @@ void server_update_active_players(struct server *server, int count)
assert_task_alive(DBG_IDLE, &server->idle_task);
debug(DBG_IDLE, "%s: currently %i active players",
- server->name, count);
+ server->scfg.name, count);
if (count < 0)
return;
@@ -327,7 +326,7 @@ void server_update_active_players(struct server *server, int count)
server->idle_count++;
if (server->idle_count > server->scfg.idle_timeout) {
- verbose("stopping idle server %s", server->name);
+ verbose("stopping idle server %s", server->scfg.name);
server_stop(server);
}
}
@@ -342,7 +341,7 @@ static void server_idle_connected_cb(struct connection *conn, bool connected)
if (!connected) {
debug(DBG_IDLE,
"idle check connection to remote server (%s) failed",
- server->name);
+ server->scfg.name);
server->idle_count = 0;
server->state = SERVER_STATE_STOPPED;
return;
@@ -390,11 +389,11 @@ static void server_announce_cb(struct uring_task *task, int res)
assert_return(task);
if (res < 0)
- error("%s: failure %i", server->name, res);
+ error("%s: failure %i", server->scfg.name, res);
else if (res == server->ann_buf.len)
- debug(DBG_ANN, "%s: ok (%i)", server->name, res);
+ debug(DBG_ANN, "%s: ok (%i)", server->scfg.name, res);
else
- debug(DBG_ANN, "%s: unexpected result: %i", server->name, res);
+ debug(DBG_ANN, "%s: unexpected result: %i", server->scfg.name, res);
uring_task_set_fd(&server->ann_task, -1);
}
@@ -410,7 +409,7 @@ bool server_announce(struct server *server, int fd)
server->state != SERVER_STATE_RUNNING))
return false;
- debug(DBG_ANN, "announcing server: %s", server->name);
+ debug(DBG_ANN, "announcing server: %s", server->scfg.name);
uring_task_set_fd(&server->ann_task, fd);
uring_tbuf_sendmsg(&server->ann_task, server_announce_cb);
return true;
@@ -422,12 +421,12 @@ bool server_commit(struct server *server)
struct saddr *saddr, *tmp;
int r;
- assert_return(server && server->name, false);
+ assert_return(server && server->scfg.name, false);
assert_task_alive_or(DBG_SRV, &server->task, return false);
if (!list_empty(&server->scfg.dnslookups)) {
debug(DBG_SRV, "%s: called with pending DNS requests",
- server->name);
+ server->scfg.name);
return false;
}
@@ -437,23 +436,23 @@ bool server_commit(struct server *server)
}
if (!list_empty(&server->proxys)) {
- error("%s: proxys not empty?", server->name);
+ error("%s: proxys not empty?", server->scfg.name);
return false;
}
if (!scfg_validate(&server->scfg, &error)) {
error("%s: failed to validate config file (%s)",
- server->name, error);
+ server->scfg.name, error);
server_delete(server);
return false;
}
r = snprintf(server->ann_buf.buf, sizeof(server->ann_buf.buf),
"[MOTD]%s[/MOTD][AD]%" PRIu16 "[/AD]",
- server->scfg.pretty_name ? server->scfg.pretty_name : server->name,
+ server->scfg.pretty_name ? server->scfg.pretty_name : server->scfg.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,
+ error("%s: unable to create announce msg: %i\n", server->scfg.name,
r);
return false;
}
@@ -469,14 +468,14 @@ bool server_commit(struct server *server)
local = local_new(server, saddr);
if (!local) {
error("%s: failed to create local listener",
- server->name);
+ server->scfg.name);
server_delete(server);
return false;
}
list_add(&local->list, &server->listenings);
if (!local_open(local)) {
error("%s: failed to open listening port",
- server->name);
+ server->scfg.name);
server_delete(server);
return false;
}
@@ -486,19 +485,18 @@ bool server_commit(struct server *server)
server_check_running(server);
- debug(DBG_SRV, "%s: success", server->name);
+ debug(DBG_SRV, "%s: success", server->scfg.name);
return true;
}
struct server *server_new(const char *filename)
{
struct server *server;
- const char *suffix;
assert_return(!empty_str(filename), NULL);
list_for_each_entry(server, &cfg->servers, list) {
- if (!streq(filename, server->name))
+ if (!streq(filename, server->scfg.filename))
continue;
error("attempt to add duplicate server: %s", filename);
return server;
@@ -511,29 +509,14 @@ struct server *server_new(const char *filename)
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;
- uring_task_init(&server->task, server->name, uring_parent(),
+ uring_task_init(&server->task, server->scfg.name, uring_parent(),
server_free);
uring_task_set_buf(&server->task, &server->tbuf);
diff --git a/minecproxy/server.h b/minecproxy/server.h
index 8058d42..41aaf41 100644
--- a/minecproxy/server.h
+++ b/minecproxy/server.h
@@ -15,7 +15,6 @@ enum server_state {
/* clang-format on */
struct server {
- char *name;
struct server_config scfg;
struct list_head listenings;
struct list_head proxys;
diff --git a/shared/config-parser.c b/shared/config-parser.c
index 8ea6557..4dc446c 100644
--- a/shared/config-parser.c
+++ b/shared/config-parser.c
@@ -529,29 +529,17 @@ bool scfg_parse(struct server_config *scfg, char *buf, bool async,
case SCFG_KEY_SYSTEMD_SERVICE:
if (scfg->systemd_service)
ERROR("systemd service defined multiple times");
- else {
- const char *suffix;
- char *tmp;
-
- suffix = strrchr(value.str, '.');
- if (!suffix || !streq(suffix, ".service")) {
- tmp = zmalloc(strlen(value.str) +
- STRLEN(".service") + 1);
- if (tmp)
- sprintf(tmp, "%s.service",
- value.str);
- } else
- tmp = xstrdup(value.str);
-
- if (!tmp)
- ERROR("malloc/strdup failure");
-
- scfg->systemd_service = tmp;
- scfg->systemd_obj =
- systemd_object_path(scfg->systemd_service);
- if (!scfg->systemd_obj)
- ERROR("failed to create object_path");
- }
+
+ const char *suffix = strrchr(value.str, '.');
+ if (!suffix || !streq(suffix, ".service"))
+ scfg->systemd_service = xsprintf(NULL,
+ "%s.service",
+ value.str);
+ else
+ scfg->systemd_service = xstrdup(value.str);
+
+ if (!scfg->systemd_service)
+ ERROR("malloc/strdup failure");
break;
@@ -563,6 +551,22 @@ bool scfg_parse(struct server_config *scfg, char *buf, bool async,
}
}
+ if (!scfg->systemd_service &&
+ (scfg->stop_method == SERVER_STOP_METHOD_SYSTEMD ||
+ scfg->start_method == SERVER_START_METHOD_SYSTEMD)) {
+ scfg->systemd_service = xsprintf(NULL,
+ "minecserver@%s.service",
+ scfg->name);
+ if (!scfg->systemd_service)
+ ERROR("failed to create systemd_service string");
+ }
+
+ if (scfg->systemd_service && !scfg->systemd_obj) {
+ scfg->systemd_obj = systemd_object_path(scfg->systemd_service);
+ if (!scfg->systemd_obj)
+ ERROR("failed to create object_path");
+ }
+
return true;
}
@@ -605,14 +609,31 @@ bool scfg_init(struct server_config *scfg, const char *filename)
assert_return(scfg, false);
if (filename) {
+ const char *suffix;
+
+ suffix = strrchr(filename, '.');
+ if (!suffix || suffix == filename) {
+ error("invalid filename: %s", filename);
+ return false;
+ }
+
+ scfg->name = xstrndup(filename, suffix - filename);
+ if (!scfg->name) {
+ error("xstrndup: %m");
+ return false;
+ }
+
scfg->filename = xstrdup(filename);
-
if (!scfg->filename) {
error("strdup: %m");
+ xfree(scfg->name);
+ scfg->name = NULL;
return false;
}
- } else
+ } else {
+ scfg->name = NULL;
scfg->filename = NULL;
+ }
scfg->type = SERVER_TYPE_UNDEFINED;
scfg->pretty_name = NULL;
diff --git a/shared/config-parser.h b/shared/config-parser.h
index da5250d..ad7e4b2 100644
--- a/shared/config-parser.h
+++ b/shared/config-parser.h
@@ -35,6 +35,7 @@ enum server_announce {
};
struct server_config {
+ char *name;
char *filename;
enum server_type type;
char *pretty_name;
diff --git a/shared/utils.c b/shared/utils.c
index 9bf8cd8..99fcaa3 100644
--- a/shared/utils.c
+++ b/shared/utils.c
@@ -13,6 +13,7 @@
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <inttypes.h>
+#include <stdarg.h>
#include "utils.h"
@@ -218,3 +219,36 @@ int strtou16_strict(const char *str, uint16_t *result)
*result = val;
return 0;
}
+
+char *xsprintf(size_t *rlen, const char *fmt, ...)
+{
+ va_list ap;
+ int len;
+ char *str;
+
+ va_start(ap, fmt);
+ len = vsnprintf(NULL, 0, fmt, ap);
+ va_end(ap);
+
+ if (len < 0)
+ return NULL;
+
+ len++;
+ str = zmalloc(len);
+ if (!str)
+ return NULL;
+
+ va_start(ap, fmt);
+ len = vsnprintf(str, len, fmt, ap);
+ va_end(ap);
+
+ if (len < 0) {
+ xfree(str);
+ return NULL;
+ }
+
+ if (rlen)
+ *rlen = len;
+
+ return str;
+}
diff --git a/shared/utils.h b/shared/utils.h
index bf1b63a..1291d21 100644
--- a/shared/utils.h
+++ b/shared/utils.h
@@ -89,6 +89,8 @@ void saddr_set_addrstr(struct saddr *saddr);
int strtou16_strict(const char *str, uint16_t *result);
+char *xsprintf(size_t *rlen, const char *fmt, ...) _printf_(2, 3);
+
static inline bool empty_str(const char *str)
{
if (!str || str[0] == '\0')