From 8c27290245b7bcc7cd2f72f3b4a7562294b43bbe Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Tue, 23 Jun 2020 16:25:36 +0200 Subject: Split directories better --- server.c | 837 --------------------------------------------------------------- 1 file changed, 837 deletions(-) delete mode 100644 server.c (limited to 'server.c') diff --git a/server.c b/server.c deleted file mode 100644 index de42721..0000000 --- a/server.c +++ /dev/null @@ -1,837 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "main.h" -#include "uring.h" -#include "ptimer.h" -#include "server.h" -#include "server-proxy.h" -#include "server-rcon.h" -#include "utils.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; - struct server_proxy *proxy; - - assert_return(server); - - uring_task_refdump(&server->task); - 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) - local_refdump(local); - list_for_each_entry(proxy, &server->proxys, list) - proxy_refdump(proxy); - rcon_refdump(server); -} - -static void -server_free(struct uring_task *task) -{ - struct server *server = container_of(task, struct server, task); - - assert_return(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); -} - -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); - - verbose("Removing server %s", server->name); - server->state = SERVER_STATE_DEAD; - - rcon_delete(server); - - list_for_each_entry_safe(local, ltmp, &server->locals, 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); -} - -void -server_delete_by_name(const char *name) -{ - struct server *server; - - assert_return(!empty_str(name)); - - list_for_each_entry(server, &cfg->servers, list) { - if (streq(server->name, name)) { - server_delete(server); - return; - } - } -} - -static void -server_dump(struct server *server) -{ - struct server_local *local; - struct saddr *remote; - struct saddr *rcon; - - assert_return(server); - - verbose("Server %s:", server->name); - switch (server->type) { - case SERVER_TYPE_ANNOUNCE: - verbose(" * Type: announce"); - break; - case SERVER_TYPE_PROXY: - verbose(" * Type: proxy"); - break; - default: - verbose(" * Type: unknown"); - break; - } - verbose(" * Name: %s", server->pretty_name ? server->pretty_name : ""); - verbose(" * Announce port: %" PRIu16, server->announce_port); - - if (!list_empty(&server->locals)) { - verbose(" * Local:"); - list_for_each_entry(local, &server->locals, list) - verbose(" * %s", local->local.addrstr); - } - - if (!list_empty(&server->remotes)) { - verbose(" * Remote:"); - list_for_each_entry(remote, &server->remotes, list) - verbose(" * %s", remote->addrstr); - } - - if (!list_empty(&server->rcons)) { - verbose(" * RCon:"); - list_for_each_entry(rcon, &server->rcons, list) - verbose(" * %s", rcon->addrstr); - } - - verbose(""); -} - -static void -server_exec_free(struct uring_task *task) -{ - assert_return(task); - - debug(DBG_SRV, "called"); -} - -#ifndef P_PIDFD -#define P_PIDFD 3 -#endif - -/* FIXME: update states */ -static void -server_exec_done(struct uring_task *task, int res) -{ - struct server *server = container_of(task, struct server, exec_task); - int r; - siginfo_t info; - - assert_return(task); - assert_task_alive_or(DBG_SRV, task, goto out); - /* Should we leave child processes running? */ - - if (!(res & POLLIN)) { - error("unexpected result: %i", res); - goto out; - } - - r = waitid(P_PIDFD, server->exec_task.fd, &info, WEXITED); - if (r < 0) { - error("waitid: %m"); - goto out; - } - - if (info.si_status == 0) - debug(DBG_SRV, "command successfully executed"); - else - error("command failed: %i", info.si_status); - -out: - uring_task_close_fd(&server->exec_task); -} - -static int -server_exec_child(void *ptr) -{ - const char *cmd = ptr; - - assert_return(ptr, EINVAL); - - execl(cmd, cmd, NULL); - return errno; -} - -#ifndef CLONE_PIDFD -#define CLONE_PIDFD 0x00001000 -#endif - -static bool -server_exec(struct server *server, const char *cmd) -{ - char stack[4096]; /* Beautiful/horrible hack :) */ - int pidfd; - int r; - - assert_return(server && cmd && server->exec_task.fd < 1, false); - - r = clone(server_exec_child, stack + sizeof(stack), - CLONE_VM | CLONE_VFORK | CLONE_PIDFD | SIGCHLD, - (void *)cmd, &pidfd); - if (r < 0) { - error("clone: %m: %i", r); - return false; - } - - uring_task_set_fd(&server->exec_task, pidfd); - uring_poll(&server->exec_task, POLLIN, server_exec_done); - return true; -} - -static bool -server_check_running(struct server *server) -{ - assert_return(server, false); - - /* FIXME: other methods, rcon? */ - if (server->systemd_service) { - verbose("%s: checking if systemd service is running", server->name); - if (systemd_service_running(server)) { - server->state = SERVER_STATE_RUNNING; - return true; - } else { - server->state = SERVER_STATE_STOPPED; - return false; - } - } - - return false; -} - -bool -server_start(struct server *server) -{ - assert_return(server, false); - assert_task_alive_or(DBG_SRV, &server->task, return false); - - switch (server->start_method) { - - case SERVER_START_METHOD_EXEC: - verbose("Starting server %s via external cmd", server->name); - return server_exec(server, server->start_exec); - - case SERVER_START_METHOD_SYSTEMD: - verbose("Starting server %s via systemd (%s)", - server->name, server->systemd_service); - - if (systemd_service_start(server)) { - server->state = SERVER_STATE_RUNNING; - return true; - } else - return server_check_running(server); - - case SERVER_START_METHOD_UNDEFINED: - default: - break; - } - - return false; -} - -bool -server_stop(struct server *server) -{ - assert_return(server, false); - assert_task_alive_or(DBG_SRV, &server->task, return false); - - switch (server->stop_method) { - - case SERVER_STOP_METHOD_EXEC: - verbose("Stopping server %s via external cmd", server->name); - return server_exec(server, server->stop_exec); - - case SERVER_STOP_METHOD_SYSTEMD: - verbose("Stopping server %s via systemd (%s)", - server->name, server->systemd_service); - if (systemd_service_stop(server)) { - server->state = SERVER_STATE_STOPPED; - return true; - } else - return server_check_running(server); - - case SERVER_STOP_METHOD_RCON: - verbose("Stopping server %s via rcon", server->name); - rcon_stop(server); - return true; - - case SERVER_STOP_METHOD_UNDEFINED: - default: - break; - } - - return false; -} - -static void -server_idle_free(struct uring_task *task) -{ - assert_return(task); - - debug(DBG_ANN, "called"); -} - -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); - - if (count < 0) - return; - - server->state = SERVER_STATE_RUNNING; - if (count > 0) - server->idle_count = 0; - else if (count == 0) - server->idle_count++; - - if (server->idle_count > server->idle_timeout) { - verbose("stopping idle server %s", server->name); - server_stop(server); - } -} - -static void -server_idle_connected_cb(struct connection *conn, bool connected) -{ - struct server *server = container_of(conn, struct server, idle_conn); - - assert_return(conn); - assert_task_alive(DBG_IDLE, &server->idle_task); - - if (!connected) { - debug(DBG_IDLE, - "idle check connection to remote server (%s) failed", - server->name); - server->idle_count = 0; - server->state = SERVER_STATE_STOPPED; - return; - } - - debug(DBG_IDLE, "connected to remote %s\n", conn->remote.addrstr); - idle_check_get_player_count(server, conn); -} - -bool -server_idle_check(struct server *server) -{ - assert_return(server, false); - - if (server->state == SERVER_STATE_INIT || - server->state == SERVER_STATE_DEAD) - return false; - - if (server->idle_timeout < 1) - return false; - - if (list_empty(&server->remotes)) - return false; - - if (!list_empty(&server->proxys)) { - server->idle_count = 0; - return true; - } - - connect_any(&server->idle_task, &server->remotes, - &server->idle_conn, server_idle_connected_cb); - return true; -} - -static void -server_announce_free(struct uring_task *task) -{ - assert_return(task); - - debug(DBG_ANN, "called"); -} - -static void -server_announce_cb(struct uring_task *task, int res) -{ - struct server *server = container_of(task, struct server, ann_task); - - assert_return(task); - - if (res < 0) - error("%s: failure %i", server->name, res); - else if (res == server->ann_buf.len) - debug(DBG_ANN, "%s: ok (%i)", server->name, res); - else - debug(DBG_ANN, "%s: unexpected result: %i", server->name, res); - - uring_task_set_fd(&server->ann_task, -1); -} - -bool -server_announce(struct server *server, int fd) -{ - assert_return(server && fd >= 0, false); - - if (server->state == SERVER_STATE_INIT || - server->state == SERVER_STATE_DEAD) - return false; - - debug(DBG_ANN, "announcing server: %s", server->name); - uring_task_set_fd(&server->ann_task, fd); - uring_tbuf_sendmsg(&server->ann_task, server_announce_cb); - return true; -} - -bool -server_commit(struct server *server) -{ - struct server_local *local; - uint16_t port; - int r; - - assert_return(server && server->name, false); - assert_task_alive_or(DBG_SRV, &server->task, return false); - - if (server->state != SERVER_STATE_INIT) { - error("called in wrong state"); - return false; - } - - if (!list_empty(&server->proxys)) { - error("%s: proxys not empty?", server->name); - return false; - } - - if (!list_empty(&server->dnslookups)) { - debug(DBG_SRV, "called with pending DNS requests"); - return true; - } - - if (server->stop_method == SERVER_STOP_METHOD_RCON && - list_empty(&server->rcons)) { - error("%s: rcon stop method missing rcon address", - server->name); - return false; - } - - if (server->stop_method == SERVER_STOP_METHOD_RCON && - !server->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) { - 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->idle_timeout > 0 && - server->stop_method == SERVER_STOP_METHOD_UNDEFINED) { - error("%s: idle_timeout set but missing stop method", server->name); - return false; - } - - switch (server->type) { - case SERVER_TYPE_ANNOUNCE: - if (server->announce_port < 1) { - error("%s: missing announce port", server->name); - return false; - } - - if (server->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)) { - error("%s: can't set local addresses for announce server", server->name); - return false; - } - - if (!list_empty(&server->remotes)) { - error("%s: can't set remote addresses for announce server", server->name); - return false; - } - - break; - - case SERVER_TYPE_PROXY: - if (server->announce_port >= 1) { - error("%s: can't set announce port for proxy server", server->name); - return false; - } - - if (list_empty(&server->locals)) { - error("%s: missing local addresses for proxy server", server->name); - return false; - } - - if (list_empty(&server->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); - - if (port == 0) { - error("%s: invalid local port", server->name); - return false; - } - - if (server->announce_port < 1) - server->announce_port = port; - - if (server->announce_port != port) { - error("%s: multiple local ports", server->name); - return false; - } - } - - if (server->announce_port < 1) { - error("%s: can't determine which port to announce", server->name); - return false; - } - - break; - - default: - error("%s: can't determine server type", server->name); - return false; - } - - if (!server->pretty_name) { - char *suffix; - - suffix = strrchr(server->name, '.'); - if (!suffix || suffix == server->name) { - error("invalid server name: %s", server->name); - return false; - } - - server->pretty_name = xstrndup(server->name, suffix - server->name); - if (!server->pretty_name) { - error("failed to create display name: %s", server->name); - return false; - } - } - - r = snprintf(server->ann_buf.buf, sizeof(server->ann_buf.buf), - "[MOTD]%s[/MOTD][AD]%" PRIu16 "[/AD]", - server->pretty_name, server->announce_port); - if (r < 1 || r >= sizeof(server->ann_buf.buf)) { - error("%s: unable to create announce msg: %i\n", server->name, r); - return false; - } - server->ann_buf.len = r; - - /* FIXME: config, dont reread config if server running, make sure fd is available before this is called */ - server_dump(server); - - list_for_each_entry(local, &server->locals, list) - local_open(local); - - server->state = SERVER_STATE_CFG_OK; - - server_check_running(server); - - debug(DBG_SRV, "success"); - 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; - - assert_return(!empty_str(name), NULL); - - list_for_each_entry(server, &cfg->servers, list) { - if (!streq(name, server->name)) - continue; - error("attempt to add duplicate server: %s", name); - return server; - } - - verbose("Adding server %s", name); - server = zmalloc(sizeof(*server)); - if (!server) { - error("malloc: %m"); - 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); - uring_task_set_buf(&server->task, &server->tbuf); - - uring_task_init(&server->ann_task, "announce", &server->task, server_announce_free); - uring_task_set_buf(&server->ann_task, &server->ann_buf); - saddr_set_ipv4(&server->ann_task.saddr, cinet_addr(224,0,2,60), htons(4445)); - - uring_task_init(&server->exec_task, "exec", &server->task, server_exec_free); - - uring_task_init(&server->idle_task, "idle", &server->task, server_idle_free); - uring_task_set_buf(&server->idle_task, &server->idle_buf); - - rcon_init(server); - - list_init(&server->remotes); - list_init(&server->locals); - list_init(&server->proxys); - list_init(&server->rcons); - list_init(&server->dnslookups); - list_add(&server->list, &cfg->servers); - - return server; -} -- cgit v1.2.3