summaryrefslogtreecommitdiff
path: root/cfgdir.c
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-22 12:00:05 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-22 12:00:05 +0200
commit77071eb45391c9f0bbc593bcf2c10605ed1d5d17 (patch)
treecf1bd5d9d39c77dfc2fc84b98fcf3b5ace4eb989 /cfgdir.c
parentf2489c89e95c07495768b5401b63ba31ec39d72d (diff)
Rename proxy and cfgdir to more descriptive names
Diffstat (limited to 'cfgdir.c')
-rw-r--r--cfgdir.c576
1 files changed, 0 insertions, 576 deletions
diff --git a/cfgdir.c b/cfgdir.c
deleted file mode 100644
index ec8a0bf..0000000
--- a/cfgdir.c
+++ /dev/null
@@ -1,576 +0,0 @@
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdbool.h>
-#include <sys/inotify.h>
-#include <dirent.h>
-#include <errno.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <inttypes.h>
-
-#include "main.h"
-#include "uring.h"
-#include "cfgdir.h"
-#include "config.h"
-#include "server.h"
-
-static void
-scfg_dns_cb(struct dns_async *dns, bool (*server_cb)(struct server *, struct saddr *))
-{
- struct server *server;
- struct sockaddr_in *in4;
- struct sockaddr_in6 *in6;
- struct saddr *saddr;
- struct addrinfo *results = NULL, *ai;
- int r;
-
- assert_return(dns && dns->priv && server_cb);
-
- server = dns->priv;
- debug(DBG_DNS, "called, dns: %p, name: %s, server: %p, server->name: %s",
- dns, dns->name, server, server->name);
-
- r = gai_error(&dns->gcb);
- if (r == EAI_INPROGRESS) {
- /* This shouldn't happen, assume we'll get called again */
- error("called with request in progress");
- return;
- } else if (r == EAI_CANCELED) {
- /* The server must be in the process of going away */
- goto out;
- } else if (r < 0) {
- error("DNS lookup of %s:%s failed: %s",
- dns->name, dns->port, gai_strerror(r));
- goto out;
- }
-
- results = dns->gcb.ar_result;
-
- for (ai = results; ai; ai = ai->ai_next) {
- saddr = zmalloc(sizeof(*saddr));
- if (!saddr) {
- error("DNS lookup of %s:%s failed: %m", dns->name, dns->port);
- goto out;
- }
-
- switch (ai->ai_family) {
- case AF_INET:
- in4 = (struct sockaddr_in *)ai->ai_addr;
- saddr_set_ipv4(saddr, in4->sin_addr.s_addr, in4->sin_port);
- server_cb(server, saddr);
- break;
-
- case AF_INET6:
- in6 = (struct sockaddr_in6 *)ai->ai_addr;
- saddr_set_ipv6(saddr, &in6->sin6_addr, in6->sin6_port);
- server_cb(server, saddr);
- break;
-
- default:
- error("getaddrinfo(%s:%s): unknown address family (%i)",
- dns->name, dns->port, ai->ai_family);
- xfree(saddr);
- break;
- }
- }
-
-out:
- freeaddrinfo(results);
- list_del(&dns->list);
- xfree(dns);
- uring_task_put(&server->task);
- server_commit(server);
-}
-
-static void
-scfg_local_dns_cb(struct dns_async *dns)
-{
- assert_return(dns);
-
- scfg_dns_cb(dns, server_add_local);
-}
-
-static void
-scfg_remote_dns_cb(struct dns_async *dns)
-{
- assert_return(dns);
-
- scfg_dns_cb(dns, server_add_remote);
-}
-
-static void
-scfg_rcon_dns_cb(struct dns_async *dns)
-{
- assert_return(dns);
-
- scfg_dns_cb(dns, server_add_rcon);
-}
-
-enum scfg_keys {
- SCFG_KEY_INVALID = 0,
- SCFG_KEY_TYPE,
- SCFG_KEY_NAME,
- SCFG_KEY_PORT,
- SCFG_KEY_LOCAL,
- SCFG_KEY_REMOTE,
- SCFG_KEY_IDLE_TIMEOUT,
- SCFG_KEY_STOP_METHOD,
- SCFG_KEY_START_METHOD,
- SCFG_KEY_STOP_EXEC,
- SCFG_KEY_START_EXEC,
- SCFG_KEY_RCON,
- SCFG_KEY_RCON_PASSWORD,
- SCFG_KEY_SYSTEMD_SERVICE,
-};
-
-struct cfg_key_value_map scfg_key_map[] = {
- {
- .key_name = "type",
- .key_value = SCFG_KEY_TYPE,
- .value_type = CFG_VAL_TYPE_STRING,
- }, {
- .key_name = "name",
- .key_value = SCFG_KEY_NAME,
- .value_type = CFG_VAL_TYPE_STRING,
- }, {
- .key_name = "port",
- .key_value = SCFG_KEY_PORT,
- .value_type = CFG_VAL_TYPE_UINT16,
- }, {
- .key_name = "local",
- .key_value = SCFG_KEY_LOCAL,
- .value_type = CFG_VAL_TYPE_ASYNC_ADDRS,
- }, {
- .key_name = "remote",
- .key_value = SCFG_KEY_REMOTE,
- .value_type = CFG_VAL_TYPE_ASYNC_ADDRS,
- }, {
- .key_name = "idle_timeout",
- .key_value = SCFG_KEY_IDLE_TIMEOUT,
- .value_type = CFG_VAL_TYPE_UINT16,
- }, {
- .key_name = "stop_method",
- .key_value = SCFG_KEY_STOP_METHOD,
- .value_type = CFG_VAL_TYPE_STRING,
- }, {
- .key_name = "start_method",
- .key_value = SCFG_KEY_START_METHOD,
- .value_type = CFG_VAL_TYPE_STRING,
- }, {
- .key_name = "stop_exec",
- .key_value = SCFG_KEY_STOP_EXEC,
- .value_type = CFG_VAL_TYPE_STRING,
- }, {
- .key_name = "start_exec",
- .key_value = SCFG_KEY_START_EXEC,
- .value_type = CFG_VAL_TYPE_STRING,
- }, {
- .key_name = "rcon",
- .key_value = SCFG_KEY_RCON,
- .value_type = CFG_VAL_TYPE_ASYNC_ADDRS,
- }, {
- .key_name = "rcon_password",
- .key_value = SCFG_KEY_RCON_PASSWORD,
- .value_type = CFG_VAL_TYPE_STRING,
- }, {
- .key_name = "systemd_service",
- .key_value = SCFG_KEY_SYSTEMD_SERVICE,
- .value_type = CFG_VAL_TYPE_STRING,
- }, {
- .key_name = NULL,
- .key_value = SCFG_KEY_INVALID,
- .value_type = CFG_VAL_TYPE_INVALID,
- }
-};
-
-static bool
-handle_dns(struct server *server, const char *type,
- struct cfg_value *value, dns_cb_t *async_cb,
- bool (*sync_cb)(struct server *, struct saddr *))
-{
- struct saddr *saddr, *tmp;
- struct dns_async *dns;
-
- assert_return(server && type && value && async_cb && sync_cb, false);
-
- switch (value->type) {
- case CFG_VAL_TYPE_ADDRS:
- debug(DBG_DNS, "%s: got immediate addrs", type);
-
- list_for_each_entry_safe(saddr, tmp, &value->saddrs, list) {
- list_del(&saddr->list);
- sync_cb(server, saddr);
- }
- return true;
-
- case CFG_VAL_TYPE_ASYNC_ADDRS:
- debug(DBG_DNS, "%s: doing async lookup of DNS record: %p",
- type, value->dns_async);
-
- dns = value->dns_async;
- dns->cb = async_cb;
- dns->priv = server;
- list_add(&dns->list, &server->dnslookups);
- uring_task_get(&server->task);
- return true;
-
- default:
- return false;
- }
-}
-
-static void
-scfg_parse(struct server *server)
-{
- char *pos;
-
- assert_return(server);
-
- pos = server->tbuf.buf;
-
- if (!config_parse_header(server->name, "server", &pos))
- return;
-
- while (true) {
- int key;
- const char *keyname;
- struct cfg_value value;
-
- if (!config_parse_line(server->name, &pos, scfg_key_map,
- &key, &keyname, &value))
- break;
-
- if (key == SCFG_KEY_INVALID)
- break;
-
- debug(DBG_CFG, "%s: key %s", server->name, keyname);
-
- switch (key) {
-
- case SCFG_KEY_TYPE:
- if (streq(value.str, "proxy")) {
- if (!server_set_type(server, SERVER_TYPE_PROXY))
- return;
- } else if (streq(value.str, "announce")) {
- if (!server_set_type(server, SERVER_TYPE_ANNOUNCE))
- return;
- }
- break;
-
- case SCFG_KEY_NAME:
- if (!server_set_pretty_name(server, value.str))
- return;
- break;
-
- case SCFG_KEY_PORT:
- if (!server_set_port(server, value.uint16))
- return;
- break;
-
- case SCFG_KEY_LOCAL:
- if (!handle_dns(server, "local", &value,
- scfg_local_dns_cb, server_add_local))
- return;
- break;
-
- case SCFG_KEY_REMOTE:
- if (!handle_dns(server, "remote", &value,
- scfg_remote_dns_cb, server_add_remote))
- return;
- break;
-
- case SCFG_KEY_IDLE_TIMEOUT:
- if (!server_set_idle_timeout(server, value.uint16))
- return;
- break;
-
- case SCFG_KEY_STOP_METHOD:
- if (streq(value.str, "exec")) {
- if (server_set_stop_method(server, SERVER_STOP_METHOD_EXEC))
- break;
- } else if (streq(value.str, "rcon")) {
- if (server_set_stop_method(server, SERVER_STOP_METHOD_RCON))
- break;
- } else if (streq(value.str, "systemd")) {
- if (server_set_stop_method(server, SERVER_STOP_METHOD_SYSTEMD))
- break;
- }
- return;
-
- case SCFG_KEY_START_METHOD:
- if (streq(value.str, "exec")) {
- if (server_set_start_method(server, SERVER_START_METHOD_EXEC))
- break;
- } else if (streq(value.str, "systemd")) {
- if (server_set_start_method(server, SERVER_START_METHOD_SYSTEMD))
- break;
- }
- return;
-
- case SCFG_KEY_STOP_EXEC:
- if (!server_set_stop_exec(server, value.str))
- return;
- break;
-
- case SCFG_KEY_START_EXEC:
- if (!server_set_start_exec(server, value.str))
- return;
- break;
-
- case SCFG_KEY_RCON:
- if (!handle_dns(server, "rcon", &value,
- scfg_rcon_dns_cb, server_add_rcon))
- return;
- break;
-
- case SCFG_KEY_RCON_PASSWORD:
- if (!server_set_rcon_password(server, value.str))
- return;
- break;
-
- case SCFG_KEY_SYSTEMD_SERVICE:
- if (!server_set_systemd_service(server, value.str))
- return;
- break;
-
- case SCFG_KEY_INVALID:
- default:
- break;
- }
- }
-}
-
-static void
-scfg_read_cb(struct uring_task *task, int res)
-{
- struct server *server = container_of(task, struct server, task);
-
- assert_return(task);
- assert_task_alive(DBG_CFG, task);
-
- if (res <= 0) {
- error("error reading config file for %s: %s",
- server->name, strerror(-res));
- server_delete(server);
- }
-
- debug(DBG_CFG, "%s: parsing cfg (%i bytes)", server->name, res);
- uring_task_close_fd(&server->task);
- scfg_parse(server);
- server_commit(server);
-}
-
-static void
-scfg_open_cb(struct uring_task *task, int res)
-{
- struct server *server = container_of(task, struct server, task);
-
- assert_return(task);
- assert_task_alive(DBG_CFG, task);
-
- if (res < 0) {
- error("open(%s) failed: %s", server->name, strerror(-res));
- server_delete(server);
- return;
- }
-
- debug(DBG_CFG, "reading server cfg %s (fd %i)", server->name, res);
- uring_task_set_fd(&server->task, res);
- uring_tbuf_read_until_eof(&server->task, scfg_read_cb);
-}
-
-static bool
-scfg_valid_filename(const char *name)
-{
- const char *suffix;
-
- if (empty_str(name))
- return false;
- if (name[0] == '.')
- return false;
- if ((suffix = strrchr(name, '.')) == NULL)
- return false;
- if (!streq(suffix, ".server"))
- return false;
-
- return true;
-}
-
-struct inotify_ev {
- struct uring_task task;
- char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event))));
-};
-
-static void
-inotify_free(struct uring_task *task)
-{
- struct inotify_ev *iev = container_of(task, struct inotify_ev, task);
-
- assert_return(task);
-
- debug(DBG_CFG, "called");
- xfree(iev);
- cfg->iev = NULL;
-}
-
-static void
-inotify_event_dump(const struct inotify_event *event)
-{
- assert_return(event);
-
- debug(DBG_CFG, "inotify event:");
- debug(DBG_CFG, " * WD : %i", event->wd);
- debug(DBG_CFG, " * Cookie : %" PRIu32, event->cookie);
- debug(DBG_CFG, " * Length : %" PRIu32, event->len);
- debug(DBG_CFG, " * Name : %s", event->name);
- debug(DBG_CFG, " * Mask : %" PRIu32, event->mask);
- if (event->mask & IN_ACCESS)
- debug(DBG_CFG, "\tIN_ACCESS");
- else if(event->mask & IN_MODIFY)
- debug(DBG_CFG, "\tIN_MODIFY");
- else if(event->mask & IN_ATTRIB)
- debug(DBG_CFG, "\tIN_ATTRIB");
- else if(event->mask & IN_CLOSE_WRITE)
- debug(DBG_CFG, "\tIN_CLOSE_WRITE");
- else if(event->mask & IN_CLOSE_NOWRITE)
- debug(DBG_CFG, "\tIN_CLOSE_NOWRITE");
- else if(event->mask & IN_OPEN)
- debug(DBG_CFG, "\tIN_OPEN");
- else if(event->mask & IN_MOVED_FROM)
- debug(DBG_CFG, "\tIN_MOVED_FROM");
- else if(event->mask & IN_MOVED_TO)
- debug(DBG_CFG, "\tIN_MOVED_TO");
- else if(event->mask & IN_CREATE)
- debug(DBG_CFG, "\tIN_CREATE");
- else if(event->mask & IN_DELETE)
- debug(DBG_CFG, "\tIN_DELETE");
- else if(event->mask & IN_DELETE_SELF)
- debug(DBG_CFG, "\tIN_DELETE_SELF");
- else if(event->mask & IN_MOVE_SELF)
- debug(DBG_CFG, "\tIN_MOVE_SELF");
- else if(event->mask & IN_UNMOUNT)
- debug(DBG_CFG, "\tIN_UNMOUNT");
- else if(event->mask & IN_Q_OVERFLOW)
- debug(DBG_CFG, "\tIN_Q_OVERFLOW");
- else if(event->mask & IN_IGNORED)
- debug(DBG_CFG, "\tIN_IGNORED");
-}
-
-static void
-inotify_cb(struct uring_task *task, int res)
-{
- struct inotify_ev *iev = container_of(task, struct inotify_ev, task);
- const struct inotify_event *event;
- char *ptr;
- struct server *server;
-
- assert_return(task);
- assert_task_alive(DBG_CFG, task);
-
- if (res <= 0) {
- error("inotify_read: %i", res);
- return;
- }
-
- for (ptr = iev->buf; ptr < iev->buf + res; ptr += sizeof(struct inotify_event) + event->len) {
- event = (const struct inotify_event *)ptr;
-
- if (debug_enabled(DBG_CFG))
- inotify_event_dump(event);
-
- if (event->mask & (IN_IGNORED | IN_MOVE_SELF | IN_DELETE_SELF | IN_UNMOUNT))
- die("configuration directory gone, exiting");
-
- if (event->mask & IN_Q_OVERFLOW) {
- error("inotify queue overflow");
- continue;
- }
-
- if (!scfg_valid_filename(event->name))
- continue;
-
- if (event->mask & (IN_MOVED_FROM | IN_DELETE))
- server_delete_by_name(event->name);
- else if (event->mask & (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, scfg_open_cb);
- } else
- error("inotify: unknown event: 0x%08x", event->mask);
- }
-
- uring_read(&iev->task, iev->buf, sizeof(iev->buf), inotify_cb);
-}
-
-void
-cfgdir_refdump()
-{
- assert_return_silent(cfg->iev);
-
- uring_task_refdump(&cfg->iev->task);
-}
-
-void
-cfgdir_delete()
-{
- assert_return(cfg->iev);
-
- debug(DBG_CFG, "closing fd %i", cfg->iev->task.fd);
- uring_task_destroy(&cfg->iev->task);
- cfg->iev = NULL;
-}
-
-void
-cfgdir_init()
-{
- int ifd;
- int iwd;
- struct inotify_ev *iev;
- DIR *dir;
- struct dirent *dent;
- struct server *server;
-
- assert_return(!cfg->iev);
-
- iev = zmalloc(sizeof(*iev));
- if (!iev)
- die("malloc: %m");
-
- ifd = inotify_init1(IN_CLOEXEC);
- if (ifd < 0)
- die("inotify_init1: %m");
-
- /* ln = IN_CREATE, cp/vi/mv = IN_CREATE, IN_OPEN, IN_CLOSE_WRITE */
- iwd = inotify_add_watch(ifd, ".",
- IN_CLOSE_WRITE | IN_DELETE | IN_CREATE |
- IN_DELETE_SELF | IN_MOVE_SELF | IN_MOVED_TO |
- IN_MOVED_FROM | IN_DONT_FOLLOW |
- IN_EXCL_UNLINK | IN_ONLYDIR );
- if (iwd < 0)
- die("inotify_add_watch: %m");
-
- uring_task_init(&iev->task, "server_config", uring_parent(), inotify_free);
- uring_task_set_fd(&iev->task, ifd);
- cfg->iev = iev;
- uring_read(&iev->task, iev->buf, sizeof(iev->buf), inotify_cb);
-
- dir = opendir(".");
- if (!dir)
- die("opendir(%s): %m", cfg->homedir);
-
- while ((dent = readdir(dir)) != NULL) {
- if (dent->d_type != DT_REG && dent->d_type != DT_UNKNOWN)
- continue;
- if (!scfg_valid_filename(dent->d_name))
- continue;
-
- server = server_new(dent->d_name);
- if (server)
- uring_openat(&server->task, server->name, scfg_open_cb);
- }
-
- closedir(dir);
-}
-