summaryrefslogtreecommitdiff
path: root/mcserverproxy
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-23 20:56:22 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-23 20:56:22 +0200
commitea053d96f7e89e053d4af8d39b04c5428760345f (patch)
tree8182ca73675ad3933b0f38cb48a99c69101309b4 /mcserverproxy
parent8c27290245b7bcc7cd2f72f3b4a7562294b43bbe (diff)
Big renaming, move some more functionality to shared lib
Diffstat (limited to 'mcserverproxy')
-rw-r--r--mcserverproxy/announce.c116
-rw-r--r--mcserverproxy/announce.h14
-rw-r--r--mcserverproxy/config-parser.c490
-rw-r--r--mcserverproxy/config-parser.h59
-rw-r--r--mcserverproxy/idle.c378
-rw-r--r--mcserverproxy/idle.h13
-rw-r--r--mcserverproxy/igmp.c587
-rw-r--r--mcserverproxy/igmp.h10
-rw-r--r--mcserverproxy/main.c740
-rw-r--r--mcserverproxy/main.h175
-rw-r--r--mcserverproxy/meson.build36
-rw-r--r--mcserverproxy/ptimer.c223
-rw-r--r--mcserverproxy/ptimer.h33
-rw-r--r--mcserverproxy/server-config.c580
-rw-r--r--mcserverproxy/server-config.h10
-rw-r--r--mcserverproxy/server-proxy.c578
-rw-r--r--mcserverproxy/server-proxy.h51
-rw-r--r--mcserverproxy/server-rcon.c227
-rw-r--r--mcserverproxy/server-rcon.h12
-rw-r--r--mcserverproxy/server.c837
-rw-r--r--mcserverproxy/server.h128
-rw-r--r--mcserverproxy/signal-handler.c195
-rw-r--r--mcserverproxy/signal-handler.h8
-rw-r--r--mcserverproxy/systemd.c219
-rw-r--r--mcserverproxy/systemd.h14
-rw-r--r--mcserverproxy/uring.c759
-rw-r--r--mcserverproxy/uring.h73
-rw-r--r--mcserverproxy/utils.c430
-rw-r--r--mcserverproxy/utils.h245
29 files changed, 0 insertions, 7240 deletions
diff --git a/mcserverproxy/announce.c b/mcserverproxy/announce.c
deleted file mode 100644
index 13ef423..0000000
--- a/mcserverproxy/announce.c
+++ /dev/null
@@ -1,116 +0,0 @@
-#include <inttypes.h>
-#include <sys/socket.h>
-#include <netinet/ip.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "main.h"
-#include "uring.h"
-#include "announce.h"
-#include "server.h"
-#include "ptimer.h"
-
-struct announce {
- uint64_t value;
- struct uring_task task;
- struct ptimer_task ptask;
- int mcast_fd;
-};
-
-static void
-announce_cb(struct ptimer_task *ptask)
-{
- struct announce *announce = container_of(ptask, struct announce, ptask);
- struct server *server;
-
- assert_return(ptask);
- assert_task_alive(DBG_ANN, &announce->task);
-
- debug(DBG_ANN, "announcing servers");
- list_for_each_entry(server, &cfg->servers, list)
- server_announce(server, announce->mcast_fd);
-}
-
-static void
-announce_free(struct uring_task *task)
-{
- struct announce *announce = container_of(task, struct announce, task);
-
- assert_return(task);
- debug(DBG_ANN, "task %p, announce 0x%p, mcast_fd: %i",
- task, announce, announce->mcast_fd);
- close(announce->mcast_fd);
- xfree(announce);
-}
-
-void
-announce_refdump()
-{
- assert_return_silent(cfg->announce);
-
- uring_task_refdump(&cfg->announce->task);
-}
-
-void
-announce_delete()
-{
- assert_return_silent(cfg->announce);
-
- debug(DBG_ANN, "called");
- announce_stop();
- uring_task_destroy(&cfg->announce->task);
- cfg->announce = NULL;
-}
-
-void
-announce_stop()
-{
- struct announce *announce = cfg->announce;
-
- assert_return_silent(announce);
-
- ptimer_del_task(&announce->ptask);
-}
-
-void
-announce_start(unsigned duration)
-{
- struct announce *announce = cfg->announce;
- unsigned times;
-
- assert_return_silent(announce);
-
- if (duration == 0)
- times = 0;
- else
- times = MAX(announce->ptask.times,
- DIV_ROUND_UP(duration, cfg->announce_interval));
-
- announce->ptask.times = times;
- ptimer_add_task(&announce->ptask);
-}
-
-void
-announce_init()
-{
- struct announce *announce;
- int sfd;
-
- assert_return(!cfg->announce);
- assert_return_silent(cfg->announce_interval > 0);
-
- announce = zmalloc(sizeof(*announce));
- if (!announce)
- die("malloc: %m");
-
- sfd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (sfd < 0)
- die("socket: %m");
-
- uring_task_init(&announce->task, "announce", uring_parent(), announce_free);
- ptask_init(&announce->ptask, cfg->announce_interval, 0, announce_cb);
- announce->mcast_fd = sfd;
- cfg->announce = announce;
-}
-
diff --git a/mcserverproxy/announce.h b/mcserverproxy/announce.h
deleted file mode 100644
index 77a36f2..0000000
--- a/mcserverproxy/announce.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef fooannouncehfoo
-#define fooannouncehfoo
-
-void announce_refdump();
-
-void announce_delete();
-
-void announce_stop();
-
-void announce_start(unsigned duration);
-
-void announce_init();
-
-#endif
diff --git a/mcserverproxy/config-parser.c b/mcserverproxy/config-parser.c
deleted file mode 100644
index ffed7f1..0000000
--- a/mcserverproxy/config-parser.c
+++ /dev/null
@@ -1,490 +0,0 @@
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdbool.h>
-#include <errno.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <inttypes.h>
-
-#include "main.h"
-#include "config-parser.h"
-
-static void
-eat_whitespace_and_comments(char **pos)
-{
- assert_return(pos && *pos);
-
- while (true) {
- while (isspace(**pos))
- (*pos)++;
-
- if (**pos != '#')
- return;
-
- while (**pos != '\r' && **pos != '\n' && **pos != '\0')
- (*pos)++;
- }
-}
-
-static char *
-get_line(char **pos)
-{
- char *begin, *end;
-
- assert_return(pos && *pos, NULL);
-
- begin = *pos;
- while (isspace(*begin))
- begin++;
-
- if (*begin == '\0')
- return NULL;
-
- end = begin;
- while (*end != '\n' && *end != '\0')
- end++;
-
- if (*end == '\0')
- *pos = end;
- else
- *pos = end + 1;
-
- while (isspace(*end)) {
- *end = '\0';
- end--;
- }
-
- return begin;
-}
-
-static bool
-dnslookup(const char *name, uint16_t port, struct cfg_value *rvalue, bool async)
-{
- struct sockaddr_in *in4;
- struct sockaddr_in6 *in6;
- struct dns_async tmp;
- struct dns_async *dns;
- int mode = async ? GAI_NOWAIT : GAI_WAIT;
- struct addrinfo *results = NULL, *ai;
- struct saddr *saddr = NULL;
- bool rv = false;
- int r;
-
- assert_return(!empty_str(name) && strlen(name) < sizeof(dns->name) && port > 0 && rvalue, false);
-
- if (async) {
- rvalue->type = CFG_VAL_TYPE_ASYNC_ADDRS;
- rvalue->dns_async = NULL;
- dns = zmalloc(sizeof(*dns));
- if (!dns) {
- error("async DNS lookup of %s failed: %m", name);
- goto out;
- }
- debug(DBG_DNS, "doing async DNS lookup of %s: %p", name, dns);
- } else {
- memset(&tmp, 0, sizeof(tmp));
- dns = &tmp;
- debug(DBG_DNS, "doing sync DNS lookup of %s", name);
- }
-
- sprintf(dns->name, "%s", name);
- sprintf(dns->port, "%" PRIu16, port);
-
- dns->req.ai_family = AF_UNSPEC;
- dns->req.ai_socktype = SOCK_STREAM;
- dns->req.ai_protocol = 0;
- dns->req.ai_flags = AI_NUMERICSERV;
-
- dns->sev.sigev_notify = SIGEV_SIGNAL;
- dns->sev.sigev_signo = SIGUSR1;
- dns->sev.sigev_value.sival_ptr = dns;
-
- dns->gcb.ar_name = dns->name;
- dns->gcb.ar_service = dns->port;
- dns->gcb.ar_request = &dns->req;
-
- struct gaicb *gcbs[] = { &dns->gcb };
-
- r = getaddrinfo_a(mode, gcbs, ARRAY_SIZE(gcbs), &dns->sev);
- if (r != 0) {
- error("getaddrinfo(%s:%" PRIu16 "): %s", name, port, gai_strerror(r));
- goto out;
- }
-
- if (async) {
- rvalue->dns_async = dns;
- rv = true;
- goto out;
- }
-
- results = dns->gcb.ar_result;
-
- for (ai = results; ai; ai = ai->ai_next) {
- saddr = zmalloc(sizeof(*saddr));
- if (!saddr) {
- error("sync DNS lookup of %s failed: %m", name);
- 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);
- error("addrstr: %s", saddr->addrstr);
- list_add(&saddr->list, &rvalue->saddrs);
- break;
-
- case AF_INET6:
- in6 = (struct sockaddr_in6 *)ai->ai_addr;
- saddr_set_ipv6(saddr, &in6->sin6_addr, in6->sin6_port);
- error("addrstr: %s", saddr->addrstr);
- list_add(&saddr->list, &rvalue->saddrs);
- break;
-
- default:
- error("getaddrinfo(%s:%s): unknown address family (%i)",
- dns->name, dns->port, ai->ai_family);
- xfree(saddr);
- break;
- }
- }
-
- rv = true;
-
-out:
- freeaddrinfo(results);
- return rv;
-}
-
-static bool
-strtosockaddrs(const char *str, struct cfg_value *rvalue, bool async)
-{
- struct saddr *saddr;
- uint16_t port;
- char *tmp;
- struct list_head *list;
- unsigned naddrs = 0;
-
- assert_return(!empty_str(str) && rvalue, false);
-
- rvalue->type = CFG_VAL_TYPE_ADDRS;
- list = &rvalue->saddrs;
- list_init(list);
-
- if (*str == '[') {
- /* IPv6, [a:b:c...h]:p or [*]:p */
- debug(DBG_CFG, "attempting to parse IPv6 addr (%s)", str);
-
- str++;
- tmp = strchr(str, ']');
- if (!tmp)
- goto error;
- *tmp = '\0';
-
- saddr = zmalloc(sizeof(*saddr));
- if (!saddr)
- goto error;
-
- /* early list_add to make sure saddr is free():d on error */
- list_add(&saddr->list, list);
-
- if (streq(str, "*"))
- saddr->in6.sin6_addr = in6addr_any;
- else if (inet_pton(AF_INET6, str, &saddr->in6.sin6_addr) <= 0)
- goto error;
-
- tmp++;
- if (*tmp != ':')
- goto error;
-
- tmp++;
- if (strtou16_strict(tmp, &port) < 0)
- goto error;
-
- saddr_set_ipv6(saddr, NULL, htons(port));
- naddrs++;
-
- } else if (*str == '*') {
- /* IPv4, *:p */
- debug(DBG_CFG, "attempting to parse IPv4 addr (%s)", str);
-
- str++;
- if (*str != ':')
- goto error;
-
- str++;
- if (strtou16_strict(str, &port) < 0)
- goto error;
-
- saddr = zmalloc(sizeof(*saddr));
- if (!saddr)
- goto error;
-
- saddr_set_ipv4(saddr, INADDR_ANY, htons(port));
- list_add(&saddr->list, list);
- naddrs++;
-
- } else if ((tmp = strchr(str, ':'))) {
- /* IPv4, a.b.c.d:p or IPv4/6 hostname:p */
- debug(DBG_CFG, "attempting to parse IPv4 addr or hostname (%s)", str);
-
- *tmp = '\0';
- tmp++;
- if (strtou16_strict(tmp, &port) < 0)
- goto error;
-
- saddr = zmalloc(sizeof(*saddr));
- if (!saddr)
- goto error;
-
- if (inet_pton(AF_INET, str, &saddr->in4.sin_addr) > 0) {
- debug(DBG_CFG, "got an IPv4:port (%s:%" PRIu16 ")", str, port);
- saddr_set_ipv4(saddr, saddr->in4.sin_addr.s_addr, htons(port));
- list_add(&saddr->list, list);
- naddrs++;
- goto success;
- }
-
- xfree(saddr);
- debug(DBG_CFG, "maybe got a hostname:port (%s:%" PRIu16 ")", str, port);
- if (!dnslookup(str, port, rvalue, async))
- goto error;
-
- } else if (strtou16_strict(tmp, &port) == 0) {
- /* Port */
- debug(DBG_CFG, "attempting to parse a port number (%s)", str);
-
- saddr = zmalloc(sizeof(*saddr));
- if (!saddr)
- goto error;
-
- saddr_set_ipv6(saddr, &in6addr_any, htons(port));
- list_add(&saddr->list, list);
- naddrs++;
-
- saddr = zmalloc(sizeof(*saddr));
- if (!saddr)
- goto error;
-
- saddr_set_ipv4(saddr, INADDR_ANY, htons(port));
- list_add(&saddr->list, list);
- naddrs++;
-
- } else {
- /* Unknown */
- error("unable to parse address: %s", str);
- goto error;
- }
-
-success:
- switch (rvalue->type) {
- case CFG_VAL_TYPE_ADDRS:
- if (list_empty(list) || naddrs == 0) {
- error("empty address list");
- return false;
- }
-
- debug(DBG_CFG, "parsed to %u addresses", naddrs);
- return true;
-
- case CFG_VAL_TYPE_ASYNC_ADDRS:
- debug(DBG_CFG, "looking up address asynchronously");
- return true;
-
- default:
- error("invalid rvalue type");
- rvalue->type = CFG_VAL_TYPE_INVALID;
- break;
- }
-
-error:
- if (rvalue->type == CFG_VAL_TYPE_ADDRS && !list_empty(list)) {
- struct saddr *tmp;
-
- list_for_each_entry_safe(saddr, tmp, list, list) {
- list_del(&saddr->list);
- xfree(saddr);
- }
- }
- return false;
-}
-
-/* Returns true if there's data left to parse in buf */
-bool
-config_parse_line(const char *filename, char **buf,
- struct cfg_key_value_map *kvmap, int *rkey,
- const char **rkeyname, struct cfg_value *rvalue)
-{
- char *line, *tmp, *key;
- int i;
-
- assert_return(buf && *buf && kvmap && rkey && rkeyname && rvalue, false);
-
- eat_whitespace_and_comments(buf);
- line = get_line(buf);
- if (!line)
- return false;
-
- debug(DBG_CFG, "%s: parsing config line: %s", filename, line);
-
- tmp = line;
- while (isspace(*tmp))
- tmp++;
-
- if (*tmp == '\0')
- goto error;
-
- key = tmp;
- while (*tmp != '\0' && !isspace(*tmp))
- tmp++;
-
- if (*tmp == '\0')
- goto error;
-
- *tmp = '\0';
- tmp++;
-
- while (isspace(*tmp))
- tmp++;
-
- if (*tmp != '=')
- goto error;
-
- tmp++;
- while (isspace(*tmp))
- tmp++;
-
- if (*tmp == '\0')
- goto error;
-
- for (i = 0; kvmap[i].key_name; i++) {
- if (!streq(kvmap[i].key_name, key))
- continue;
-
- switch (kvmap[i].value_type) {
-
- case CFG_VAL_TYPE_STRING:
- rvalue->type = CFG_VAL_TYPE_STRING;
- rvalue->str = tmp;
- break;
-
- case CFG_VAL_TYPE_UINT16: {
- uint16_t v;
-
- if (strtou16_strict(tmp, &v) < 0)
- goto error;
-
- rvalue->type = CFG_VAL_TYPE_UINT16;
- rvalue->uint16 = v;
- break;
- }
-
- case CFG_VAL_TYPE_ADDRS:
- if (!strtosockaddrs(tmp, rvalue, false))
- goto error;
-
- if (rvalue->type != CFG_VAL_TYPE_ADDRS) {
- error("invalid type returned from strtosockaddrs");
- goto error;
- }
-
- if (list_empty(&rvalue->saddrs)) {
- error("empty address list");
- goto error;
- }
- break;
-
- case CFG_VAL_TYPE_ASYNC_ADDRS:
- if (!strtosockaddrs(tmp, rvalue, true))
- goto error;
-
- switch (rvalue->type) {
- case CFG_VAL_TYPE_ADDRS:
- if (list_empty(&rvalue->saddrs)) {
- error("empty address list");
- goto error;
- }
- break;
-
- case CFG_VAL_TYPE_ASYNC_ADDRS:
- if (!rvalue->dns_async) {
- error("dns_async not set");
- goto error;
- }
- break;
-
- default:
- error("invalid type returned from strtosockaddrs");
- goto error;
- }
-
- break;
-
- case CFG_VAL_TYPE_BOOL:
- if (strcaseeq(tmp, "yes") || strcaseeq(tmp, "true")) {
- rvalue->type = CFG_VAL_TYPE_BOOL;
- rvalue->boolean = true;
- } else if (strcaseeq(tmp, "no") || strcaseeq(tmp, "false")) {
- rvalue->type = CFG_VAL_TYPE_BOOL;
- rvalue->boolean = false;
- } else {
- error("invalid boolean value (%s)", tmp);
- goto error;
- }
- break;
-
- case CFG_VAL_TYPE_INVALID:
- /* fall through */
- default:
- goto error;
- }
-
- /* sanity check */
- if ((rvalue->type != kvmap[i].value_type) &&
- ((kvmap[i].value_type != CFG_VAL_TYPE_ASYNC_ADDRS) &&
- (rvalue->type != CFG_VAL_TYPE_ADDRS))) {
- error("rvalue->type != kvmap->type");
- goto error;
- }
-
- *rkey = kvmap[i].key_value;
- *rkeyname = kvmap[i].key_name;
- return true;
- }
-
-error:
- /* FIXME: the line is already mangled here, a line number would be nice */
- error("%s: invalid config line: %s", filename, line);
- rvalue->type = CFG_VAL_TYPE_INVALID;
- *rkey = 0;
- *rkeyname = NULL;
- return true;
-}
-
-bool
-config_parse_header(const char *filename, const char *title, char **buf)
-{
- char *line;
-
- assert_return(!empty_str(filename) && !empty_str(title) && buf && *buf, false);
-
- eat_whitespace_and_comments(buf);
-
- line = get_line(buf);
- if (!line) {
- error("%s: missing header in configuration file", filename);
- return false;
- } else {
- char titlehdr[strlen(title) + 3];
-
- sprintf(titlehdr, "[%s]", title);
- if (!streq(line, titlehdr)) {
- error("%s: incorrect header in configuration file", filename);
- return false;
- }
- }
-
- return true;
-}
diff --git a/mcserverproxy/config-parser.h b/mcserverproxy/config-parser.h
deleted file mode 100644
index 3a117a3..0000000
--- a/mcserverproxy/config-parser.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef fooconfigparserhfoo
-#define fooconfigparserhfoo
-
-#define _GNU_SOURCE
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <signal.h>
-
-enum cfg_value_type {
- CFG_VAL_TYPE_INVALID,
- CFG_VAL_TYPE_STRING,
- CFG_VAL_TYPE_UINT16,
- CFG_VAL_TYPE_ADDRS,
- CFG_VAL_TYPE_ASYNC_ADDRS,
- CFG_VAL_TYPE_BOOL,
-};
-
-struct dns_async;
-
-typedef void (dns_cb_t)(struct dns_async *);
-
-struct dns_async {
- char name[FQDN_STR_LEN + 1];
- char port[PORT_STR_LEN + 1];
- struct addrinfo req;
- struct gaicb gcb;
- struct sigevent sev;
- dns_cb_t *cb;
- void *priv;
- struct list_head list;
-};
-
-struct cfg_key_value_map {
- const char *key_name;
- int key_value;
- enum cfg_value_type value_type;
-};
-
-struct cfg_value {
- enum cfg_value_type type;
- union {
- const char *str;
- uint16_t uint16;
- struct list_head saddrs;
- struct dns_async *dns_async;
- bool boolean;
- };
-};
-
-bool config_parse_line(const char *filename, char **buf,
- struct cfg_key_value_map *kvmap,
- int *rkey, const char **rkeyname,
- struct cfg_value *rvalue);
-
-bool config_parse_header(const char *filename,
- const char *title, char **buf);
-
-#endif
diff --git a/mcserverproxy/idle.c b/mcserverproxy/idle.c
deleted file mode 100644
index c49846d..0000000
--- a/mcserverproxy/idle.c
+++ /dev/null
@@ -1,378 +0,0 @@
-#define _GNU_SOURCE
-#include <inttypes.h>
-#include <sys/socket.h>
-#include <netinet/ip.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-
-#include "main.h"
-#include "uring.h"
-#include "server.h"
-#include "idle.h"
-#include "ptimer.h"
-
-struct idle {
- struct ptimer_task ptask;
- struct uring_task task;
-};
-
-static inline void
-write_byte(char **pos, char byte)
-{
- assert_return(pos && *pos);
-
- **pos = byte;
- (*pos)++;
-}
-
-#define MC_HELO 0x00
-#define MC_NEXT_STATE_STATUS 0x01
-#define MC_GET_STATUS 0x00
-#define MC_VARINT_MAX_BYTES 5
-#define MC_STATUS_REPLY 0x00
-#define MC_UNDEFINED_VERSION -1
-
-static inline void
-write_varint(char **pos, int32_t orig)
-{
- assert_return(pos && *pos);
-
- uint32_t val = (uint32_t)orig;
-
- while (val) {
- **pos = val & 0x7f;
- val >>= 7;
- if (val > 0)
- **pos |= 0x80;
- (*pos)++;
- }
-}
-
-/*
- * return value:
- * positive = varint parsed
- * zero = need more bytes
- * negative = error
- */
-static inline int
-read_varint(char **pos, size_t *remain, int32_t *res)
-{
- unsigned consumed;
- uint32_t val = 0;
-
- assert_return(pos && *pos && remain && res, -1);
-
- for (consumed = 1; consumed <= *remain; consumed++) {
- uint32_t tmp;
-
- tmp = **pos & 0x7f;
- val += (tmp << (7 * (consumed - 1)));
- (*pos)++;
-
- if (!(tmp & 0x80))
- break;
- }
-
- if (consumed > *remain)
- return 0;
- else if (consumed > MC_VARINT_MAX_BYTES)
- return -1;
-
- *remain -= consumed;
- *res = (int32_t)val;
- return 1;
-}
-
-static inline void
-write_bytes(char **pos, const char *bytes, size_t n)
-{
- assert_return(pos && *pos && bytes && n > 0);
-
- memcpy(*pos, bytes, n);
- *pos += n;
-}
-
-static inline void
-write_str(char **pos, const char *str)
-{
- size_t len;
-
- assert_return(pos && *pos && !empty_str(str));
-
- len = strlen(str);
- write_varint(pos, len);
- write_bytes(pos, str, len);
-}
-
-static inline void
-write_cmd(char **pos, const char *begin, const char *end)
-{
- assert_return(pos && *pos && begin && end && end > begin);
-
- write_varint(pos, end - begin);
- write_bytes(pos, begin, end - begin);
-}
-
-static int
-idle_check_handshake_complete(struct uring_task *task, int res)
-{
- size_t remain;
- char *pos;
- int32_t mclen;
- int r;
-
- assert_return(task, -EINVAL);
- assert_task_alive_or(DBG_IDLE, task, return -EINTR);
-
- remain = task->tbuf->len;
- pos = task->tbuf->buf;
-
- r = read_varint(&pos, &remain, &mclen);
- if (r < 0) {
- error("failed to parse message length");
- return -EINVAL;
- } else if (r == 0) {
- return 0;
- } else if (mclen < 2) {
- error("short MC message");
- return -EINVAL;
- }
-
- if (mclen < remain) {
- debug(DBG_IDLE, "short MC message - len: %" PRIi32 ", remain: %zu",
- mclen, remain);
- return 0;
- }
-
- debug(DBG_IDLE, "Complete message");
- return 1;
-}
-
-#define ONLINE_NEEDLE "\"online\""
-static int
-get_player_count(const char *pos, size_t remain)
-{
- /*
- * Example JSON (line breaks added):
- * {"description":{
- * "text":"A Minecraft Server"},
- * "players":{"max":20,"online":0},
- * "version":{"name":"1.15.2","protocol":578}
- * }
- */
- char *online;
- char *end;
- unsigned count;
-
- assert_return(pos && remain > 0, -1);
-
- online = memmem(pos, remain, ONLINE_NEEDLE, strlen(ONLINE_NEEDLE));
- if (!online) {
- error("could not find online count in JSON");
- return -1;
- }
-
- remain -= (online - pos);
-
- end = memchr(online, '}', remain);
- if (!end) {
- error("could not parse JSON (no end)");
- return -1;
- }
- *end = '\0';
-
- if (sscanf(online, ONLINE_NEEDLE " : %u", &count) != 1) {
- error("could not parse JSON (online count)");
- return -1;
- }
-
- return count;
-}
-
-static void
-idle_check_handshake_reply(struct uring_task *task, int res)
-{
- struct server *server = container_of(task, struct server, idle_task);
- int32_t mclen;
- int32_t jsonlen;
- char *pos;
- size_t remain;
- int player_count = -1;
- int r;
-
- assert_return(task);
- assert_task_alive(DBG_IDLE, task);
-
- debug(DBG_IDLE, "res: %i", res);
- if (res < 0)
- goto out;
-
- /*
- fprintf(stderr, "Received MC message (%i bytes):", res);
- for (int i = 0; i < res; i++)
- fprintf(stderr, "0x%02hhx ", idle->remotebuf[i]);
- fprintf(stderr, "n");
- */
-
- remain = server->idle_buf.len;
- pos = server->idle_buf.buf;
-
- r = read_varint(&pos, &remain, &mclen);
- if (r <= 0 || mclen < 2 || mclen < remain) {
- /* Should not happen since the msg has been checked already */
- error("invalid message");
- goto out;
- }
-
- debug(DBG_IDLE, "MC message - len: %" PRIi32 ", remain: %zu",
- mclen, remain);
-
- if (*pos != MC_STATUS_REPLY) {
- error("unknown server reply (0x%02hhx)", *pos);
- goto out;
- }
-
- pos++;
- remain--;
-
- r = read_varint(&pos, &remain, &jsonlen);
- if (r <= 0) {
- error("could not read JSON length");
- goto out;
- }
-
- debug(DBG_IDLE, "MC - json len: %" PRIi32 ", remain: %zu",
- jsonlen, remain);
-
- if (jsonlen < remain) {
- error("invalid JSON length");
- goto out;
- }
-
- /*
- fprintf(stderr, "JSON: ");
- for (int i = 0; i < jsonlen; i++)
- fprintf(stderr, "%c", pos[i]);
- */
-
- player_count = get_player_count(pos, remain);
-
-out:
- uring_task_close_fd(task);
- server_set_active_players(server, player_count);
- return;
-}
-
-static void
-idle_check_handshake_sent(struct uring_task *task, int res)
-{
- assert_return(task);
- assert_task_alive(DBG_IDLE, task);
-
- debug(DBG_IDLE, "sent %i bytes", res);
- if (res < 0) {
- uring_task_close_fd(task);
- return;
- }
-
- uring_tbuf_read_until(task,
- idle_check_handshake_complete,
- idle_check_handshake_reply);
-}
-
-void
-idle_check_get_player_count(struct server *server, struct connection *conn)
-{
- char buf[1024];
- char *pos;
- char *cmdbuf = server->idle_buf.buf;
- uint16_t port;
- char hostname[INET6_ADDRSTRLEN];
-
- assert_return(server && conn && server->idle_task.priv);
-
- port = saddr_port(&conn->remote);
- saddr_addr(&conn->remote, hostname, sizeof(hostname));
-
- pos = buf;
- write_byte(&pos, MC_HELO);
- write_varint(&pos, MC_UNDEFINED_VERSION);
- write_str(&pos, hostname);
- write_byte(&pos, (port >> 8) & 0xff);
- write_byte(&pos, (port >> 0) & 0xff);
- write_byte(&pos, MC_NEXT_STATE_STATUS);
- write_cmd(&cmdbuf, buf, pos);
-
- pos = buf;
- write_byte(&pos, MC_GET_STATUS);
- write_cmd(&cmdbuf, buf, pos);
-
- server->idle_buf.len = (cmdbuf - server->idle_buf.buf);
- debug(DBG_IDLE, "sending MC message (%zu bytes)", server->idle_buf.len);
-
- uring_tbuf_write(&server->idle_task, idle_check_handshake_sent);
-}
-
-static void
-idle_cb(struct ptimer_task *ptask)
-{
- struct idle *idle = container_of(ptask, struct idle, ptask);
- struct server *server;
-
- assert_return(ptask);
- assert_task_alive(DBG_IDLE, &idle->task);
-
- debug(DBG_IDLE, "timer fired");
-
- list_for_each_entry(server, &cfg->servers, list)
- server_idle_check(server);
-}
-
-static void
-idle_free(struct uring_task *task)
-{
- struct idle *idle = container_of(task, struct idle, task);
-
- assert_return(task);
- debug(DBG_IDLE, "task %p, idle %p", task, idle);
- xfree(idle);
-}
-
-void
-idle_refdump()
-{
- assert_return_silent(cfg->idle);
-
- uring_task_refdump(&cfg->idle->task);
-}
-
-void
-idle_delete()
-{
- assert_return(cfg->idle);
-
- debug(DBG_IDLE, "closing fd %i", cfg->idle->task.fd);
- ptimer_del_task(&cfg->idle->ptask);
- uring_task_destroy(&cfg->idle->task);
- cfg->idle = NULL;
-}
-
-void
-idle_init()
-{
- struct idle *idle;
-
- assert_return(!cfg->idle);
-
- idle = zmalloc(sizeof(*idle));
- if (!idle)
- die("malloc: %m");
-
- ptask_init(&idle->ptask, 60, 0, idle_cb);
- uring_task_init(&idle->task, "idle", uring_parent(), idle_free);
- ptimer_add_task(&idle->ptask);
- cfg->idle = idle;
-}
-
diff --git a/mcserverproxy/idle.h b/mcserverproxy/idle.h
deleted file mode 100644
index d7e4ab0..0000000
--- a/mcserverproxy/idle.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef fooidlehfoo
-#define fooidlehfoo
-
-void idle_check_get_player_count(struct server *server,
- struct connection *conn);
-
-void idle_refdump();
-
-void idle_delete();
-
-void idle_init();
-
-#endif
diff --git a/mcserverproxy/igmp.c b/mcserverproxy/igmp.c
deleted file mode 100644
index dc43a9f..0000000
--- a/mcserverproxy/igmp.c
+++ /dev/null
@@ -1,587 +0,0 @@
-#include <unistd.h>
-#include <string.h>
-#include <stdint.h>
-#include <sys/socket.h>
-#include <linux/if_packet.h>
-#include <net/ethernet.h>
-#include <net/if.h>
-#include <netinet/ip.h>
-#include <linux/bpf.h>
-#include <linux/filter.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-
-#include "main.h"
-#include "uring.h"
-#include "igmp.h"
-#include "announce.h"
-
-struct igmp {
- struct uring_task task;
- struct uring_task_buf tbuf;
-};
-
-#define ETH_HDR_LEN 14
-#define IPV4_MIN_HDR_LEN 20
-#define IGMP_MIN_LEN 8
-
-struct __attribute__((packed, scalar_storage_order("big-endian"))) ipv4_hdr {
- unsigned version:4;
- unsigned ihl:4;
- unsigned dscp:6;
- unsigned ecn:2;
- unsigned length:16;
- unsigned id:16;
- unsigned flags:3;
- unsigned fragment_offset:13;
- unsigned ttl:8;
- unsigned protocol:8;
- unsigned checksum:16;
- unsigned src:32;
- unsigned dst:32;
- unsigned options[];
-};
-
-enum igmp_type {
- IGMP_MEMBERSHIP_QUERY = 0x11,
- IGMP_V1_MEMBERSHIP_REPORT = 0x12,
- IGMP_V2_MEMBERSHIP_REPORT = 0x16,
- IGMP_V3_MEMBERSHIP_REPORT = 0x22,
- IGMP_V2_LEAVE_GROUP = 0x17
-};
-
-union igmp_msg {
- struct __attribute__((packed, scalar_storage_order("big-endian"))) {
- enum igmp_type type:8;
- unsigned unknown:8;
- unsigned checksum:16;
- } common;
-
- struct __attribute__((packed, scalar_storage_order("big-endian"))) {
- enum igmp_type type:8;
- unsigned resptime:8;
- unsigned checksum:16;
- unsigned addr:32;
- } v2;
-
- struct __attribute__((packed, scalar_storage_order("big-endian"))) {
- enum igmp_type type:8;
- unsigned reserved1:8;
- unsigned checksum:16;
- unsigned reserved2:16;
- unsigned nrecs:16;
- uint8_t records[];
- } v3;
-};
-
-enum igmp_v3_record_type {
- IGMP_V3_REC_MODE_IS_INCL = 1,
- IGMP_V3_REC_MODE_IS_EXCL = 2,
- IGMP_V3_REC_MODE_CH_INCL = 3,
- IGMP_V3_REC_MODE_CH_EXCL = 4
-};
-
-union igmp_v3_record {
- struct __attribute__((packed, scalar_storage_order("big-endian"))) {
- enum igmp_v3_record_type type:8;
- unsigned auxlen:8;
- unsigned nsrcs:16;
- unsigned addr:32;
- uint32_t saddr[];
- };
-};
-
-static inline unsigned short
-from32to16(unsigned int x)
-{
- /* add up 16-bit and 16-bit for 16+c bit */
- x = (x & 0xffff) + (x >> 16);
- /* add up carry.. */
- x = (x & 0xffff) + (x >> 16);
- return x;
-}
-
-static unsigned int
-do_csum(const unsigned char *buf, int len)
-{
- int odd;
- unsigned int result = 0;
-
- assert_return(buf && len > 0, 0);
-
- odd = 1 & (unsigned long)buf;
- if (odd) {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- result += (*buf << 8);
-#else
- result = *buf;
-#endif
- len--;
- buf++;
- }
-
- if (len >= 2) {
- if (2 & (unsigned long)buf) {
- result += *(unsigned short *)buf;
- len -= 2;
- buf += 2;
- }
- if (len >= 4) {
- const unsigned char *end = buf + ((unsigned)len & ~3);
- unsigned int carry = 0;
- do {
- unsigned int w = *(unsigned int *)buf;
- buf += 4;
- result += carry;
- result += w;
- carry = (w > result);
- } while (buf < end);
- result += carry;
- result = (result & 0xffff) + (result >> 16);
- }
- if (len & 2) {
- result += *(unsigned short *)buf;
- buf += 2;
- }
- }
-
- if (len & 1)
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- result += *buf;
-#else
- result += (*buf << 8);
-#endif
-
- result = from32to16(result);
- if (odd)
- result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
-
- return result;
-}
-
-static inline bool
-csum_valid(const char *buf, size_t len)
-{
- assert_return(buf && len > 0, false);
-
- return do_csum((unsigned const char *)buf, len) == 0xffff;
-}
-
-static void
-igmp_match()
-{
- debug(DBG_IGMP, "multicast request discovered");
- /*
- * IGMP messages are sent with approx 120-130 sec intervals,
- * so set time to 5 minutes to allow some slack.
- */
- announce_start(5 * 60);
-}
-
-static void
-igmp_parse(struct igmp *igmp)
-{
- char *buf;
- size_t len;
- struct ipv4_hdr *hdr;
- size_t body_len;
- union igmp_msg *igmp_msg;
-
- assert_return(igmp);
-
- buf = igmp->task.tbuf->buf;
- len = igmp->task.tbuf->len;
- hdr = (struct ipv4_hdr *)buf;
-
- if (len <= IPV4_MIN_HDR_LEN)
- return;
-
- if (hdr->version != 4)
- return;
-
- if (hdr->ihl * 4 < IPV4_MIN_HDR_LEN)
- return;
-
- if (hdr->length < hdr->ihl * 4)
- return;
-
- if (hdr->length != len)
- return;
-
- if (hdr->fragment_offset > 0)
- return;
-
- if (hdr->protocol != IPPROTO_IGMP)
- return;
-
- if (!csum_valid(buf, hdr->ihl * 4))
- return;
-
- body_len = hdr->length - hdr->ihl * 4;
- igmp_msg = (union igmp_msg *)(buf + hdr->ihl * 4);
-
- if (body_len < IGMP_MIN_LEN)
- return;
-
- switch (igmp_msg->common.type) {
- case IGMP_V1_MEMBERSHIP_REPORT:
- debug(DBG_IGMP, "igmp_v1_membership_report");
- /* fall through */
-
- case IGMP_V2_MEMBERSHIP_REPORT: {
- struct in_addr src;
- char src_str[INET_ADDRSTRLEN];
- struct in_addr dst;
- char dst_str[INET_ADDRSTRLEN];
- struct in_addr grp;
- char grp_str[INET_ADDRSTRLEN];
-
- src.s_addr = htonl(hdr->src);
- inet_ntop(AF_INET, &src, src_str, sizeof(src_str));
- dst.s_addr = htonl(hdr->dst);
- inet_ntop(AF_INET, &dst, dst_str, sizeof(dst_str));
- grp.s_addr = htonl(igmp_msg->v2.addr);
- inet_ntop(AF_INET, &grp, grp_str, sizeof(grp_str));
-
- debug(DBG_IGMP, "igmp_v2_membership_report %s -> %s (%s)",
- src_str, dst_str, grp_str);
-
- if (body_len != IGMP_MIN_LEN) {
- error("IGMPv2 invalid size");
- break;
- }
-
- if (!csum_valid((char *)igmp_msg, body_len)) {
- error("IGMPv2 invalid checksum");
- break;
- }
-
- debug(DBG_IGMP, "Inet addr: 0x%x", inet_addr("224.0.2.60"));
- debug(DBG_IGMP, "Inet addr: 0x%x", cinet_addr(224,0,2,60));
- debug(DBG_IGMP, "Inet addr: 0x%x", chtobe32(cinet_addr(224,0,2,60)));
- if (htonl(hdr->dst) != cinet_addr(224,0,2,60)) {
- debug(DBG_IGMP, "IGMPv2 invalid dst addr");
- break;
- }
-
- if (htonl(igmp_msg->v2.addr) != cinet_addr(224,0,2,60)) {
- debug(DBG_IGMP, "IGMPv2 invalid grp addr");
- break;
- }
-
- igmp_match();
- break;
- }
-
- case IGMP_V3_MEMBERSHIP_REPORT: {
- char *pos = (char *)igmp_msg;
- struct in_addr src;
- char src_str[INET_ADDRSTRLEN];
- struct in_addr dst;
- char dst_str[INET_ADDRSTRLEN];
-
- src.s_addr = htonl(hdr->src);
- inet_ntop(AF_INET, &src, src_str, sizeof(src_str));
- dst.s_addr = htonl(hdr->dst);
- inet_ntop(AF_INET, &dst, dst_str, sizeof(dst_str));
-
- debug(DBG_IGMP, "igmp_v3_membership_report %s -> %s",
- src_str, dst_str);
-
- debug(DBG_IGMP, "IGMPv3"
- " type: %x,"
- " reserved: %u,"
- " csum: %u,"
- " reserved: %u,"
- " nrecs: %u,"
- " size: %zu\n",
- igmp_msg->v3.type,
- igmp_msg->v3.reserved1,
- igmp_msg->v3.checksum,
- igmp_msg->v3.reserved2,
- igmp_msg->v3.nrecs,
- sizeof(igmp_msg->v3));
-
- if (!csum_valid(pos, body_len)) {
- error("IGMPv3 csum invalid");
- break;
- }
-
- if (htonl(hdr->dst) != cinet_addr(224,0,0,22)) {
- debug(DBG_IGMP, "IGMPv2 invalid dst addr");
- break;
- }
-
- body_len -= sizeof(igmp_msg->v3);
- pos += sizeof(igmp_msg->v3);
-
- for (unsigned rec = 0; rec < igmp_msg->v3.nrecs; rec++) {
- union igmp_v3_record *record = (union igmp_v3_record *)pos;
- struct in_addr grp;
- char grp_str[INET_ADDRSTRLEN];
-
- if (body_len < sizeof(*record)) {
- error("IGMPv3 too short");
- break;
- }
-
- grp.s_addr = htonl(record->addr);
- inet_ntop(AF_INET, &grp, grp_str, sizeof(grp_str));
- debug(DBG_IGMP, "received IGMPv3 record to %s", grp_str);
-
- debug(DBG_IGMP, "IGMPv3 rec, "
- " type: %u,"
- " auxlen: %u,"
- " nsrcs: %u,"
- " addr: %s,"
- " size: %zu bytes",
- record->type,
- record->auxlen,
- record->nsrcs,
- grp_str,
- sizeof(*record));
-
- body_len -= sizeof(*record);
- pos += sizeof(*record);
-
- if (body_len < record->nsrcs * sizeof(uint32_t) + record->auxlen) {
- error("IGMPv3 too short");
- break;
- }
-
- for (unsigned addr = 0; addr < record->nsrcs; addr++) {
- struct in_addr grp_src;
- char grp_src_str[INET_ADDRSTRLEN];
-
- grp_src.s_addr = htonl(record->saddr[addr]);
- inet_ntop(AF_INET, &grp_src, grp_src_str, sizeof(grp_src_str));
- debug(DBG_IGMP, "received IGMPv3 record src %s",
- grp_src_str);
-
- body_len -= sizeof(record->saddr[addr]);
- pos += sizeof(record->saddr[addr]);
- }
-
- /* Yes, EXCL, not INCL, see RFC3376 */
- if ((htonl(record->addr) == cinet_addr(224,0,2,60)) &&
- ((record->type == IGMP_V3_REC_MODE_IS_EXCL) ||
- (record->type == IGMP_V3_REC_MODE_CH_EXCL)))
- igmp_match();
-
- body_len -= record->auxlen;
- pos += record->auxlen;
- }
-
- break;
- }
-
- case IGMP_MEMBERSHIP_QUERY:
- debug(DBG_IGMP, "igmp_membership_query");
- break;
-
- case IGMP_V2_LEAVE_GROUP:
- debug(DBG_IGMP, "igmp_v2_leave_group");
- break;
-
- default:
- debug(DBG_IGMP, "IGMP msg type %02hhx", igmp_msg->common.type);
- break;
- }
-
- buf += hdr->length;
- len -= hdr->length;
-}
-
-static void
-igmp_read_cb(struct uring_task *task, int res)
-{
- struct igmp *igmp = container_of(task, struct igmp, task);
-
- assert_return(task);
- assert_task_alive(DBG_IGMP, task);
-
- debug(DBG_IGMP, "task %p, igmp %p, res %i", task, igmp, res);
- if (res < 0) {
- error("res: %i", res);
- return;
- }
-
- task->tbuf->len = res;
-
- if (task->saddr.storage.ss_family == AF_PACKET ||
- task->saddr.ll.sll_protocol == htons(ETH_P_IP))
- igmp_parse(igmp);
- else
- debug(DBG_IGMP, "invalid packet type received");
-
- uring_tbuf_read(&igmp->task, igmp_read_cb);
-}
-
-static void
-igmp_free(struct uring_task *task)
-{
- struct igmp *igmp = container_of(task, struct igmp, task);
-
- assert_return(task);
- debug(DBG_IGMP, "task %p, igmp %p", task, igmp);
- xfree(igmp);
-}
-
-void
-igmp_refdump()
-{
- assert_return_silent(cfg->igmp);
-
- uring_task_refdump(&cfg->igmp->task);
-}
-
-void
-igmp_delete()
-{
- assert_return_silent(cfg->igmp);
-
- debug(DBG_IGMP, "closing fd %i", cfg->igmp->task.fd);
- uring_task_destroy(&cfg->igmp->task);
- cfg->igmp = NULL;
-}
-
-void
-igmp_init()
-{
- static const struct sock_filter filter[] = {
- BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
- BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct iphdr), 1, 0), /* A < sizeof(iphdr) */
- BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
-
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 0 /* iphdr[0] */), /* A <- version + ihl */
- BPF_STMT(BPF_ALU + BPF_RSH + BPF_K, 4), /* A <- A >> 4 (version) */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x04, 1, 0), /* A != 4 */
- BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
-
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct iphdr, protocol)), /* A <- ip protocol */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_IGMP, 1, 0), /* A != IPPROTO_IGMP */
- BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
-
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct iphdr, daddr)), /* A <- ip dst addr */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, chtobe32(cinet_addr(224,0,2,60)), 2, 0), /* A != 224.0.2.60 */
- //BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xe000023c, 2, 0), /* A != 224.0.2.60 */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, chtobe32(cinet_addr(224,0,0,22)), 1, 0), /* A != 224.0.0.22 */
- //BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xe0000016, 1, 0), /* A != 224.0.0.22 */
- BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
-
- BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 0 /* iphdr[0] */), /* X <- pkt->ihl * 4 */
- BPF_STMT(BPF_LD + BPF_IMM, 20), /* A <- 20 */
- BPF_JUMP(BPF_JMP + BPF_JGT + BPF_X, 0, 0, 1), /* A > X */
- BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
-
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct iphdr, tot_len)), /* A <- ip tot_len */
- BPF_JUMP(BPF_JMP + BPF_JGT + BPF_X, 0, 1, 0), /* A <= ip->ihl * 4 */
- BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
- BPF_STMT(BPF_ALU + BPF_SUB + BPF_X, 0), /* A <- A - X (bodylen) */
- BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, 8, 1, 0), /* A < 8 */
- BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
-
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct iphdr, tot_len)), /* A <- ip->tot_len */
- BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
- BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A != ip->tot_len */
- BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
-
- BPF_STMT(BPF_RET + BPF_K, (uint32_t) -1), /* accept packet */
- };
- static const struct sock_fprog fprog = {
- .len = ARRAY_SIZE(filter),
- .filter = (struct sock_filter*) filter,
- };
- struct sockaddr_ll addr = {
- .sll_family = AF_PACKET,
- .sll_ifindex = 0,
- .sll_pkttype = PACKET_MULTICAST,
- };
- struct igmp *igmp;
- int sfd;
- int opt;
-
- if (!cfg->do_igmp) {
- debug(DBG_IGMP, "igmp snooping disabled");
- return;
- }
-
- assert_return(!cfg->igmp);
-
- igmp = zmalloc(sizeof(*igmp));
- if (!igmp)
- return;
-
- /*
- * Kernel limitation, must be ETH_P_ALL, not ETH_P_IP or we won't get
- * outgoing packets, https://lkml.org/lkml/1999/12/23/112
- */
- sfd = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_ALL));
- if (sfd < 0) {
- if (errno == EACCES || errno == EPERM)
- info("Unable to do IGMP snooping, permission denied");
- else
- error("socket: %m");
- goto error;
- }
-
- if (setsockopt(sfd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0) {
- error("setsockopt(SO_ATTACH_FILTER): %m");
- goto error;
- }
-
- if (setsockopt(sfd, SOL_SOCKET, SO_LOCK_FILTER, &opt, sizeof(opt)) < 0) {
- error("setsockopt(SO_LOCK_FILTER): %m");
- goto error;
- }
-
- if (cfg->igmp_iface) {
- struct ifreq ifreq;
- int r;
-
- r = snprintf(ifreq.ifr_name, sizeof(ifreq.ifr_name),
- "%s", cfg->igmp_iface);
- if (r < 0 || r >= sizeof(ifreq.ifr_name))
- die("invalid interface name: %s", cfg->igmp_iface);
-
- if (ioctl(sfd, SIOCGIFINDEX, &ifreq) < 0)
- die("ioctl: %m");
-
- debug(DBG_IGMP, "using interface %s (%i)",
- cfg->igmp_iface, ifreq.ifr_ifindex);
-
- struct packet_mreq mreq = {
- .mr_ifindex = ifreq.ifr_ifindex,
- .mr_type = PACKET_MR_ALLMULTI
- };
-
- if (setsockopt(sfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- error("setsockopt(PACKET_ADD_MEMBERSHIP): %m");
- goto error;
- }
- }
-
- /* can't set .sll_protocol to htons(ETH_P_IP), see comment above */
- if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- error("bind: %m");
- goto error;
- }
-
- debug(DBG_IGMP, "init successful, using fd %i", sfd);
- uring_task_init(&igmp->task, "igmp", uring_parent(), igmp_free);
- uring_task_set_fd(&igmp->task, sfd);
- uring_task_set_buf(&igmp->task, &igmp->tbuf);
- igmp->task.saddr.addrlen = sizeof(igmp->task.saddr.ll);
- uring_tbuf_recvmsg(&igmp->task, igmp_read_cb);
-
- cfg->igmp = igmp;
-
- return;
-
-error:
- close(sfd);
- xfree(igmp);
-}
diff --git a/mcserverproxy/igmp.h b/mcserverproxy/igmp.h
deleted file mode 100644
index 80875b0..0000000
--- a/mcserverproxy/igmp.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef fooigmphfoo
-#define fooigmphfoo
-
-void igmp_refdump();
-
-void igmp_delete();
-
-void igmp_init();
-
-#endif
diff --git a/mcserverproxy/main.c b/mcserverproxy/main.c
deleted file mode 100644
index 047e70e..0000000
--- a/mcserverproxy/main.c
+++ /dev/null
@@ -1,740 +0,0 @@
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include <getopt.h>
-#include <systemd/sd-daemon.h>
-#include <cap-ng.h>
-#include <pwd.h>
-#include <grp.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#include "main.h"
-#include "signal-handler.h"
-#include "uring.h"
-#include "config-parser.h"
-#include "server.h"
-#include "server-config.h"
-#include "announce.h"
-#include "systemd.h"
-#include "igmp.h"
-#include "idle.h"
-#include "ptimer.h"
-#include <config.h>
-
-/* Global */
-struct cfg *cfg = NULL;
-bool exiting = false;
-unsigned debug_mask = DBG_ERROR | DBG_INFO;
-
-/* Local */
-static bool daemonize = false;
-static FILE *log_file = NULL;
-static const char *log_file_path = NULL;
-
-#define ANSI_RED "\x1B[0;31m"
-#define ANSI_GREEN "\x1B[0;32m"
-#define ANSI_YELLOW "\x1B[0;33m"
-#define ANSI_BLUE "\x1B[0;34m"
-#define ANSI_MAGENTA "\x1B[0;35m"
-#define ANSI_GREY "\x1B[0;38;5;245m"
-#define ANSI_NORMAL "\x1B[0m"
-
-static void
-msg(enum debug_lvl lvl, const char *fmt, va_list ap)
-{
- static bool first = true;
- static bool use_colors = false;
- static bool sd_daemon = false;
- const char *color;
- const char *sd_lvl;
-
- assert_return(lvl != 0 && !empty_str(fmt) && ap);
-
- while (first) {
- int fd;
- const char *e;
-
- first = false;
-
- /* assume we're not launched by systemd when daemonized */
- if (daemonize) {
- sd_daemon = false;
- use_colors = false;
- break;
- }
-
- if (log_file) {
- sd_daemon = false;
- use_colors = false;
- break;
- }
-
- if (getenv("NO_COLOR")) {
- sd_daemon = false;
- use_colors = false;
- break;
- }
-
- fd = fileno(stderr);
- if (fd < 0) {
- /* Umm... */
- sd_daemon = true;
- use_colors = false;
- break;
- }
-
- if (!isatty(fd)) {
- sd_daemon = true;
- use_colors = false;
- break;
- }
-
- /* systemd wouldn't normally set TERM */
- e = getenv("TERM");
- if (!e) {
- sd_daemon = true;
- use_colors = false;
- break;
- }
-
- if (streq(e, "dumb")) {
- sd_daemon = false;
- use_colors = false;
- break;
- }
-
- sd_daemon = false;
- use_colors = true;
- }
-
- switch (lvl) {
- case DBG_ERROR:
- sd_lvl = SD_ERR;
- color = use_colors ? ANSI_RED : NULL;
- break;
- case DBG_VERBOSE:
- sd_lvl = SD_INFO;
- color = NULL;
- break;
- case DBG_INFO:
- sd_lvl = SD_NOTICE;
- color = NULL;
- break;
- default:
- sd_lvl = SD_DEBUG;
- color = use_colors ? ANSI_GREY : NULL;
- break;
- }
-
- if (sd_daemon)
- fprintf(stderr, sd_lvl);
- else if (color)
- fprintf(stderr, color);
-
- vfprintf(log_file ? log_file : stderr, fmt, ap);
-
- if (color)
- fprintf(stderr, ANSI_NORMAL);
-}
-
-void
-__debug(enum debug_lvl lvl, const char *fmt, ...)
-{
- va_list ap;
-
- assert_return(lvl != 0 && !empty_str(fmt));
-
- va_start(ap, fmt);
- msg(lvl, fmt, ap);
- va_end(ap);
-}
-
-__attribute__((noreturn)) void
-__die(const char *fmt, ...)
-{
- va_list ap;
-
- if (!empty_str(fmt)) {
- va_start(ap, fmt);
- msg(DBG_ERROR, fmt, ap);
- va_end(ap);
- } else
- error("fmt not set");
-
- sd_notifyf(0, "STATUS=Error, shutting down");
- exit(EXIT_FAILURE);
-};
-
-static void
-cfg_free(struct uring_task *task)
-{
- struct cfg *xcfg = container_of(task, struct cfg, task);
-
- assert_return(task && xcfg == cfg);
-
- debug(DBG_SIG, "called");
- systemd_delete(cfg);
- xfree(cfg->igmp_iface);
- cfg->igmp_iface = NULL;
- exiting = true;
- /* The cfg struct is free:d in main() */
-}
-
-enum mcfg_keys {
- MCFG_KEY_INVALID = 0,
- MCFG_KEY_IGMP,
- MCFG_KEY_IGMP_IFACE,
- MCFG_KEY_ANN_INTERVAL,
- MCFG_KEY_PROXY_CONN_INTERVAL,
- MCFG_KEY_PROXY_CONN_ATTEMPTS,
- MCFG_KEY_SOCKET_DEFER,
- MCFG_KEY_SOCKET_FREEBIND,
- MCFG_KEY_SOCKET_KEEPALIVE,
- MCFG_KEY_SOCKET_IPTOS,
- MCFG_KEY_SOCKET_NODELAY,
-};
-
-struct cfg_key_value_map mcfg_key_map[] = {
- {
- .key_name = "igmp",
- .key_value = MCFG_KEY_IGMP,
- .value_type = CFG_VAL_TYPE_BOOL,
- }, {
- .key_name = "igmp_iface",
- .key_value = MCFG_KEY_IGMP_IFACE,
- .value_type = CFG_VAL_TYPE_STRING,
- }, {
- .key_name = "announce_interval",
- .key_value = MCFG_KEY_ANN_INTERVAL,
- .value_type = CFG_VAL_TYPE_UINT16,
- }, {
- .key_name = "proxy_connection_interval",
- .key_value = MCFG_KEY_PROXY_CONN_INTERVAL,
- .value_type = CFG_VAL_TYPE_UINT16,
- }, {
- .key_name = "proxy_connection_attempts",
- .key_value = MCFG_KEY_PROXY_CONN_ATTEMPTS,
- .value_type = CFG_VAL_TYPE_UINT16,
- }, {
- .key_name = "socket_defer",
- .key_value = MCFG_KEY_SOCKET_DEFER,
- .value_type = CFG_VAL_TYPE_BOOL,
- }, {
- .key_name = "socket_freebind",
- .key_value = MCFG_KEY_SOCKET_FREEBIND,
- .value_type = CFG_VAL_TYPE_BOOL,
- }, {
- .key_name = "socket_keepalive",
- .key_value = MCFG_KEY_SOCKET_KEEPALIVE,
- .value_type = CFG_VAL_TYPE_BOOL,
- }, {
- .key_name = "socket_iptos",
- .key_value = MCFG_KEY_SOCKET_IPTOS,
- .value_type = CFG_VAL_TYPE_BOOL,
- }, {
- .key_name = "socket_nodelay",
- .key_value = MCFG_KEY_SOCKET_NODELAY,
- .value_type = CFG_VAL_TYPE_BOOL,
- }, {
- .key_name = NULL,
- .key_value = MCFG_KEY_INVALID,
- .value_type = CFG_VAL_TYPE_INVALID,
- }
-};
-
-static void
-cfg_read()
-{
- FILE *cfgfile;
- const char *path;
- char buf[4096];
- char *pos = buf;
- size_t rd = 0;
- size_t r;
-
- assert_return(cfg);
-
- if (cfg->cfg_file)
- path = cfg->cfg_file;
- else
- path = DEFAULT_MAIN_CFG_FILE;
-
- cfgfile = fopen(path, "re");
- if (!cfgfile) {
- /* ENOENT is only an error with an explicitly set path */
- if (errno == ENOENT && !cfg->cfg_file)
- return;
- else if (errno == ENOENT)
- die("main config file (%s) missing", path);
- else
- die("fopen(%s): %m", path);
- }
-
- debug(DBG_CFG, "opened main config file (%s)", path);
-
- while (rd < sizeof(buf)) {
- r = fread(pos, 1, sizeof(buf) - rd - 1, cfgfile);
- if (r == 0)
- break;
- rd += r;
- pos += r;
- }
-
- if (rd == 0)
- die("main config file (%s) zero size", path);
-
- if (rd >= sizeof(buf))
- die("main config file (%s) too large", path);
-
- fclose(cfgfile);
- *pos = '\0';
- pos = buf;
-
- if (!config_parse_header(path, "mcproxy", &pos))
- die("main config file (%s) invalid", path);
-
- while (true) {
- int key;
- const char *keyname;
- struct cfg_value value;
-
- if (!config_parse_line(path, &pos, mcfg_key_map,
- &key, &keyname, &value))
- break;
-
- if (key == MCFG_KEY_INVALID)
- die("main config file (%s) invalid", path);
-
- debug(DBG_CFG, "main cfg: key %s", keyname);
-
- switch (key) {
-
- case MCFG_KEY_IGMP:
- cfg->do_igmp = value.boolean;
- break;
-
- case MCFG_KEY_IGMP_IFACE:
- cfg->igmp_iface = xstrdup(value.str);
- if (!cfg->igmp_iface)
- die("xstrdup: %m");
-
- break;
-
- case MCFG_KEY_ANN_INTERVAL:
- cfg->announce_interval = value.uint16;
- break;
-
- case MCFG_KEY_PROXY_CONN_INTERVAL:
- cfg->proxy_connection_interval = value.uint16;
- break;
-
- case MCFG_KEY_PROXY_CONN_ATTEMPTS:
- cfg->proxy_connection_attempts = value.uint16;
- break;
-
- case MCFG_KEY_SOCKET_DEFER:
- cfg->socket_defer = value.boolean;
- break;
-
- case MCFG_KEY_SOCKET_FREEBIND:
- cfg->socket_freebind = value.boolean;
- break;
-
- case MCFG_KEY_SOCKET_KEEPALIVE:
- cfg->socket_keepalive = value.boolean;
- break;
-
- case MCFG_KEY_SOCKET_IPTOS:
- cfg->socket_iptos = value.boolean;
- break;
-
- case MCFG_KEY_SOCKET_NODELAY:
- cfg->socket_nodelay = value.boolean;
- break;
-
- case MCFG_KEY_INVALID:
- default:
- die("main config file (%s) invalid", path);
- }
- }
-}
-
-const struct {
- const char *name;
- unsigned val;
-} debug_category_str[] = {
- {
- .name = "config",
- .val = DBG_CFG,
- },{
- .name = "refcount",
- .val = DBG_REF,
- },{
- .name = "malloc",
- .val = DBG_MALLOC,
- },{
- .name = "announce",
- .val = DBG_ANN,
- },{
- .name = "signal",
- .val = DBG_SIG,
- },{
- .name = "uring",
- .val = DBG_UR,
- },{
- .name = "server",
- .val = DBG_SRV,
- },{
- .name = "proxy",
- .val = DBG_PROXY,
- },{
- .name = "rcon",
- .val = DBG_RCON,
- },{
- .name = "idle",
- .val = DBG_IDLE,
- },{
- .name = "igmp",
- .val = DBG_IGMP,
- },{
- .name = "systemd",
- .val = DBG_SYSD,
- },{
- .name = "dns",
- .val = DBG_DNS,
- },{
- .name = "timer",
- .val = DBG_TIMER,
- },{
- .name = NULL,
- .val = 0,
- }
-};
-
-__attribute__((noreturn)) static void
-usage(int argc, char **argv, bool invalid)
-{
- if (invalid)
- info("Invalid option(s)");
-
- info("Usage: %s [OPTIONS]\n"
- "\n"
- "Valid options:\n"
- " -c, --cfgdir=DIR\tlook for configuration files in DIR\n"
- " -u, --user=USER\trun as USER\n"
- " -D, --daemonize\trun in daemon mode (disables stderr output)\n"
- " -l, --logfile=FILE\tlog to FILE instead of stderr\n"
- " -h, --help\t\tprint this information\n"
- " -v, --verbose\t\tenable verbose logging\n"
- " -d, --debug=CATEGORY\tenable debugging for CATEGORY\n"
- "\t\t\t(use \"list\" to see available categories,\n"
- "\t\t\t or \"all\" to enable all categories)\n",
- argv ? argv[0] : "mcproxy");
-
- exit(invalid ? EXIT_FAILURE : EXIT_SUCCESS);
-}
-
-static void
-cfg_init(int argc, char **argv)
-{
- int c;
- unsigned i;
-
- assert_die(argc > 0 && argv, "invalid arguments");
-
- cfg = zmalloc(sizeof(*cfg));
- if (!cfg)
- die("malloc: %m");
-
- uring_task_init(&cfg->task, "main", NULL, cfg_free);
- list_init(&cfg->servers);
-
- cfg->cfg_dir = DEFAULT_CFG_DIR;
- cfg->announce_interval = DEFAULT_ANNOUNCE_INTERVAL;
- cfg->proxy_connection_interval = DEFAULT_PROXY_CONN_INTERVAL;
- cfg->proxy_connection_attempts = DEFAULT_PROXY_CONN_ATTEMPTS;
- cfg->socket_defer = DEFAULT_SOCKET_DEFER;
- cfg->socket_freebind = DEFAULT_SOCKET_FREEBIND;
- cfg->socket_keepalive = DEFAULT_SOCKET_KEEPALIVE;
- cfg->socket_iptos = DEFAULT_SOCKET_IPTOS;
- cfg->socket_nodelay = DEFAULT_SOCKET_NODELAY;
- cfg->uid = geteuid();
- cfg->gid = getegid();
-
- while (true) {
- int option_index = 0;
- static struct option long_options[] = {
- { "cfgdir", required_argument, 0, 'c' },
- { "cfgfile", required_argument, 0, 'C' },
- { "user", required_argument, 0, 'u' },
- { "daemonize", no_argument, 0, 'D' },
- { "logfile", required_argument, 0, 'l' },
- { "help", no_argument, 0, 'h' },
- { "verbose", no_argument, 0, 'v' },
- { "debug", required_argument, 0, 'd' },
- { 0, 0, 0, 0 }
- };
-
- c = getopt_long(argc, argv, ":c:C:u:Dl:hvd:",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 'c':
- cfg->cfg_dir = optarg;
- break;
-
- case 'C':
- cfg->cfg_file = optarg;
- break;
-
- case 'v':
- debug_mask |= DBG_VERBOSE;
- break;
-
- case 'D':
- daemonize = true;
- break;
-
- case 'l':
- log_file_path = optarg;
- break;
-
- case 'u': {
- struct passwd *pwd;
-
- errno = 0;
- pwd = getpwnam(optarg);
- if (!pwd) {
- if (errno == 0)
- errno = ESRCH;
- if (errno == ESRCH)
- die("failed to find user %s", optarg);
- else
- die("failed to find user %s (%m)", optarg);
- }
-
- debug(DBG_CFG, "asked to execute with uid %ji gid %ji",
- (intmax_t)pwd->pw_uid,
- (intmax_t)pwd->pw_gid);
- cfg->uid = pwd->pw_uid;
- cfg->gid = pwd->pw_gid;
- break;
- }
-
- case 'd':
- if (strcaseeq(optarg, "all")) {
- debug_mask = ~0;
- break;
- } else if (strcaseeq(optarg, "list")) {
- info("Debug categories:");
- info(" * all");
- for (i = 0; debug_category_str[i].name; i++)
- info(" * %s", debug_category_str[i].name);
- exit(EXIT_FAILURE);
- }
-
- for (i = 0; debug_category_str[i].name; i++) {
- if (strcaseeq(optarg, debug_category_str[i].name))
- break;
- }
-
- if (!debug_category_str[i].name)
- usage(argc, argv, true);
-
- debug_mask |= DBG_VERBOSE;
- debug_mask |= debug_category_str[i].val;
- break;
-
- case 'h':
- usage(argc, argv, false);
-
- default:
- usage(argc, argv, true);
- }
-
- }
-
- if (optind < argc)
- usage(argc, argv, true);
-}
-
-static void
-cfg_apply()
-{
- if (cfg->uid == 0 || cfg->gid == 0)
- /* This catches both -u root and running as root without -u */
- die("Execution as root is not supported (use -u <someuser>)");
-
- capng_clear(CAPNG_SELECT_BOTH);
- if (capng_updatev(CAPNG_ADD,
- CAPNG_EFFECTIVE | CAPNG_PERMITTED,
- CAP_NET_RAW, CAP_NET_BIND_SERVICE, -1))
- die("capng_updatev failed");
-
- if (geteuid() != cfg->uid) {
- if (capng_change_id(cfg->uid,
- cfg->gid,
- CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING))
- die("capng_change_id failed");
- } else {
- /*
- * This can fail if any of the caps are lacking, but it'll
- * be re-checked later.
- */
- capng_apply(CAPNG_SELECT_BOTH);
- setgroups(0, NULL);
- }
-
- if (daemonize) {
- if (daemon(1, 0) < 0)
- die("daemon() failed: %m");
- }
-
- if (log_file_path) {
- log_file = fopen(log_file_path, "ae");
- if (!log_file)
- die("fopen(%s) failed: %m", log_file_path);
- }
-
- /*
- * Do this after caps have been dropped to make sure we're not
- * accessing a directory we should have permissions to.
- */
- if (chdir(cfg->cfg_dir))
- die("chdir(%s): %m", cfg->cfg_dir);
-
- if (debug_enabled(DBG_VERBOSE)) {
- char *wd;
-
- wd = get_current_dir_name();
- verbose("Working directory: %s", wd ? wd : "<unknown>");
- free(wd);
- }
-}
-
-void
-dump_tree()
-{
- struct server *server;
-
- if (!debug_enabled(DBG_REF))
- return;
-
- info("\n\n");
- info("Dumping Tree");
- info("============");
- uring_task_refdump(&cfg->task);
- uring_refdump();
- signal_refdump();
- ptimer_refdump();
- idle_refdump();
- igmp_refdump();
- announce_refdump();
- server_cfg_monitor_refdump();
- list_for_each_entry(server, &cfg->servers, list)
- server_refdump(server);
- info("============");
- info("\n\n");
-}
-
-int
-main(int argc, char **argv)
-{
- struct server *server;
- unsigned server_count;
- struct rlimit old_rlimit;
-
- cfg_init(argc, argv);
-
- cfg_apply();
-
- cfg_read();
-
- /*
- * In the splice case we use 4 fds per proxy connection...
- */
- if (prlimit(0, RLIMIT_NOFILE, NULL, &old_rlimit) == 0) {
- struct rlimit new_rlimit;
-
- new_rlimit.rlim_cur = old_rlimit.rlim_max;
- new_rlimit.rlim_max = old_rlimit.rlim_max;
-
- if (prlimit(0, RLIMIT_NOFILE, &new_rlimit, NULL) == 0)
- debug(DBG_MALLOC, "prlimit(NOFILE): %u/%u -> %u/%u",
- (unsigned)old_rlimit.rlim_cur,
- (unsigned)old_rlimit.rlim_max,
- (unsigned)new_rlimit.rlim_cur,
- (unsigned)new_rlimit.rlim_cur);
- }
-
- uring_init();
-
- ptimer_init();
-
- igmp_init();
-
- /* Drop CAP_NET_RAW (if we have it), only used for igmp */
- capng_clear(CAPNG_SELECT_BOTH);
- if (capng_update(CAPNG_ADD,
- CAPNG_EFFECTIVE | CAPNG_PERMITTED,
- CAP_NET_BIND_SERVICE))
- die("capng_update failed");
-
- if (capng_apply(CAPNG_SELECT_BOTH)) {
- /* Try clearing all caps, shouldn't fail */
- capng_clear(CAPNG_SELECT_BOTH);
- if (capng_apply(CAPNG_SELECT_BOTH))
- die("capng_apply failed");
- }
-
- signal_init();
-
- server_cfg_monitor_init();
-
- announce_init();
-
- if (!cfg->igmp)
- announce_start(0);
-
- idle_init();
-
- uring_task_put(&cfg->task);
-
- server_count = 0;
- list_for_each_entry(server, &cfg->servers, list)
- server_count++;
-
- sd_notifyf(0, "READY=1\n"
- "STATUS=Running, %u server configurations loaded\n"
- "MAINPID=%lu",
- server_count,
- (unsigned long)getpid());
-
- info("mcproxy (%s) started, %u server configurations loaded",
- VERSION, server_count);
-
- uring_event_loop();
-
- verbose("Exiting");
-
- xfree(cfg);
- cfg = NULL;
-
- if (debug_enabled(DBG_MALLOC))
- debug_resource_usage();
-
- fflush(stdout);
- fflush(stderr);
- exit(EXIT_SUCCESS);
-}
diff --git a/mcserverproxy/main.h b/mcserverproxy/main.h
deleted file mode 100644
index 256ddae..0000000
--- a/mcserverproxy/main.h
+++ /dev/null
@@ -1,175 +0,0 @@
-#ifndef foomainhfoo
-#define foomainhfoo
-
-#include <sys/socket.h>
-#include <netinet/ip.h>
-
-struct cfg;
-
-#include "utils.h"
-
-extern struct cfg *cfg;
-extern bool exiting;
-extern unsigned debug_mask;
-
-enum debug_lvl {
- DBG_ERROR = (0x1 << 1),
- DBG_INFO = (0x1 << 2),
- DBG_VERBOSE = (0x1 << 3),
- DBG_CFG = (0x1 << 4),
- DBG_REF = (0x1 << 5),
- DBG_MALLOC = (0x1 << 6),
- DBG_ANN = (0x1 << 7),
- DBG_SIG = (0x1 << 8),
- DBG_UR = (0x1 << 9),
- DBG_SRV = (0x1 << 10),
- DBG_PROXY = (0x1 << 11),
- DBG_RCON = (0x1 << 12),
- DBG_IDLE = (0x1 << 13),
- DBG_IGMP = (0x1 << 14),
- DBG_SYSD = (0x1 << 15),
- DBG_DNS = (0x1 << 16),
- DBG_TIMER = (0x1 << 17),
-};
-
-static inline bool
-debug_enabled(enum debug_lvl lvl)
-{
- return !!(lvl & debug_mask);
-}
-
-void __debug(enum debug_lvl lvl, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
-
-#define __ifdebug(lvl, fmt, ...) \
- do { \
- if (debug_enabled((lvl))) \
- __debug((lvl), fmt "\n"__VA_OPT__(,) __VA_ARGS__); \
- } while (0)
-
-#define debug(lvl, fmt, ...) __ifdebug((lvl), "%s:%s:%i: " fmt, \
- __FILE__, __func__, __LINE__ \
- __VA_OPT__(,) __VA_ARGS__)
-#define verbose(fmt, ...) __ifdebug(DBG_VERBOSE, fmt, __VA_ARGS__)
-#define info(fmt, ...) __ifdebug(DBG_INFO, fmt, __VA_ARGS__)
-#define error(fmt, ...) __ifdebug(DBG_ERROR, "%s:%s:%i: " fmt, \
- __FILE__, __func__, __LINE__ \
- __VA_OPT__(,) __VA_ARGS__)
-
-void __die(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
-
-#define die(fmt, ...) \
- __die("%s:%s:%i: " fmt "\n", \
- __FILE__, __func__, __LINE__ \
- __VA_OPT__(,) __VA_ARGS__)
-
-#define assert_log(expr, msg) \
- ((expr) ? \
- (true) : \
- (__debug(DBG_ERROR, "%s:%s:%i: assertion \"" msg "\" failed\n", \
- __FILE__, __func__, __LINE__), false))
-
-#define assert_return(expr, ...) \
- do { \
- if (!assert_log(expr, #expr)) \
- return __VA_ARGS__; \
- } while (0)
-
-#define assert_return_silent(expr, ...) \
- do { \
- if (!(expr)) \
- return __VA_ARGS__; \
- } while (0)
-
-#define assert_die(expr, msg) \
- do { \
- if (!assert_log(expr, #expr)) \
- die(msg); \
- } while (0)
-
-#define assert_task_alive_or(lvl, t, cmd) \
-do { \
- if (!(t)) { \
- error("invalid task"); \
- cmd; \
- } \
- \
- if ((t)->dead) { \
- debug((lvl), "task dead"); \
- cmd; \
- } \
-} while(0)
-
-#define assert_task_alive(lvl, t) assert_task_alive_or((lvl), (t), return)
-
-void dump_tree();
-
-struct uring_task;
-
-/* To save typing in all the function definitions below */
-typedef void (*utask_cb_t)(struct uring_task *, int res);
-typedef int (*rutask_cb_t)(struct uring_task *, int res);
-
-struct uring_task_buf {
- char buf[4096];
- size_t len;
- size_t done;
- struct iovec iov;
- struct msghdr msg;
-};
-
-struct uring_task {
- const char *name;
- unsigned refcount;
- int fd;
- struct uring_task *parent;
- void (*free)(struct uring_task *);
- bool dead;
- struct uring_task_buf *tbuf;
-
- /* called once or repeatedly until is_complete_cb is satisfied */
- utask_cb_t cb;
-
- /* returns: 0 = not complete; < 0 = error; > 0 = complete */
- rutask_cb_t is_complete_cb;
-
- /* called once tbuf processing is done */
- utask_cb_t final_cb;
-
- /* used for recvmsg/sendmsg */
- struct saddr saddr;
- void *priv;
-};
-
-struct cfg {
- /* Options */
- uid_t uid;
- gid_t gid;
- const char *cfg_dir;
- const char *cfg_file;
- bool do_igmp;
- char *igmp_iface;
- bool splice_supported;
- uint16_t announce_interval;
- uint16_t proxy_connection_interval;
- uint16_t proxy_connection_attempts;
- bool socket_defer;
- bool socket_freebind;
- bool socket_keepalive;
- bool socket_iptos;
- bool socket_nodelay;
-
- /* Bookkeeping */
- struct uring_ev *uring;
- struct server_cfg_monitor *server_cfg_monitor;
- struct signal_ev *signal;
- struct announce *announce;
- struct ptimer *ptimer;
- struct igmp *igmp;
- struct idle *idle;
- struct sd_bus *sd_bus;
- bool sd_bus_failed;
- struct uring_task task;
- struct list_head servers;
-};
-
-#endif
diff --git a/mcserverproxy/meson.build b/mcserverproxy/meson.build
deleted file mode 100644
index e5fa7bc..0000000
--- a/mcserverproxy/meson.build
+++ /dev/null
@@ -1,36 +0,0 @@
-mcproxy_sources = [
- 'main.c',
- 'uring.c',
- 'signal-handler.c',
- 'server.c',
- 'server-proxy.c',
- 'server-config.c',
- 'server-rcon.c',
- 'announce.c',
- 'config-parser.c',
- 'idle.c',
- 'ptimer.c',
- 'igmp.c',
- 'systemd.c',
- 'utils.c'
-]
-
-dep_liburing = dependency('liburing')
-dep_libsystemd = dependency('libsystemd')
-dep_libcapng = dependency('libcap-ng')
-
-mcproxy_deps = [
- dep_liburing,
- dep_libsystemd,
- dep_libcapng,
- dep_config_h,
- dep_libshared,
-]
-
-executable(
- 'mcproxy',
- mcproxy_sources,
- link_args: [ '-lanl' ],
- dependencies: mcproxy_deps,
-)
-
diff --git a/mcserverproxy/ptimer.c b/mcserverproxy/ptimer.c
deleted file mode 100644
index 5f9cf5d..0000000
--- a/mcserverproxy/ptimer.c
+++ /dev/null
@@ -1,223 +0,0 @@
-#include <inttypes.h>
-#include <sys/timerfd.h>
-#include <string.h>
-#include <unistd.h>
-#include <time.h>
-
-#include "main.h"
-#include "uring.h"
-#include "ptimer.h"
-
-struct ptimer {
- uint64_t value;
- time_t previous_time;
- struct uring_task task;
- unsigned task_count;
- struct list_head ptasks;
-};
-
-static void
-ptimer_set(unsigned value, unsigned interval)
-{
- struct itimerspec tspec = {
- .it_interval = {
- .tv_sec = interval,
- .tv_nsec = 0
- },
- .it_value = {
- .tv_sec = value,
- .tv_nsec = 0
- }
- };
-
- assert_return(cfg->ptimer && cfg->ptimer->task.fd >= 0);
-
- if (timerfd_settime(cfg->ptimer->task.fd, 0, &tspec, NULL) != 0)
- error("timerfd_settime: %m");
-}
-
-static unsigned
-gcd(unsigned a, unsigned b)
-{
- if (a == 0)
- return b;
- return gcd(b % a, a);
-}
-
-static unsigned
-array_gcd(unsigned arr[], unsigned n)
-{
- unsigned result = arr[0];
-
- for (unsigned i = 1; i < n; i++)
- result = gcd(arr[i], result);
-
- return result;
-}
-
-static void
-ptimer_tick(struct ptimer *ptimer)
-{
- time_t now = time(NULL);
- unsigned diff = (unsigned)(now - ptimer->previous_time);
- struct ptimer_task *ptask, *ptmp;
-
- debug(DBG_TIMER, "got a tick of %u secs", diff);
- list_for_each_entry_safe(ptask, ptmp, &ptimer->ptasks, list) {
- if (ptask->remain > diff) {
- ptask->remain -= diff;
- continue;
- }
-
- debug(DBG_TIMER, "triggering ptask %p (times %u)",
- ptask, ptask->times);
-
- ptask->cb(ptask);
- ptask->remain = ptask->interval;
-
- if (ptask->times == 0)
- continue;
-
- ptask->times--;
- if (ptask->times == 0) {
- ptask->active = false;
- list_del(&ptask->list);
- }
- }
-
- ptimer->previous_time = now;
-}
-
-static void
-ptimer_reconfig(struct ptimer *ptimer)
-{
- struct ptimer_task *ptask;
- unsigned i = 0;
- unsigned lowest = ~0;
- unsigned interval;
-
- if (list_empty(&ptimer->ptasks)) {
- debug(DBG_TIMER, "no tasks");
- ptimer_set(0, 0);
- return;
- }
-
- unsigned intervals[ptimer->task_count];
-
- list_for_each_entry(ptask, &ptimer->ptasks, list) {
- if (ptask->remain < lowest)
- lowest = ptask->remain;
- intervals[i++] = ptask->interval;
- }
-
- interval = array_gcd(intervals, i);
-
- debug(DBG_TIMER, "lowest: %u, gcd: %u\n", lowest, interval);
- ptimer_set(lowest, interval);
-}
-
-void
-ptimer_del_task(struct ptimer_task *ptask)
-{
- struct ptimer *ptimer = cfg->ptimer;
-
- assert_return(ptask && ptimer);
- assert_return_silent(ptask->active);
- assert_return(ptimer->task_count > 0);
-
- list_del(&ptask->list);
- ptask->active = false;
- ptimer->task_count--;
- ptimer_tick(ptimer);
- ptimer_reconfig(ptimer);
- uring_task_put(&ptimer->task);
-}
-
-void
-ptimer_add_task(struct ptimer_task *ptask)
-{
- struct ptimer *ptimer = cfg->ptimer;
-
- assert_return(ptask && ptask->interval > 0 && ptask->cb && ptimer);
- assert_return_silent(!ptask->active);
-
- uring_task_get(&ptimer->task);
- ptask->active = true;
- ptask->remain = ptask->interval;
- ptimer_tick(ptimer);
- list_add(&ptask->list, &ptimer->ptasks);
- ptimer->task_count++;
- ptimer_reconfig(ptimer);
-}
-
-void
-ptimer_refdump()
-{
- assert_return(cfg->ptimer);
-
- uring_task_refdump(&cfg->ptimer->task);
-}
-
-static void
-ptimer_free(struct uring_task *task)
-{
- struct ptimer *ptimer = container_of(task, struct ptimer, task);
-
- assert_return(task);
-
- debug(DBG_TIMER, "task %p, ptimer %p", task, ptimer);
- xfree(ptimer);
- cfg->ptimer = NULL;
-}
-
-void
-ptimer_delete()
-{
- assert_return(cfg->ptimer);
-
- debug(DBG_TIMER, "closing fd %i", cfg->ptimer->task.fd);
- uring_task_destroy(&cfg->ptimer->task);
-}
-
-static void
-ptimer_cb(struct uring_task *task, int res)
-{
- struct ptimer *ptimer = container_of(task, struct ptimer, task);
-
- assert_return(task);
- assert_task_alive(DBG_IGMP, task);
-
- if (res != sizeof(ptimer->value)) {
- error("timerfd_read: res: %i, %m", res);
- return;
- }
-
- ptimer_tick(ptimer);
- uring_read(&ptimer->task, &ptimer->value, sizeof(ptimer->value), ptimer_cb);
-}
-
-void
-ptimer_init()
-{
- struct ptimer *ptimer;
- int tfd;
-
- assert_return(!cfg->ptimer);
-
- ptimer = zmalloc(sizeof(*ptimer));
- if (!ptimer)
- die("malloc: %m");
-
- tfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
- if (tfd < 0)
- die("timerfd_create: %m");
-
- ptimer->task_count = 0;
- ptimer->previous_time = time(NULL);
- list_init(&ptimer->ptasks);
- uring_task_init(&ptimer->task, "ptimer", uring_parent(), ptimer_free);
- uring_task_set_fd(&ptimer->task, tfd);
- cfg->ptimer = ptimer;
- uring_read(&ptimer->task, &ptimer->value, sizeof(ptimer->value), ptimer_cb);
-}
-
diff --git a/mcserverproxy/ptimer.h b/mcserverproxy/ptimer.h
deleted file mode 100644
index 0b53590..0000000
--- a/mcserverproxy/ptimer.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef fooptimerhfoo
-#define fooptimerhfoo
-
-struct ptimer_task {
- unsigned interval;
- unsigned times;
- void (*cb)(struct ptimer_task *);
- bool active;
- unsigned remain;
- struct list_head list;
-};
-
-static inline void
-ptask_init(struct ptimer_task *ptask, unsigned interval,
- unsigned times, void(*cb)(struct ptimer_task *))
-{
- ptask->interval = interval;
- ptask->times = times;
- ptask->cb = cb;
- ptask->active = false;
-}
-
-void ptimer_del_task(struct ptimer_task *ptask);
-
-void ptimer_add_task(struct ptimer_task *ptask);
-
-void ptimer_refdump();
-
-void ptimer_delete();
-
-void ptimer_init();
-
-#endif
diff --git a/mcserverproxy/server-config.c b/mcserverproxy/server-config.c
deleted file mode 100644
index 549cf16..0000000
--- a/mcserverproxy/server-config.c
+++ /dev/null
@@ -1,580 +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 "config-parser.h"
-#include "server.h"
-#include "server-config.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 server_cfg_monitor {
- struct uring_task task;
- char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event))));
-};
-
-static void
-scfgm_free(struct uring_task *task)
-{
- struct server_cfg_monitor *scfgm = container_of(task,
- struct server_cfg_monitor,
- task);
-
- assert_return(task);
-
- debug(DBG_CFG, "called");
- xfree(scfgm);
- cfg->server_cfg_monitor = 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 server_cfg_monitor *scfgm = container_of(task,
- struct server_cfg_monitor,
- 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 = scfgm->buf; ptr < scfgm->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(&scfgm->task, scfgm->buf, sizeof(scfgm->buf), inotify_cb);
-}
-
-void
-server_cfg_monitor_refdump()
-{
- assert_return_silent(cfg->server_cfg_monitor);
-
- uring_task_refdump(&cfg->server_cfg_monitor->task);
-}
-
-void
-server_cfg_monitor_delete()
-{
- assert_return(cfg->server_cfg_monitor);
-
- debug(DBG_CFG, "closing fd %i", cfg->server_cfg_monitor->task.fd);
- uring_task_destroy(&cfg->server_cfg_monitor->task);
- cfg->server_cfg_monitor = NULL;
-}
-
-void
-server_cfg_monitor_init()
-{
- int ifd;
- int iwd;
- struct server_cfg_monitor *scfgm;
- DIR *dir;
- struct dirent *dent;
- struct server *server;
-
- assert_return(!cfg->server_cfg_monitor);
-
- scfgm = zmalloc(sizeof(*scfgm));
- if (!scfgm)
- 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(&scfgm->task, "server-config-monitor", uring_parent(), scfgm_free);
- uring_task_set_fd(&scfgm->task, ifd);
- cfg->server_cfg_monitor = scfgm;
- uring_read(&scfgm->task, scfgm->buf, sizeof(scfgm->buf), inotify_cb);
-
- dir = opendir(".");
- if (!dir)
- die("opendir(%s): %m", cfg->cfg_dir);
-
- 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);
-}
-
diff --git a/mcserverproxy/server-config.h b/mcserverproxy/server-config.h
deleted file mode 100644
index 590dae0..0000000
--- a/mcserverproxy/server-config.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef fooserverconfighfoo
-#define fooserverconfighfoo
-
-void server_cfg_monitor_delete();
-
-void server_cfg_monitor_refdump();
-
-void server_cfg_monitor_init();
-
-#endif
diff --git a/mcserverproxy/server-proxy.c b/mcserverproxy/server-proxy.c
deleted file mode 100644
index 4cbbb87..0000000
--- a/mcserverproxy/server-proxy.c
+++ /dev/null
@@ -1,578 +0,0 @@
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <unistd.h>
-#include <time.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "main.h"
-#include "uring.h"
-#include "ptimer.h"
-#include "server.h"
-#include "server-proxy.h"
-#include "utils.h"
-
-static void
-format_bytes(char *buf, size_t len, uint64_t val)
-{
- uint64_t tmp;
- const char *suffix = "B";
-
- assert_return(buf && len > 0);
-
- tmp = val * 10;
- if (val > 1152921504606846976ULL) {
- tmp = val / 115292150460684697ULL;
- suffix= "EiB";
- } else if (val > 1125899906842624ULL) {
- tmp /= 1125899906842624ULL;
- suffix = "PiB";
- } else if (val > 1099511627776ULL) {
- tmp /= 1099511627776ULL;
- suffix = "TiB";
- } else if (val > 1073741824ULL) {
- tmp /= 1073741824ULL;
- suffix = "GiB";
- } else if (val > 1048576) {
- tmp /= 1048576;
- suffix = "MiB";
- } else if (val > 1024) {
- tmp /= 1024;
- suffix = "KiB";
- }
-
- snprintf(buf, len, "%lu.%lu %s", tmp / 10, tmp % 10, suffix);
-}
-
-static void
-format_time(char *buf, size_t len, time_t diff)
-{
- unsigned hh, mm, ss;
-
- assert_return(buf && len > 0);
-
- hh = diff / 3600;
- diff %= 3600;
- mm = diff / 60;
- diff %= 60;
- ss = diff;
-
- snprintf(buf, len, "%02u:%02u:%02u", hh, mm, ss);
-}
-
-static void
-proxy_free(struct uring_task *task)
-{
- struct server_proxy *proxy = container_of(task, struct server_proxy, task);
- char cts[100];
- char stc[100];
- char duration[100];
-
- assert_return(task);
-
- debug(DBG_PROXY, "server: %s, src: %s, dst: %s",
- proxy->server->name,
- proxy->client_conn.remote.addrstr,
- proxy->server_conn.remote.addrstr);
-
- if (proxy->begin > 0) {
- format_time(duration, sizeof(duration), time(NULL) - proxy->begin);
- format_bytes(cts, sizeof(cts), proxy->client_bytes);
- format_bytes(stc, sizeof(stc), proxy->server_bytes);
-
- info("%s: proxy connection %s -> %s closed "
- "(CtS: %s, StC: %s), duration %s",
- proxy->server->name,
- proxy->client_conn.remote.addrstr,
- proxy->server_conn.remote.addrstr,
- cts, stc, duration);
- }
-
- list_del(&proxy->list);
- xfree(proxy);
-}
-
-static void
-proxy_client_free(struct uring_task *task)
-{
- struct server_proxy *proxy = container_of(task, struct server_proxy, clienttask);
-
- assert_return(task);
-
- debug(DBG_PROXY, "%s: client connection closed", proxy->server->name);
-}
-
-static void
-proxy_server_free(struct uring_task *task)
-{
- struct server_proxy *proxy = container_of(task, struct server_proxy, servertask);
-
- assert_return(task);
-
- debug(DBG_PROXY, "%s: server connection closed", proxy->server->name);
-}
-
-void
-proxy_delete(struct server_proxy *proxy)
-{
- debug(DBG_PROXY, "%s: shutting down proxy %p", proxy->server->name, proxy);
-
- assert_return(proxy);
-
- ptimer_del_task(&proxy->ptask);
-
- if (cfg->splice_supported) {
- uring_close(&proxy->server->task, proxy->cpipe[PIPE_RD]);
- uring_close(&proxy->server->task, proxy->cpipe[PIPE_WR]);
- uring_close(&proxy->server->task, proxy->spipe[PIPE_RD]);
- uring_close(&proxy->server->task, proxy->spipe[PIPE_WR]);
- }
-
- uring_task_set_fd(&proxy->servertask, proxy->sfd);
- uring_task_destroy(&proxy->servertask);
- uring_task_set_fd(&proxy->clienttask, proxy->cfd);
- uring_task_destroy(&proxy->clienttask);
- uring_task_destroy(&proxy->task);
-}
-
-/*
- * These four functions provide the fallback read-write mode
- */
-static void proxy_client_read(struct uring_task *task, int res);
-
-static void
-proxy_client_written(struct uring_task *task, int res)
-{
- struct server_proxy *proxy = container_of(task, struct server_proxy, clienttask);
-
- assert_return(task);
- assert_task_alive(DBG_PROXY, task);
-
- if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
- proxy_delete(proxy);
- return;
- }
-
- proxy->client_bytes += res;
- uring_task_set_fd(&proxy->clienttask, proxy->cfd);
- uring_tbuf_read(task, proxy_client_read);
-}
-
-static void
-proxy_client_read(struct uring_task *task, int res)
-{
- struct server_proxy *proxy = container_of(task, struct server_proxy, clienttask);
-
- assert_return(task);
- assert_task_alive(DBG_PROXY, task);
-
- if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
- proxy_delete(proxy);
- return;
- }
-
- uring_task_set_fd(&proxy->clienttask, proxy->sfd);
- uring_tbuf_write(task, proxy_client_written);
-}
-
-static void proxy_server_read(struct uring_task *task, int res);
-
-static void
-proxy_server_written(struct uring_task *task, int res)
-{
- struct server_proxy *proxy = container_of(task, struct server_proxy, servertask);
-
- assert_return(task);
- assert_task_alive(DBG_PROXY, task);
-
- if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
- proxy_delete(proxy);
- return;
- }
-
- proxy->server_bytes += res;
- uring_task_set_fd(&proxy->servertask, proxy->sfd);
- uring_tbuf_read(&proxy->servertask, proxy_server_read);
-}
-
-static void
-proxy_server_read(struct uring_task *task, int res)
-{
- struct server_proxy *proxy = container_of(task, struct server_proxy, servertask);
-
- assert_return(task);
- assert_task_alive(DBG_PROXY, task);
-
- if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
- proxy_delete(proxy);
- return;
- }
-
- uring_task_set_fd(&proxy->servertask, proxy->cfd);
- uring_tbuf_write(task, proxy_server_written);
-}
-
-/*
- * These four functions provide the splice fd->pipe->fd mode
- */
-static void proxy_client_spliced_in(struct uring_task *task, int res);
-
-static void
-proxy_client_spliced_out(struct uring_task *task, int res)
-{
- struct server_proxy *proxy = container_of(task, struct server_proxy, servertask);
-
- assert_return(task);
- assert_task_alive(DBG_PROXY, task);
-
- if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
- proxy_delete(proxy);
- return;
- }
-
- uring_splice(task, proxy->cfd, proxy->cpipe[PIPE_WR], proxy_client_spliced_in);
-}
-
-static void
-proxy_client_spliced_in(struct uring_task *task, int res)
-{
- struct server_proxy *proxy = container_of(task, struct server_proxy, servertask);
-
- assert_return(task);
- assert_task_alive(DBG_PROXY, task);
-
- if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
- proxy_delete(proxy);
- return;
- }
-
- uring_splice(task, proxy->cpipe[PIPE_RD], proxy->sfd, proxy_client_spliced_out);
-}
-
-static void proxy_server_spliced_in(struct uring_task *task, int res);
-
-static void
-proxy_server_spliced_out(struct uring_task *task, int res)
-{
- struct server_proxy *proxy = container_of(task, struct server_proxy, servertask);
-
- assert_return(task);
- assert_task_alive(DBG_PROXY, task);
-
- if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
- proxy_delete(proxy);
- return;
- }
-
- uring_splice(task, proxy->sfd, proxy->spipe[PIPE_WR], proxy_server_spliced_in);
-}
-
-static void
-proxy_server_spliced_in(struct uring_task *task, int res)
-{
- struct server_proxy *proxy = container_of(task, struct server_proxy, servertask);
-
- assert_return(task);
- assert_task_alive(DBG_PROXY, task);
-
- if (res <= 0) {
- debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res);
- proxy_delete(proxy);
- return;
- }
-
- uring_splice(task, proxy->spipe[PIPE_RD], proxy->cfd, proxy_server_spliced_out);
-}
-
-static void
-proxy_connected_cb(struct connection *conn, bool connected)
-{
- struct server_proxy *proxy = container_of(conn, struct server_proxy, server_conn);
-
- assert_return(conn);
- assert_task_alive(DBG_PROXY, &proxy->clienttask);
- assert_task_alive(DBG_PROXY, &proxy->servertask);
-
- proxy->connecting = false;
- if (!connected) {
- error("%s: proxy connection to remote server failed",
- proxy->server->name);
- if (!proxy->ptask.active)
- proxy_delete(proxy);
- return;
- }
-
- ptimer_del_task(&proxy->ptask);
-
- proxy->sfd = proxy->servertask.fd;
- verbose("%s: proxy connection %s -> %s opened",
- proxy->server->name,
- proxy->client_conn.remote.addrstr,
- proxy->server_conn.remote.addrstr);
- proxy->begin = time(NULL);
-
- if (cfg->splice_supported) {
- debug(DBG_PROXY, "handling proxy connection with splice");
- uring_splice(&proxy->clienttask, proxy->cfd, proxy->cpipe[PIPE_WR], proxy_client_spliced_in);
- uring_splice(&proxy->servertask, proxy->sfd, proxy->spipe[PIPE_WR], proxy_server_spliced_in);
- } else {
- debug(DBG_PROXY, "handling proxy connection with read-write");
- uring_tbuf_read(&proxy->clienttask, proxy_client_read);
- uring_tbuf_read(&proxy->servertask, proxy_server_read);
- }
-}
-
-void
-proxy_refdump(struct server_proxy *proxy)
-{
- assert_return(proxy);
-
- uring_task_refdump(&proxy->task);
- uring_task_refdump(&proxy->clienttask);
- uring_task_refdump(&proxy->servertask);
-}
-
-static void
-proxy_connect_timer_cb(struct ptimer_task *ptask)
-{
- struct server_proxy *proxy = container_of(ptask, struct server_proxy, ptask);
-
- assert_return(ptask);
-
- if (proxy->connecting)
- return;
-
- proxy->connecting = true;
- connect_any(&proxy->servertask, &proxy->server->remotes,
- &proxy->server_conn, proxy_connected_cb);
-}
-
-struct server_proxy *
-proxy_new(struct server *server, struct saddr *client, int fd)
-{
- struct server_proxy *proxy;
-
- assert_return(server && client && fd > 0, NULL);
-
- proxy = zmalloc(sizeof(*proxy));
- if (!proxy) {
- error("malloc: %m");
- goto out;
- }
-
- if (cfg->splice_supported) {
- if (pipe2(proxy->cpipe, O_CLOEXEC) < 0) {
- error("pipe2: %m");
- goto out_free;
- }
-
- if (pipe2(proxy->spipe, O_CLOEXEC) < 0) {
- error("pipe2: %m");
- goto out_close_cpipe;
- }
- }
-
- proxy->sfd = -1;
- proxy->cfd = fd;
- proxy->server = server;
- uring_task_init(&proxy->task, "proxy", &server->task, proxy_free);
-
- connection_set_local(&proxy->client_conn, fd);
- connection_set_remote(&proxy->client_conn, client);
-
- uring_task_init(&proxy->clienttask, "proxy_client", &proxy->task,
- proxy_client_free);
- uring_task_set_buf(&proxy->clienttask, &proxy->clientbuf);
- uring_task_set_fd(&proxy->clienttask, fd);
-
- uring_task_init(&proxy->servertask, "proxy_server", &proxy->task,
- proxy_server_free);
- uring_task_set_buf(&proxy->servertask, &proxy->serverbuf);
-
- list_add(&proxy->list, &server->proxys);
-
- if (server->state != SERVER_STATE_RUNNING) {
- if (server_start(server) &&
- cfg->proxy_connection_interval > 0 &&
- cfg->proxy_connection_attempts > 0) {
- ptask_init(&proxy->ptask,
- cfg->proxy_connection_interval,
- cfg->proxy_connection_attempts,
- proxy_connect_timer_cb);
- ptimer_add_task(&proxy->ptask);
- }
- }
-
- proxy->connecting = true;
- connect_any(&proxy->servertask, &server->remotes,
- &proxy->server_conn, proxy_connected_cb);
-
- return proxy;
-
-out_close_cpipe:
- uring_close(&server->task, proxy->cpipe[PIPE_RD]);
- uring_close(&server->task, proxy->cpipe[PIPE_WR]);
-out_free:
- xfree(proxy);
-out:
- return NULL;
-}
-
-static void
-local_accept(struct uring_task *task, int res)
-{
- struct server_local *local = container_of(task, struct server_local, task);
- struct server *server = container_of(task->parent, struct server, task);
- struct server_proxy *proxy;
-
- assert_return(task);
- assert_task_alive(DBG_PROXY, task);
-
- debug(DBG_PROXY, "task %p, res %i, server %s", task, res, server->name);
-
- if (res < 0) {
- error("res: %i", res);
- goto out;
- }
-
- saddr_set_addrstr(&local->client);
-
- verbose("%s: incoming proxy connection: %s -> %s",
- server->name, local->client.addrstr, local->local.addrstr);
-
- if (list_empty(&server->remotes)) {
- /* This shouldn't be possible, checked before opening local */
- error("server->remotes empty!");
- uring_close(&local->task, res);
- goto out;
- }
-
- proxy = proxy_new(server, &local->client, res);
- if (!proxy)
- uring_close(&local->task, res);
-
-out:
- uring_accept(&local->task, &local->client, local_accept);
-}
-
-bool
-local_open(struct server_local *local)
-{
- int sfd;
- int option;
- int r;
-
- assert_return(local && local->server, false);
-
- sfd = socket(local->local.storage.ss_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
- if (sfd < 0) {
- error("socket: %m");
- goto error;
- }
-
- option = true;
- if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)) < 0) {
- error("setsockopt: %m");
- goto error;
- }
-
- /* The MC protocol expects the client to send data first */
- if (cfg->socket_defer) {
- option = true;
- if (setsockopt(sfd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &option, sizeof(option)) < 0)
- error("setsockopt: %m");
- }
-
- /*
- * This has the advantage that interfaces don't need to be up but
- * it means that cfg errors will not be caught.
- */
- if (cfg->socket_freebind) {
- option = true;
- if (setsockopt(sfd, IPPROTO_IP, IP_FREEBIND, &option, sizeof(option)) < 0)
- error("setsockopt: %m");
- }
-
- socket_set_low_latency(sfd);
-
- r = bind(sfd, (struct sockaddr *)&local->local.storage, local->local.addrlen);
- if (r < 0) {
- error("bind: %m");
- goto error;
- }
-
- r = listen(sfd, 100);
- if (r < 0) {
- error("listen: %m");
- goto error;
- }
-
- uring_task_set_fd(&local->task, sfd);
- uring_accept(&local->task, &local->client, local_accept);
- return true;
-
-error:
- if (sfd >= 0)
- uring_close(&local->task, sfd);
- return false;
-}
-
-void
-local_refdump(struct server_local *local)
-{
- assert_return(local);
-
- uring_task_refdump(&local->task);
-}
-
-static void
-local_free(struct uring_task *task)
-{
- struct server_local *local = container_of(task, struct server_local, task);
-
- assert_return(task);
-
- debug(DBG_PROXY, "task %p, local %p", task, local);
- list_del(&local->list);
- xfree(local);
-}
-
-void
-local_delete(struct server_local *local)
-{
- assert_return(local);
-
- uring_task_destroy(&local->task);
-}
-
-struct server_local *
-local_new(struct server *server, struct saddr *saddr)
-{
- struct server_local *local;
-
- assert_return(server && saddr, NULL);
-
- local = zmalloc(sizeof(*local));
- if (!local) {
- error("malloc: %m");
- return NULL;
- }
-
- debug(DBG_PROXY, "%s adding local: %s", server->name, saddr->addrstr);
- local->local = *saddr;
- local->server = server;
- uring_task_init(&local->task, "local", &server->task, local_free);
- xfree(saddr);
- return local;
-}
-
diff --git a/mcserverproxy/server-proxy.h b/mcserverproxy/server-proxy.h
deleted file mode 100644
index ee3bda3..0000000
--- a/mcserverproxy/server-proxy.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef fooserverproxyhfoo
-#define fooserverproxyhfoo
-
-struct server_proxy {
- struct connection client_conn;
- struct uring_task_buf clientbuf;
- struct uring_task clienttask;
- uint64_t client_bytes;
- int cpipe[2];
- int cfd;
-
- struct connection server_conn;
- struct uring_task_buf serverbuf;
- struct uring_task servertask;
- uint64_t server_bytes;
- int spipe[2];
- int sfd;
-
- bool connecting;
- time_t begin;
- struct ptimer_task ptask;
- struct uring_task task;
- struct server *server;
- struct list_head list;
-};
-
-void proxy_refdump(struct server_proxy *proxy);
-
-void proxy_delete(struct server_proxy *proxy);
-
-struct server_proxy *proxy_new(struct server *server, struct saddr *client,
- int fd);
-
-struct server_local {
- struct saddr local;
- struct saddr client;
- struct uring_task task;
-
- struct server *server;
- struct list_head list;
-};
-
-bool local_open(struct server_local *local);
-
-void local_refdump(struct server_local *local);
-
-void local_delete(struct server_local *local);
-
-struct server_local *local_new(struct server *server, struct saddr *saddr);
-
-#endif
diff --git a/mcserverproxy/server-rcon.c b/mcserverproxy/server-rcon.c
deleted file mode 100644
index 1f8ef70..0000000
--- a/mcserverproxy/server-rcon.c
+++ /dev/null
@@ -1,227 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/ip.h>
-#include <arpa/inet.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <errno.h>
-
-#include "main.h"
-#include "uring.h"
-#include "server.h"
-#include "server-rcon.h"
-#include "rcon-protocol.h"
-
-static int
-rcon_packet_complete(struct uring_task *task, int res)
-{
- assert_return(task, -EINVAL);
- assert_task_alive_or(DBG_RCON, task, return -EINTR);
-
- return rcon_protocol_packet_complete(task->tbuf->buf, task->tbuf->len);
-}
-
-static bool
-rcon_check_reply(struct uring_task *task, int res, int32_t *id,
- int32_t *type, const char **msg)
-{
- struct server *server = container_of(task, struct server, rcon_task);
- const char *error;
-
- if (res < 0) {
- error("rcon(%s): reading reply failed, res: %i",
- server->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);
- goto error;
- }
-
- return true;
-
-error:
- uring_task_close_fd(task);
- return false;
-}
-
-static void
-rcon_stop_reply(struct uring_task *task, int res)
-{
- struct server *server = container_of(task, struct server, rcon_task);
- int32_t id;
- int32_t type;
- const char *msg;
-
- assert_return(task);
- assert_task_alive(DBG_RCON, task);
-
- if (!rcon_check_reply(task, res, &id, &type, &msg))
- return;
-
- if (id != 2) {
- error("rcon(%s): stop cmd failed, reply id (%" PRIi32 ")",
- server->name, id);
- goto out;
- } else if (type != RCON_PACKET_RESPONSE) {
- error("rcon(%s): stop cmd failed, reply type (%" PRIi32 ")",
- server->name, type);
- goto out;
- }
-
- verbose("rcon(%s): stop command sent, reply: %s", server->name, msg);
-
-out:
- uring_task_close_fd(task);
-}
-
-static void
-rcon_stop_sent(struct uring_task *task, int res)
-{
- struct server *server = container_of(task, struct server, rcon_task);
-
- assert_return(task);
- assert_task_alive(DBG_RCON, task);
-
- if (res != task->tbuf->len) {
- error("rcon(%s): sending stop cmd failed, res: %i",
- server->name, res);
- uring_task_close_fd(task);
- return;
- }
-
- debug(DBG_RCON, "rcon(%s): stop cmd sent", server->name);
- uring_tbuf_read_until(task, rcon_packet_complete, rcon_stop_reply);
-}
-
-static void
-rcon_login_reply(struct uring_task *task, int res)
-{
- struct server *server = container_of(task, struct server, rcon_task);
- int32_t id;
- int32_t type;
- const char *msg;
-
- assert_return(task);
- assert_task_alive(DBG_RCON, task);
-
- if (!rcon_check_reply(task, res, &id, &type, &msg))
- return;
-
- if (id != 1) {
- error("rcon(%s): login failed, reply id (%" PRIi32 ")",
- server->name, id);
- goto error;
- } else if (type == RCON_PACKET_LOGIN_FAIL) {
- error("rcon(%s): login failed, incorrect password",
- server->name);
- goto error;
- } else if (type != RCON_PACKET_LOGIN_OK) {
- error("rcon(%s): login failed, reply type (%" PRIi32 ")",
- server->name, type);
- goto error;
- }
-
- debug(DBG_RCON, "rcon(%s): login successful", server->name);
- rcon_protocol_create_packet(task->tbuf->buf, sizeof(task->tbuf->buf),
- &task->tbuf->len, 2, RCON_PACKET_COMMAND,
- "stop");
- uring_tbuf_write(task, rcon_stop_sent);
- return;
-
-error:
- uring_task_close_fd(task);
-}
-
-static void
-rcon_login_sent(struct uring_task *task, int res)
-{
- struct server *server = container_of(task, struct server, rcon_task);
-
- assert_return(task);
- assert_task_alive(DBG_RCON, task);
-
- if (res != task->tbuf->len) {
- error("rcon(%s): sending login failed, res: %i",
- server->name, res);
- uring_task_close_fd(task);
- return;
- }
-
- debug(DBG_RCON, "rcon(%s): login sent", server->name);
- uring_tbuf_read_until(task, rcon_packet_complete, rcon_login_reply);
-}
-
-static void
-rcon_connected_cb(struct connection *conn, bool connected)
-{
- struct server *server = container_of(conn, struct server, rcon_conn);
-
- assert_return(conn);
- assert_task_alive(DBG_RCON, &server->rcon_task);
-
- if (!connected) {
- error("rcon (%s): connection failed", server->name);
- return;
- }
-
- rcon_protocol_create_packet(server->rcon_tbuf.buf,
- sizeof(server->rcon_tbuf.buf),
- &server->rcon_tbuf.len, 1,
- RCON_PACKET_LOGIN,
- server->rcon_password);
- uring_tbuf_write(&server->rcon_task, rcon_login_sent);
-}
-
-static void
-rcon_free(struct uring_task *task)
-{
- struct server *server = container_of(task, struct server, rcon_task);
-
- assert_return(task);
-
- debug(DBG_RCON, "task %p, server %s (%p)", task, server->name, server);
-}
-
-void
-rcon_stop(struct server *server)
-{
- assert_return(server && !list_empty(&server->rcons) && !empty_str(server->rcon_password));
- assert_task_alive(DBG_RCON, &server->rcon_task);
-
- connect_any(&server->rcon_task, &server->rcons, &server->rcon_conn, rcon_connected_cb);
-}
-
-void
-rcon_refdump(struct server *server)
-{
- assert_return(server);
-
- uring_task_refdump(&server->rcon_task);
-}
-
-void
-rcon_delete(struct server *server)
-{
- assert_return(server);
-
- debug(DBG_RCON, "closing fd %i", server->rcon_task.fd);
- uring_task_destroy(&server->rcon_task);
-}
-
-void
-rcon_init(struct server *server)
-{
- assert_return(server);
-
- uring_task_init(&server->rcon_task, "rcon", &server->task, rcon_free);
- uring_task_set_buf(&server->rcon_task, &server->rcon_tbuf);
-}
-
diff --git a/mcserverproxy/server-rcon.h b/mcserverproxy/server-rcon.h
deleted file mode 100644
index 6625f25..0000000
--- a/mcserverproxy/server-rcon.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef fooserverrconhfoo
-#define fooserverrconhfoo
-
-void rcon_stop(struct server *server);
-
-void rcon_refdump(struct server *server);
-
-void rcon_delete(struct server *server);
-
-void rcon_init(struct server *server);
-
-#endif
diff --git a/mcserverproxy/server.c b/mcserverproxy/server.c
deleted file mode 100644
index de42721..0000000
--- a/mcserverproxy/server.c
+++ /dev/null
@@ -1,837 +0,0 @@
-#define _GNU_SOURCE
-#include <stdlib.h>
-#include <string.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sched.h>
-#include <poll.h>
-#include <errno.h>
-#include <sched.h>
-
-#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 : "<undefined>");
- 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;
-}
diff --git a/mcserverproxy/server.h b/mcserverproxy/server.h
deleted file mode 100644
index ff4c28e..0000000
--- a/mcserverproxy/server.h
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef fooserverhfoo
-#define fooserverhfoo
-
-enum server_state {
- SERVER_STATE_INIT = 0,
- SERVER_STATE_CFG_OK = 1,
- SERVER_STATE_RUNNING = 2,
- SERVER_STATE_STOPPED = 3,
- SERVER_STATE_DEAD = 4,
-};
-
-enum server_type {
- SERVER_TYPE_UNDEFINED,
- SERVER_TYPE_ANNOUNCE,
- SERVER_TYPE_PROXY,
-};
-
-enum server_stop_method {
- SERVER_STOP_METHOD_UNDEFINED,
- SERVER_STOP_METHOD_RCON,
- SERVER_STOP_METHOD_SYSTEMD,
- SERVER_STOP_METHOD_EXEC,
-};
-
-enum server_start_method {
- SERVER_START_METHOD_UNDEFINED,
- SERVER_START_METHOD_SYSTEMD,
- SERVER_START_METHOD_EXEC,
-};
-
-struct server {
- enum server_type type;
- char *name;
- char *pretty_name;
- uint16_t announce_port;
- struct list_head locals;
- struct list_head remotes;
- struct list_head proxys;
- struct list_head rcons;
- struct list_head dnslookups;
- enum server_state state;
-
- enum server_stop_method stop_method;
- enum server_start_method start_method;
-
- /* For calling external start/stop executables */
- char *stop_exec;
- char *start_exec;
- struct uring_task exec_task;
-
- /* For systemd services */
- char *systemd_service;
- char *systemd_obj;
-
- /* For rcon connections */
- char *rcon_password;
- struct connection rcon_conn;
- struct uring_task rcon_task;
- struct uring_task_buf rcon_tbuf;
-
- /* For announce messages */
- struct uring_task ann_task;
- struct uring_task_buf ann_buf;
-
- /* For checking idle status */
- struct uring_task idle_task;
- struct connection idle_conn;
- struct uring_task_buf idle_buf;
- unsigned idle_timeout;
- unsigned idle_count;
-
- /* For reading config files */
- struct uring_task task;
- struct uring_task_buf tbuf;
-
- struct list_head list;
-};
-
-void server_refdump(struct server *server);
-
-void server_delete(struct server *server);
-
-void server_delete_by_name(const char *name);
-
-bool server_start(struct server *server);
-
-bool server_stop(struct server *server);
-
-void server_set_active_players(struct server *server, int count);
-
-bool server_idle_check(struct server *server);
-
-bool server_announce(struct server *server, int fd);
-
-bool server_commit(struct server *server);
-
-bool server_add_remote(struct server *server, struct saddr *remote);
-
-bool server_add_local(struct server *server, struct saddr *saddr);
-
-bool server_add_rcon(struct server *server, struct saddr *rcon);
-
-bool server_set_rcon_password(struct server *server, const char *password);
-
-bool server_set_systemd_service(struct server *server, const char *service);
-
-bool server_set_stop_method(struct server *server,
- enum server_stop_method stop_method);
-
-bool server_set_start_method(struct server *server,
- enum server_start_method start_method);
-
-bool server_set_stop_exec(struct server *server, const char *cmd);
-
-bool server_set_start_exec(struct server *server, const char *cmd);
-
-bool server_set_idle_timeout(struct server *server, uint16_t timeout);
-
-bool server_set_port(struct server *server, uint16_t port);
-
-bool server_set_type(struct server *server, enum server_type type);
-
-bool server_set_pretty_name(struct server *server, const char *pretty_name);
-
-struct server *server_new(const char *name);
-
-#endif
-
diff --git a/mcserverproxy/signal-handler.c b/mcserverproxy/signal-handler.c
deleted file mode 100644
index 67c2e0b..0000000
--- a/mcserverproxy/signal-handler.c
+++ /dev/null
@@ -1,195 +0,0 @@
-#define _GNU_SOURCE
-#include <sys/signalfd.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <systemd/sd-daemon.h>
-
-#include "main.h"
-#include "signal-handler.h"
-#include "uring.h"
-#include "server.h"
-#include "server-config.h"
-#include "config-parser.h"
-#include "igmp.h"
-#include "announce.h"
-#include "idle.h"
-#include "ptimer.h"
-
-struct signal_ev {
- struct uring_task task;
- struct uring_task_buf tbuf;
- int pipe[2];
-};
-
-static void
-signal_delete()
-{
- assert_return(cfg->signal);
-
- uring_task_destroy(&cfg->signal->task);
-}
-
-static void
-signalfd_read(struct uring_task *task, int res)
-{
- struct signal_ev *signal = container_of(task, struct signal_ev, task);
- struct server *server, *stmp;
- static unsigned count = 0;
- siginfo_t *si;
-
- assert_return(task);
- assert_task_alive(DBG_SIG, task);
-
- si = (siginfo_t *)task->tbuf->buf;
- if (res != sizeof(*si))
- die("error in signalfd (%i)", res);
-
- switch (si->si_signo) {
- case SIGUSR1: {
- struct dns_async *dns;
-
- debug(DBG_SIG, "Got a SIGUSR1");
- if (si->si_code != SI_ASYNCNL || !si->si_ptr) {
- error("SIGUSR1: unexpected values in siginfo");
- goto out;
- }
-
- dns = si->si_ptr;
- if (!dns->cb) {
- error("DNS callback not set");
- goto out;
- }
-
- debug(DBG_DNS, "DNS lookup complete, dns: %p, dns->cb: %p",
- dns, dns->cb);
- dns->cb(dns);
- break;
- }
-
- case SIGUSR2:
- debug(DBG_SIG, "got a SIGUSR2");
- dump_tree();
- break;
-
- case SIGTERM:
- debug(DBG_SIG, "Got a SIGINT/SIGHUP");
- verbose("got a signal to quit");
- sd_notifyf(0, "STOPPING=1\nSTATUS=Received signal, exiting");
- exit(EXIT_SUCCESS);
- break;
-
- case SIGINT:
- case SIGHUP:
- count++;
- if (count > 5) {
- dump_tree();
- exit(EXIT_FAILURE);
- }
-
- verbose("got a signal to dump tree");
- sd_notifyf(0, "STOPPING=1\nSTATUS=Received signal, exiting");
- dump_tree();
- signal_delete();
- ptimer_delete();
- igmp_delete();
- announce_delete();
- idle_delete();
- server_cfg_monitor_delete();
- list_for_each_entry_safe(server, stmp, &cfg->servers, list)
- server_delete(server);
- uring_delete();
- return;
-
- default:
- error("got an unknown signal: %i", si->si_signo);
- break;
- }
-
-out:
- uring_tbuf_read(&signal->task, signalfd_read);
-}
-
-static void
-hack_signal_handler(int signum, siginfo_t *si, void *ucontext)
-{
- ssize_t r;
-
- assert_return(signum > 0 && si);
-
- r = write(cfg->signal->pipe[PIPE_WR], si, sizeof(*si));
- if (r != sizeof(*si))
- error("write: %zi\n", r);
-
-}
-
-static void
-signal_free(struct uring_task *task)
-{
- struct signal_ev *signal = container_of(task, struct signal_ev, task);
-
- assert_return(task);
-
- debug(DBG_SIG, "called");
- close(signal->pipe[PIPE_WR]);
- cfg->signal = NULL;
- xfree(signal);
-}
-
-void
-signal_refdump()
-{
- assert_return(cfg->signal);
-
- uring_task_refdump(&cfg->signal->task);
-}
-
-void
-signal_init()
-{
- //sigset_t mask;
- struct signal_ev *signal;
-
- assert_return(!cfg->signal);
-
- signal = zmalloc(sizeof(*signal));
- if (!signal)
- die("malloc: %m");
-
- if (pipe2(signal->pipe, O_CLOEXEC) < 0)
- die("pipe2: %m");
-
- /*
- sigfillset(&mask);
- if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
- die("sigprocmask: %m");
-
- sfd = signalfd(-1, &mask, SFD_CLOEXEC);
- if (sfd < 0)
- die("signalfd: %m");
- */
-
- struct sigaction action;
- sigfillset(&action.sa_mask);
- action.sa_sigaction = hack_signal_handler;
- action.sa_flags = SA_SIGINFO;
-
- sigaction(SIGINT, &action, NULL);
- sigaction(SIGHUP, &action, NULL);
- sigaction(SIGTERM, &action, NULL);
- sigaction(SIGUSR1, &action, NULL);
- sigaction(SIGUSR2, &action, NULL);
-
- action.sa_handler = SIG_IGN;
- action.sa_flags = 0;
- sigaction(SIGPIPE, &action, NULL);
-
- debug(DBG_SIG, "using pipe fds %i -> %i",
- signal->pipe[PIPE_WR], signal->pipe[PIPE_RD]);
- uring_task_init(&signal->task, "signal", uring_parent(), signal_free);
- uring_task_set_fd(&signal->task, signal->pipe[PIPE_RD]);
- uring_task_set_buf(&signal->task, &signal->tbuf);
- cfg->signal = signal;
- uring_tbuf_read(&signal->task, signalfd_read);
-}
-
diff --git a/mcserverproxy/signal-handler.h b/mcserverproxy/signal-handler.h
deleted file mode 100644
index e0140b3..0000000
--- a/mcserverproxy/signal-handler.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef foosignalhfoo
-#define foosignalhfoo
-
-void signal_refdump();
-
-void signal_init();
-
-#endif
diff --git a/mcserverproxy/systemd.c b/mcserverproxy/systemd.c
deleted file mode 100644
index a44b0d8..0000000
--- a/mcserverproxy/systemd.c
+++ /dev/null
@@ -1,219 +0,0 @@
-#include <string.h>
-#include <stdlib.h>
-#include <systemd/sd-bus.h>
-
-#include "main.h"
-#include "server.h"
-#include "systemd.h"
-
-#define SYSTEMD_DBUS_SERVICE "org.freedesktop.systemd1"
-#define SYSTEMD_DBUS_INTERFACE "org.freedesktop.systemd1.Unit"
-#define SYSTEMD_DBUS_PATH_PREFIX "/org/freedesktop/systemd1/unit/"
-
-static inline char
-tohex(uint8_t val)
-{
- static const char hex[] = "0123456789abcdef";
-
- return hex[val & 0x0f];
-}
-
-/*
- * Creates an escaped D-Bus object path for a given systemd service
- *
- * Escaping rules are documented here:
- * https://dbus.freedesktop.org/doc/dbus-specification.html
- *
- * Essentially, everyting but a-z, A-Z, 0-9 is replaced by _xx where xx is
- * the hexadecimal value of the character.
- *
- * Example: minecraft@world1.service -> minecraft_40world1_2eservice
- */
-char *
-systemd_object_path(const char *service)
-{
- char *r;
- char *d;
- const char *s;
-
- assert_return(service && !empty_str(service), NULL);
-
- r = zmalloc(strlen(SYSTEMD_DBUS_PATH_PREFIX) + strlen(service) * 3 + 1);
- if (!r)
- return NULL;
-
- memcpy(r, SYSTEMD_DBUS_PATH_PREFIX, strlen(SYSTEMD_DBUS_PATH_PREFIX));
- d = r + strlen(SYSTEMD_DBUS_PATH_PREFIX);
-
- for (s = service; *s; s++) {
- if ((*s >= 'a' && *s <= 'z') ||
- (*s >= 'A' && *s <= 'Z') ||
- (*s >= '0' && *s <= '9')) {
- *(d++) = *s;
- continue;
- }
-
- *(d++) = '_';
- *(d++) = tohex(*s >> 4);
- *(d++) = tohex(*s);
- }
-
- *d = '\0';
- return r;
-}
-
-void
-systemd_delete()
-{
- assert_return_silent(cfg->sd_bus);
-
- sd_bus_unref(cfg->sd_bus);
- cfg->sd_bus = NULL;
-}
-
-static sd_bus *
-get_bus()
-{
- int r;
-
- if (cfg->sd_bus_failed)
- return NULL;
-
- if (!cfg->sd_bus) {
- r = sd_bus_open_user(&cfg->sd_bus);
- if (r < 0) {
- error("failed to connect to user system bus: %s", strerror(-r));
- cfg->sd_bus_failed = true;
- return NULL;
- }
- }
-
- return cfg->sd_bus;
-}
-
-/*
- * Check if a systemd service is running.
- *
- * This is equivalent to (assuming service minecraft@world1):
- * gdbus call --session
- * --dest org.freedesktop.systemd1
- * --object-path /org/freedesktop/systemd1/unit/minecraft_40world1_2eservice
- * --method org.freedesktop.DBus.Properties.Get
- * "org.freedesktop.systemd1.Unit"
- * "ActiveState"
- */
-bool
-systemd_service_running(struct server *server)
-{
- sd_bus *bus = get_bus();
- sd_bus_error error = SD_BUS_ERROR_NULL;
- char *status = NULL;
- bool running = false;
- int r;
-
- assert_return(server && bus && server->systemd_service && server->systemd_obj, false);
-
- r = sd_bus_get_property_string(bus,
- SYSTEMD_DBUS_SERVICE,
- server->systemd_obj,
- SYSTEMD_DBUS_INTERFACE,
- "ActiveState",
- &error,
- &status);
- if (r < 0) {
- error("failed to get status for service %s (%s): %s",
- server->systemd_service, server->systemd_obj, error.message);
- goto out;
- }
-
- if (streq(status, "active")) {
- running = true;
- debug(DBG_SYSD, "systemd service %s (%s) is active",
- server->systemd_service, server->systemd_obj);
- } else
- debug(DBG_SYSD, "systemd service %s (%s) is not active",
- server->systemd_service, server->systemd_obj);
-
-out:
- free(status);
- sd_bus_error_free(&error);
- return running;
-}
-
-static bool
-systemd_service_action(struct server *server, const char *action)
-{
- sd_bus_error error = SD_BUS_ERROR_NULL;
- sd_bus_message *m = NULL;
- sd_bus *bus = get_bus();
- const char *path;
- bool performed = false;
- int r;
-
- assert_return(server && bus && server->systemd_service && server->systemd_obj && action, false);
-
- r = sd_bus_call_method(bus,
- SYSTEMD_DBUS_SERVICE,
- server->systemd_obj,
- SYSTEMD_DBUS_INTERFACE,
- action,
- &error,
- &m,
- "s",
- "fail");
- if (r < 0) {
- error("failed to perform action %s on systemd service %s: %s",
- action, server->systemd_service, error.message);
- goto out;
- }
-
- r = sd_bus_message_read(m, "o", &path);
- if (r < 0) {
- error("failed to parse response message: %s", strerror(-r));
- goto out;
- }
-
- verbose("action %s queued for service %s",
- action, server->systemd_service);
- performed = true;
-
-out:
- sd_bus_error_free(&error);
- sd_bus_message_unref(m);
- return performed;
-}
-
-/*
- * Stop systemd service.
- *
- * This is equivalent to (assuming service minecraft@world1):
- * gdbus call --session
- * --dest org.freedesktop.systemd1
- * --object-path /org/freedesktop/systemd1/unit/minecraft_40world1_2eservice
- * --method org.freedesktop.systemd1.Unit.Stop "fail"
- */
-bool
-systemd_service_stop(struct server *server)
-{
- assert_return(server, false);
-
- return systemd_service_action(server, "Stop");
-}
-
-/*
- * Start systemd service.
- *
- * This is equivalent to (assuming service minecraft@world1):
- * gdbus call --session
- * --dest org.freedesktop.systemd1
- * --object-path /org/freedesktop/systemd1/unit/minecraft_40world1_2eservice
- * --method org.freedesktop.systemd1.Unit.Start "fail"
- */
-bool
-systemd_service_start(struct server *server)
-{
- assert_return(server, false);
-
- return systemd_service_action(server, "Start");
-}
-
diff --git a/mcserverproxy/systemd.h b/mcserverproxy/systemd.h
deleted file mode 100644
index d455044..0000000
--- a/mcserverproxy/systemd.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef foosystemdhfoo
-#define foosystemdhfoo
-
-char *systemd_object_path(const char *service);
-
-void systemd_delete();
-
-bool systemd_service_running(struct server *server);
-
-bool systemd_service_stop(struct server *server);
-
-bool systemd_service_start(struct server *server);
-
-#endif
diff --git a/mcserverproxy/uring.c b/mcserverproxy/uring.c
deleted file mode 100644
index e979471..0000000
--- a/mcserverproxy/uring.c
+++ /dev/null
@@ -1,759 +0,0 @@
-#define _GNU_SOURCE
-#include <liburing.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "main.h"
-#include "uring.h"
-
-struct uring_ev {
- struct io_uring uring;
- struct io_uring_params uring_params;
- struct uring_task task;
-
- /* for testing if the kernel supports splice */
- int pipe[2];
- int tfd;
-};
-
-enum cqe_type {
- CQE_TYPE_NORMAL = 0x0,
- CQE_TYPE_CANCEL = 0x1,
- CQE_TYPE_CLOSE = 0x2,
- CQE_TYPE_POLL_CANCEL = 0x3
-};
-
-#define CQE_TYPE_PTR_MASK 0x3
-
-uint64_t sqe_count = 0;
-uint64_t cqe_count = 0;
-
-static struct io_uring_sqe *
-get_sqe(struct uring_task *task)
-{
- struct io_uring_sqe *sqe;
-
- assert_die(task, "invalid arguments");
-
- sqe = io_uring_get_sqe(&cfg->uring->uring);
- if (!sqe) {
- io_uring_submit(&cfg->uring->uring);
- sqe = io_uring_get_sqe(&cfg->uring->uring);
- if (!sqe)
- die("failed to get an sqe!");
- }
-
- sqe_count++;
- uring_task_get(task);
- return sqe;
-}
-
-void
-uring_task_refdump(struct uring_task *task)
-{
- char buf[4096];
- struct uring_task *tmp;
-
- assert_return(task);
-
- if (!debug_enabled(DBG_REF))
- return;
-
- buf[0] = '\0';
- for (tmp = task; tmp; tmp = tmp->parent) {
- size_t prefix;
- char *dst;
-
- if (tmp->parent)
- prefix = strlen("->") + strlen(tmp->name);
- else
- prefix = strlen(tmp->name);
-
- memmove(&buf[prefix], &buf[0], strlen(buf) + 1);
-
- dst = &buf[0];
- if (tmp->parent) {
- *dst++ = '-';
- *dst++ = '>';
- }
-
- memcpy(dst, tmp->name, strlen(tmp->name));
- }
-
- info("%s (0x%p parent 0x%p free 0x%p fd %i ref %u)",
- buf, task, task->parent, task->free, task->fd,
- task->refcount);
-}
-
-/*
- * Similar to uring_task_put, but can be called from other tasks
- * while the task is active.
- */
-void
-uring_task_destroy(struct uring_task *task)
-{
- assert_return(task);
- assert_return_silent(!task->dead);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- if (task->fd >= 0) {
- struct io_uring_sqe *sqe;
-
- sqe = get_sqe(task);
- io_uring_prep_cancel(sqe, task, 0);
- io_uring_sqe_set_data(sqe, (void *)((uintptr_t)task | CQE_TYPE_CANCEL));
- }
-
- task->dead = true;
- uring_task_put(task);
-}
-
-void
-uring_task_put(struct uring_task *task)
-{
- struct uring_task *parent;
-
- assert_return(task);
-
- debug(DBG_REF, "task %s (%p), refcount %u -> %u",
- task->name, task, task->refcount, task->refcount - 1);
-
- task->refcount--;
-
- if (task->refcount > 0)
- return;
-
- if (task->refcount < 0)
- error("Negative refcount!");
-
- if (task->fd >= 0) {
- uring_task_close_fd(task);
- /* We'll be called again once the fd is closed */
- return;
- }
-
- parent = task->parent;
- if (task->free)
- task->free(task);
-
- if (parent) {
- debug(DBG_REF, "putting parent %s (%p)", parent->name, parent);
- uring_task_put(parent);
- }
-}
-
-void
-uring_task_get(struct uring_task *task)
-{
- assert_return(task);
-
- debug(DBG_REF, "task %s (%p), refcount %u -> %u",
- task->name, task, task->refcount, task->refcount + 1);
-
- if (task->refcount < 0)
- error("Negative refcount!");
-
- task->refcount++;
-}
-
-void
-uring_task_set_buf(struct uring_task *task, struct uring_task_buf *tbuf)
-{
- assert_return(task && tbuf);
-
- debug(DBG_UR, "task %s (%p), buf %p, refcount %u",
- task->name, task, tbuf, task->refcount);
-
- /* iov_len and msg_namelen are set at send/receive time */
- tbuf->iov.iov_base = tbuf->buf;
- tbuf->msg.msg_name = &task->saddr.storage;
- tbuf->msg.msg_iov = &tbuf->iov;
- tbuf->msg.msg_iovlen = 1;
- tbuf->msg.msg_control = NULL;
- tbuf->msg.msg_controllen = 0;
- tbuf->msg.msg_flags = 0;
- task->tbuf = tbuf;
-}
-
-void
-uring_task_set_fd(struct uring_task *task, int fd)
-{
- assert_return(task);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, fd, task->refcount);
-
- task->fd = fd;
-}
-
-void
-uring_task_close_fd(struct uring_task *task)
-{
- assert_return(task);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- if (task->fd < 0)
- return;
-
- uring_close(task, task->fd);
- task->fd = -1;
-}
-
-struct uring_task *
-uring_parent()
-{
- assert_die(cfg->uring, "invalid arguments");
-
- return &cfg->uring->task;
-}
-
-void
-uring_task_init(struct uring_task *task, const char *name,
- struct uring_task *parent, void (*free)(struct uring_task *))
-{
- static bool first = true;
-
- assert_die(task && !empty_str(name) && free, "invalid arguments");
-
- if (first)
- first = false;
- else
- assert_die(parent, "called without a parent task");
-
- task->refcount = 1;
- task->fd = -1;
- task->parent = parent;
- task->free = free;
- task->dead = false;
- task->name = name;
- task->tbuf = NULL;
-
- if (task->parent) {
- debug(DBG_REF, "task %s (%p), refcount %u, "
- "getting parent %s (%p), refcount %u",
- task->name, task, task->refcount,
- task->parent->name, task->parent, task->parent->refcount);
- uring_task_get(task->parent);
- }
-}
-
-void
-uring_close(struct uring_task *task, int fd)
-{
- struct io_uring_sqe *sqe;
-
- assert_return(task && fd >= 0);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- sqe = get_sqe(task);
- io_uring_prep_close(sqe, fd);
- io_uring_sqe_set_data(sqe, (void *)((uintptr_t)task | CQE_TYPE_CLOSE));
-}
-
-static void
-uring_tbuf_write_cb(struct uring_task *task, int res)
-{
- int r;
-
- assert_return(task && task->tbuf && task->final_cb);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- if (res < 0) {
- r = res;
- goto finished;
- }
-
- /* We wrote some more data */
- task->tbuf->done += res;
- if (task->tbuf->done >= task->tbuf->len || res == 0) {
- r = task->tbuf->len;
- goto finished;
- }
-
- uring_write(task, task->tbuf->buf + task->tbuf->done,
- task->tbuf->len - task->tbuf->done,
- uring_tbuf_write_cb);
- return;
-
-finished:
- task->final_cb(task, r);
-}
-
-void
-uring_tbuf_write(struct uring_task *task, utask_cb_t final_cb)
-{
- assert_return(task && task->fd >= 0 && task->tbuf && task->tbuf->len > 0);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- task->tbuf->done = 0;
- task->final_cb = final_cb;
- uring_write(task, &task->tbuf->buf, task->tbuf->len, uring_tbuf_write_cb);
-}
-
-void
-uring_write(struct uring_task *task, void *buf, size_t len, utask_cb_t cb)
-{
- struct io_uring_sqe *sqe;
-
- assert_return(task && buf && len > 0 && cb && task->fd >= 0);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- sqe = get_sqe(task);
- task->cb = cb;
- io_uring_prep_write(sqe, task->fd, buf, len, 0);
- io_uring_sqe_set_data(sqe, task);
-}
-
-static void
-uring_tbuf_read_until_cb(struct uring_task *task, int res)
-{
- int r;
-
- assert_return(task && task->tbuf && task->final_cb && task->is_complete_cb);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- if (res < 0) {
- r = res;
- goto finished;
- }
-
- task->tbuf->len += res;
- r = task->is_complete_cb(task, res);
- if (r < 0) {
- r = res;
- goto finished;
- } else if (r > 0) {
- r = task->tbuf->len;
- goto finished;
- }
-
- /* Need to read more */
- if (task->tbuf->len >= sizeof(task->tbuf->buf)) {
- r = E2BIG;
- goto finished;
- }
-
- uring_read_offset(task, task->tbuf->buf + task->tbuf->len,
- sizeof(task->tbuf->buf) - task->tbuf->len,
- task->tbuf->len, uring_tbuf_read_until_cb);
- return;
-
-finished:
- task->final_cb(task, r);
-}
-
-void
-uring_tbuf_read_until(struct uring_task *task,
- rutask_cb_t is_complete_cb, utask_cb_t final_cb)
-{
- assert_return(task && task->fd >= 0 && task->tbuf && is_complete_cb && final_cb);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- task->tbuf->len = 0;
- task->is_complete_cb = is_complete_cb;
- task->final_cb = final_cb;
- uring_read(task, &task->tbuf->buf, sizeof(task->tbuf->buf),
- uring_tbuf_read_until_cb);
-}
-
-static int
-uring_tbuf_eof(struct uring_task *task, int res)
-{
- assert_return(task && task->tbuf, -EINVAL);
- assert_task_alive_or(DBG_UR, task, return -EINTR);
-
- if (task->tbuf->len + 1 >= sizeof(task->tbuf->buf))
- return -E2BIG;
-
- if (res > 0)
- return 0;
-
- task->tbuf->buf[task->tbuf->len] = '\0';
- task->tbuf->len++;
- return 1;
-}
-
-void
-uring_tbuf_read_until_eof(struct uring_task *task,
- utask_cb_t final_cb)
-{
- assert_return(task && task->tbuf && final_cb);
-
- uring_tbuf_read_until(task, uring_tbuf_eof, final_cb);
-}
-
-static int
-uring_tbuf_have_data(struct uring_task *task, int res)
-{
- assert_return(task, -EINVAL);
-
- if (res < 0)
- return res;
- else
- return 1;
-}
-
-void
-uring_tbuf_read(struct uring_task *task, utask_cb_t final_cb)
-{
- assert_return(task && final_cb);
-
- uring_tbuf_read_until(task, uring_tbuf_have_data, final_cb);
-}
-
-void
-uring_read_offset(struct uring_task *task, void *buf, size_t len, off_t offset, utask_cb_t cb)
-{
- struct io_uring_sqe *sqe;
-
- assert_return(task && buf && len > 0 && task->fd >= 0);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- sqe = get_sqe(task);
- task->cb = cb;
- io_uring_prep_read(sqe, task->fd, buf, len, offset);
- io_uring_sqe_set_data(sqe, task);
-}
-
-void
-uring_openat(struct uring_task *task, const char *path, utask_cb_t cb)
-{
- struct io_uring_sqe *sqe;
-
- assert_return(task && !empty_str(path) && cb);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- sqe = get_sqe(task);
- task->cb = cb;
- io_uring_prep_openat(sqe, AT_FDCWD, path, O_RDONLY | O_CLOEXEC, 0);
- io_uring_sqe_set_data(sqe, task);
-}
-
-void
-uring_tbuf_recvmsg(struct uring_task *task, utask_cb_t cb)
-{
- struct io_uring_sqe *sqe;
-
- assert_return(task && task->fd >= 0 && task->tbuf && cb);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- sqe = get_sqe(task);
- task->tbuf->done = 0;
- task->tbuf->len = 0;
- task->tbuf->iov.iov_len = sizeof(task->tbuf->buf);
- task->tbuf->msg.msg_namelen = task->saddr.addrlen;
- task->cb = cb;
- io_uring_prep_recvmsg(sqe, task->fd, &task->tbuf->msg, 0);
- io_uring_sqe_set_data(sqe, task);
-}
-
-void
-uring_tbuf_sendmsg(struct uring_task *task, utask_cb_t cb)
-{
- struct io_uring_sqe *sqe;
-
- assert_return(task && task->fd >= 0 && task->tbuf && cb);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- sqe = get_sqe(task);
- task->tbuf->done = 0;
- task->tbuf->iov.iov_len = task->tbuf->len;
- task->tbuf->msg.msg_namelen = task->saddr.addrlen;
- task->cb = cb;
- io_uring_prep_sendmsg(sqe, task->fd, &task->tbuf->msg, 0);
- io_uring_sqe_set_data(sqe, task);
-}
-
-void
-uring_connect(struct uring_task *task, struct saddr *saddr, utask_cb_t cb)
-{
- struct io_uring_sqe *sqe;
-
- assert_return(task && task->fd >= 0 && saddr && cb);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- sqe = get_sqe(task);
- task->cb = cb;
- io_uring_prep_connect(sqe, task->fd, (struct sockaddr *)&saddr->storage, saddr->addrlen);
- io_uring_sqe_set_data(sqe, task);
-}
-
-void
-uring_accept(struct uring_task *task, struct saddr *saddr, utask_cb_t cb)
-{
- struct io_uring_sqe *sqe;
-
- assert_return(task && task->fd >= 0 && saddr && cb);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- sqe = get_sqe(task);
- saddr->addrlen = sizeof(saddr->storage);
- task->cb = cb;
- io_uring_prep_accept(sqe, task->fd, (struct sockaddr *)&saddr->storage, &saddr->addrlen, SOCK_CLOEXEC);
- io_uring_sqe_set_data(sqe, task);
-}
-
-void
-uring_splice(struct uring_task *task, int fd_in, int fd_out, utask_cb_t cb)
-{
- struct io_uring_sqe *sqe;
-
- assert_return(task && fd_in >= 0 && fd_out >= 0 && cb);
-
- debug(DBG_UR, "task %s (%p), fd_in %i, fd_out %i, refcount %u",
- task->name, task, fd_in, fd_out, task->refcount);
-
- sqe = get_sqe(task);
- task->cb = cb;
- io_uring_prep_splice(sqe, fd_in, -1, fd_out, -1, 4096, SPLICE_F_MOVE);
- io_uring_sqe_set_data(sqe, task);
-}
-
-void
-uring_poll(struct uring_task *task, short poll_mask, utask_cb_t cb)
-{
- struct io_uring_sqe *sqe;
-
- assert_return(task && task->fd >= 0 && poll_mask && cb);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- sqe = get_sqe(task);
- task->cb = cb;
- io_uring_prep_poll_add(sqe, task->fd, poll_mask);
- io_uring_sqe_set_data(sqe, task);
-}
-
-void
-uring_poll_cancel(struct uring_task *task)
-{
- struct io_uring_sqe *sqe;
-
- assert_return(task);
-
- if (task->fd < 0) {
- /* not an error, no need to print error msg */
- return;
- }
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- sqe = get_sqe(task);
- task->dead = true;
- io_uring_prep_poll_remove(sqe, task);
- io_uring_sqe_set_data(sqe, (void *)((uintptr_t)task | CQE_TYPE_POLL_CANCEL));
-}
-
-static void
-uring_free(struct uring_task *task)
-{
- struct uring_ev *uring = container_of(task, struct uring_ev, task);
-
- assert_return(task);
-
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- io_uring_queue_exit(&uring->uring);
- cfg->uring = NULL;
- xfree(uring);
-}
-
-void
-uring_refdump()
-{
- assert_return(cfg->uring);
-
- uring_task_refdump(&cfg->uring->task);
-}
-
-void
-uring_delete()
-{
- struct uring_task *task;
-
- assert_return(cfg->uring);
-
- task = &cfg->uring->task;
- debug(DBG_UR, "task %s (%p), fd %i, refcount %u",
- task->name, task, task->fd, task->refcount);
-
- uring_task_put(task);
-}
-
-static void
-uring_splice_test_cb(struct uring_task *task, int res)
-{
- struct uring_ev *uring = container_of(task, struct uring_ev, task);
-
- assert_die(task && uring == cfg->uring, "splice test failed");
-
- uring_close(task, uring->tfd);
- uring_close(task, uring->pipe[PIPE_RD]);
- uring_close(task, uring->pipe[PIPE_WR]);
-
- uring->tfd = -1;
- uring->pipe[PIPE_RD] = -1;
- uring->pipe[PIPE_WR] = -1;
-
- if (res >= 0) {
- cfg->splice_supported = true;
- debug(DBG_UR, "splice supported");
- } else if (res == -EINVAL)
- debug(DBG_UR, "splice not supported");
- else
- error("splice check failed: %i\n", res);
-}
-
-void
-uring_init()
-{
- struct uring_ev *uring;
-
- assert_return(!cfg->uring);
-
- uring = zmalloc(sizeof(*uring));
- if (!uring)
- die("malloc: %m");
-
- if (io_uring_queue_init_params(4096, &uring->uring, &uring->uring_params) < 0)
- die("io_uring_queue_init_params");
-
- debug(DBG_UR, "uring initialized, features: 0x%08x",
- uring->uring_params.features);
-
- uring_task_init(&uring->task, "io_uring", &cfg->task, uring_free);
- cfg->uring = uring;
-
- /* splice check, a bit convoluted, but seems to be no simpler way */
- cfg->splice_supported = false;
- if (pipe2(uring->pipe, O_CLOEXEC) < 0)
- die("pipe2: %m");
- uring->tfd = open("/dev/null", O_RDONLY | O_CLOEXEC | O_NOCTTY);
- if (uring->tfd < 0)
- die("open(\"/dev/null\"): %m");
- uring_splice(&uring->task, uring->tfd, uring->pipe[PIPE_WR], uring_splice_test_cb);
-}
-
-static inline void
-uring_print_cqe(const char *type, struct uring_task *task,
- struct io_uring_cqe *cqe)
-{
- assert_return(!empty_str(type) && task && cqe);
-
- debug(DBG_UR, "got CQE "
- "(type: %s, res: %i (%s), task: %s (%p), fd: %i, cb: %p)",
- type,
- cqe->res,
- cqe->res < 0 ? strerror(-cqe->res) : "ok",
- task->name ? task->name : "<none>",
- task,
- task->fd,
- task->cb);
-}
-
-void
-uring_event_loop()
-{
- while (true) {
- struct io_uring_cqe *cqe;
- unsigned nr, head;
- int r;
-
- io_uring_submit(&cfg->uring->uring);
- r = io_uring_wait_cqe(&cfg->uring->uring, &cqe);
- if (r < 0) {
- if (errno == EINTR)
- continue;
- else
- die("io_uring_wait_cqe: %i", r);
- }
-
- nr = 0;
- io_uring_for_each_cqe(&cfg->uring->uring, head, cqe) {
- struct uring_task *task = io_uring_cqe_get_data(cqe);
- bool do_cb;
- enum cqe_type cqe_type;
-
- cqe_count++;
-
- cqe_type = ((uintptr_t)task & CQE_TYPE_PTR_MASK);
- task = (void *)((uintptr_t)task & ~CQE_TYPE_PTR_MASK);
-
- if (!task)
- die("null task");
-
- switch (cqe_type) {
- case CQE_TYPE_CANCEL:
- uring_print_cqe("cancel", task, cqe);
- do_cb = false;
- break;
-
- case CQE_TYPE_CLOSE:
- uring_print_cqe("close", task, cqe);
- do_cb = false;
- break;
-
- case CQE_TYPE_POLL_CANCEL:
- uring_print_cqe("poll_cancel", task, cqe);
- do_cb = false;
- break;
-
- case CQE_TYPE_NORMAL:
- uring_print_cqe("standard", task, cqe);
- do_cb = true;
- break;
-
- default:
- die("unknown CQE type");
- }
-
- if (do_cb && task->cb)
- task->cb(task, cqe->res);
-
- uring_task_put(task);
-
- if (exiting)
- return;
-
- nr++;
- }
-
- io_uring_cq_advance(&cfg->uring->uring, nr);
- }
-}
-
diff --git a/mcserverproxy/uring.h b/mcserverproxy/uring.h
deleted file mode 100644
index 9c33104..0000000
--- a/mcserverproxy/uring.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef foouringhfoo
-#define foouringhfoo
-
-extern uint64_t sqe_count;
-extern uint64_t cqe_count;
-
-void uring_task_refdump(struct uring_task *task);
-
-void uring_task_destroy(struct uring_task *task);
-
-void uring_task_put(struct uring_task *task);
-
-void uring_task_get(struct uring_task *task);
-
-void uring_task_set_buf(struct uring_task *task, struct uring_task_buf *tbuf);
-
-void uring_task_set_fd(struct uring_task *task, int fd);
-
-void uring_task_close_fd(struct uring_task *task);
-
-struct uring_task *uring_parent();
-
-void uring_task_init(struct uring_task *task, const char *name,
- struct uring_task *parent,
- void (*free)(struct uring_task *));
-
-void uring_close(struct uring_task *task, int fd);
-
-void uring_tbuf_write(struct uring_task *task, utask_cb_t final_cb);
-
-void uring_write(struct uring_task *task, void *buf, size_t len, utask_cb_t cb);
-
-void uring_tbuf_read_until(struct uring_task *task,
- rutask_cb_t is_complete_cb, utask_cb_t final_cb);
-
-void uring_tbuf_read_until_eof(struct uring_task *task, utask_cb_t final_cb);
-
-void uring_tbuf_read(struct uring_task *task, utask_cb_t final_cb);
-
-void uring_read_offset(struct uring_task *task, void *buf,
- size_t len, off_t offset, utask_cb_t cb);
-
-static inline void
-uring_read(struct uring_task *task, void *buf, size_t len, utask_cb_t cb)
-{
- uring_read_offset(task, buf, len, 0, cb);
-}
-
-void uring_openat(struct uring_task *task, const char *path, utask_cb_t cb);
-
-void uring_tbuf_recvmsg(struct uring_task *task, utask_cb_t cb);
-
-void uring_tbuf_sendmsg(struct uring_task *task, utask_cb_t cb);
-
-void uring_connect(struct uring_task *task, struct saddr *saddr, utask_cb_t cb);
-
-void uring_accept(struct uring_task *task, struct saddr *saddr, utask_cb_t cb);
-
-void uring_splice(struct uring_task *task, int fd_in, int fd_out, utask_cb_t cb);
-
-void uring_poll(struct uring_task *task, short poll_mask, utask_cb_t cb);
-
-void uring_poll_cancel(struct uring_task *task);
-
-void uring_delete();
-
-void uring_refdump();
-
-void uring_init();
-
-void uring_event_loop();
-
-#endif
diff --git a/mcserverproxy/utils.c b/mcserverproxy/utils.c
deleted file mode 100644
index eacc586..0000000
--- a/mcserverproxy/utils.c
+++ /dev/null
@@ -1,430 +0,0 @@
-#include <stdlib.h>
-#include <errno.h>
-#include <stdint.h>
-#include <limits.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <inttypes.h>
-
-#include "main.h"
-#include "utils.h"
-#include "uring.h"
-
-static unsigned total_malloc_count = 0;
-static int malloc_count = 0;
-
-LIST_HEAD(malloc_list);
-
-struct allocation {
- const char *allocfn;
- const char *callerfn;
- int line;
- void *ptr;
- size_t size;
- struct list_head list;
-};
-
-static void
-add_allocation(const char *allocfn, const char *callerfn, int line, void *ptr, size_t size)
-{
- struct allocation *a;
-
- assert_die(!empty_str(allocfn) && !empty_str(callerfn) && line > 0 && ptr && size > 0, "invalid arguments");
-
- a = malloc(sizeof(*a));
- if (!a)
- die("malloc: %m");
- a->allocfn = allocfn;
- a->callerfn = callerfn;
- a->line = line;
- a->ptr = ptr;
- a->size = size;
- list_add(&a->list, &malloc_list);
- total_malloc_count++;
- malloc_count++;
- debug(DBG_MALLOC, "called from %s:%i - %s(%zu) = %p (%p)",
- callerfn, line, allocfn, size, ptr, a);
-}
-
-void *
-__zmalloc(const char *fn, int line, size_t size)
-{
- void *ptr;
-
- assert_die(!empty_str(fn) && line > 0 && size > 0, "invalid arguments");
-
- ptr = calloc(1, size);
- if (ptr)
- add_allocation("zmalloc", fn, line, ptr, size);
- return ptr;
-}
-
-char *
-__xstrdup(const char *fn, int line, const char *s)
-{
- char *ptr;
-
- assert_die(!empty_str(fn) && line > 0 && !empty_str(s), "invalid arguments");
-
- ptr = strdup(s);
- if (ptr)
- add_allocation("xstrdup", fn, line, ptr, strlen(s) + 1);
- return ptr;
-}
-
-char *
-__xstrndup(const char *fn, int line, const char *s, size_t n)
-{
- char *ptr;
-
- assert_die(!empty_str(fn) && line > 0 && !empty_str(s) && n > 0, "invalid arguments");
-
- ptr = strndup(s, n);
- if (ptr)
- add_allocation("xstrndup", fn, line, ptr, n);
- return ptr;
-}
-
-void
-__xfree(const char *fn, int line, void *ptr)
-{
- struct allocation *a, *tmp;
- unsigned delete_count = 0;
-
- assert_die(!empty_str(fn) && line > 0, "invalid arguments");
-
- if (!ptr)
- return;
- free(ptr);
- malloc_count--;
-
- debug(DBG_MALLOC, "called from %s:%i - %p", fn, line, ptr);
-
- list_for_each_entry_safe(a, tmp, &malloc_list, list) {
- if (a->ptr == ptr) {
- list_del(&a->list);
- free(a);
- delete_count++;
- }
- }
-
- if (delete_count != 1) {
- error("Delete count is %u for ptr 0x%p", delete_count, ptr);
- exit(EXIT_FAILURE);
- }
-}
-
-void
-debug_resource_usage()
-{
- struct allocation *a;
- DIR *dir;
- struct dirent *dent;
- char buf[4096];
- ssize_t r;
- unsigned file_count = 0;
-
- debug(DBG_MALLOC, "Still malloced %i (total %u)",
- malloc_count, total_malloc_count);
-
- list_for_each_entry(a, &malloc_list, list) {
- debug(DBG_MALLOC, "* Lost allocation - %s:%i - ptr: %p, size: %zu",
- a->callerfn, a->line, a->ptr, a->size);
- }
-
- dir = opendir("/proc/self/fd");
- if (!dir) {
- error("failed to open fd dir");
- return;
- }
-
- debug(DBG_MALLOC, "Open files:");
- while ((dent = readdir(dir)) != NULL) {
- if (streq(dent->d_name, ".") || streq(dent->d_name, ".."))
- continue;
-
- r = readlinkat(dirfd(dir), dent->d_name, buf, sizeof(buf));
- if (r < 0) {
- debug(DBG_MALLOC, "Failed to readlink %s", dent->d_name);
- continue;
- }
- buf[r] = '\0';
- debug(DBG_MALLOC, " * %s -> %s", dent->d_name, buf);
- file_count++;
- }
- closedir(dir);
-
- if (file_count > 4)
- debug(DBG_MALLOC, "Lost file descriptor(s)");
-
- debug(DBG_MALLOC, "CQEs used: %" PRIu64 ", SQEs used: %" PRIu64,
- cqe_count, sqe_count);
-}
-
-void
-socket_set_low_latency(int sfd)
-{
- int option;
-
- assert_return(sfd >= 0);
-
- /* Probably not necessary, but can't hurt */
- if (cfg->socket_defer) {
- option = true;
- if (setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option)) < 0)
- error("setsockopt: %m");
- }
-
- /* Doubtful if it has much effect, but can't hurt */
- if (cfg->socket_iptos) {
- option = IPTOS_LOWDELAY;
- if (setsockopt(sfd, IPPROTO_IP, IP_TOS, &option, sizeof(option)) < 0)
- error("setsockopt: %m");
- }
-
- /* Nagle's algorithm is a poor fit for gaming */
- if (cfg->socket_nodelay) {
- option = true;
- if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option)) < 0)
- error("setsockopt: %m");
- }
-}
-
-void
-connection_set_local(struct connection *conn, int fd)
-{
- assert_return(conn && fd >= 0);
-
- conn->local.addrlen = sizeof(conn->local.storage);
- if (getsockname(fd, (struct sockaddr *)&conn->local.storage,
- &conn->local.addrlen) < 0)
- sprintf(conn->local.addrstr, "<unknown>");
- else
- saddr_set_addrstr(&conn->local);
-}
-
-void
-connection_set_remote(struct connection *conn, struct saddr *remote)
-{
- assert_return(conn && remote);
-
- conn->remote = *remote;
- saddr_set_addrstr(&conn->remote);
-}
-
-static void connect_next(struct uring_task *task, struct connection *conn);
-
-static void
-connect_cb(struct uring_task *task, int res)
-{
- struct connection *conn;
-
- assert_return(task && task->priv);
-
- conn = task->priv;
- if (res < 0) {
- debug(DBG_SRV, "%s: connection to %s failed",
- task->name, conn->remote.addrstr);
- uring_task_close_fd(task);
- connect_next(task, conn);
- return;
- }
-
- connection_set_local(conn, task->fd);
-
- debug(DBG_SRV, "%s: connection established %s -> %s",
- task->name, conn->local.addrstr, conn->remote.addrstr);
-
- conn->cb(conn, true);
-}
-
-static void
-connect_next(struct uring_task *task, struct connection *conn)
-{
- struct saddr *remote, *tmp;
- int sfd;
- unsigned i;
-
- assert_return(task && conn && conn->cb);
-again:
- assert_task_alive_or(DBG_UR, task, goto out);
-
- i = 0;
- remote = NULL;
- list_for_each_entry(tmp, conn->addrs, list) {
- if (i == conn->next_addr) {
- remote = tmp;
- break;
- }
- i++;
- }
-
- if (!remote) {
- debug(DBG_SRV, "%s: no more remote addresses to attempt",
- task->name);
- goto out;
- }
-
- conn->next_addr++;
- connection_set_remote(conn, remote);
- debug(DBG_SRV, "%s: attempting to connect to %s",
- task->name, conn->remote.addrstr);
-
- sfd = socket(conn->remote.storage.ss_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
- if (sfd < 0) {
- error("socket: %m");
- goto again;
- }
-
- socket_set_low_latency(sfd);
-
- task->priv = conn;
- uring_task_set_fd(task, sfd);
- uring_connect(task, &conn->remote, connect_cb);
- return;
-
-out:
- conn->cb(conn, false);
-}
-
-void
-connect_any(struct uring_task *task,
- struct list_head *addrs, struct connection *conn,
- connection_cb_t cb)
-{
- assert_return(task && addrs && conn && cb);
-
- conn->next_addr = 0;
- conn->addrs = addrs;
- conn->cb = cb;
- connect_next(task, conn);
-}
-
-uint16_t
-saddr_port(struct saddr *saddr)
-{
- assert_return(saddr, 0);
-
- switch (saddr->storage.ss_family) {
- case AF_INET:
- return ntohs(saddr->in4.sin_port);
- case AF_INET6:
- return ntohs(saddr->in6.sin6_port);
- default:
- return 0;
- }
-}
-
-char *
-saddr_addr(struct saddr *saddr, char *buf, size_t len)
-{
- assert_return(saddr && buf && len > 0, NULL);
-
- switch (saddr->storage.ss_family) {
- case AF_INET:
- if (inet_ntop(saddr->in4.sin_family, &saddr->in4.sin_addr, buf, len))
- return buf;
- break;
- case AF_INET6:
- if (inet_ntop(saddr->in6.sin6_family, &saddr->in6.sin6_addr, buf, len))
- return buf;
- break;
- default:
- break;
- }
-
- snprintf(buf, len, "<unknown>");
- return buf;
-}
-
-void
-saddr_set_ipv4(struct saddr *saddr, in_addr_t ip, in_port_t port)
-{
- assert_return(saddr);
-
- memset(&saddr->in4, 0, sizeof(saddr->in4));
- saddr->in4.sin_family = AF_INET;
- saddr->in4.sin_port = port;
- saddr->in4.sin_addr.s_addr = ip;
- saddr->addrlen = sizeof(saddr->in4);
- saddr_set_addrstr(saddr);
-}
-
-void
-saddr_set_ipv6(struct saddr *saddr, const struct in6_addr *ip, in_port_t port)
-{
- assert_return(saddr && ip);
-
- memset(&saddr->in6, 0, sizeof(saddr->in6));
- saddr->in6.sin6_family = AF_INET6;
- saddr->in6.sin6_port = port;
- if (ip)
- saddr->in6.sin6_addr = *ip;
- saddr->addrlen = sizeof(saddr->in6);
- saddr_set_addrstr(saddr);
-}
-
-void
-saddr_set_addrstr(struct saddr *saddr)
-{
- assert_return(saddr);
-
- char abuf[ADDRSTRLEN];
-
- switch (saddr->storage.ss_family) {
- case AF_INET:
- snprintf(saddr->addrstr, sizeof(saddr->addrstr),
- "AF_INET4 %s %" PRIu16,
- saddr_addr(saddr, abuf, sizeof(abuf)),
- saddr_port(saddr));
- break;
- case AF_INET6:
- snprintf(saddr->addrstr, sizeof(saddr->addrstr),
- "AF_INET6 %s %" PRIu16,
- saddr_addr(saddr, abuf, sizeof(abuf)),
- saddr_port(saddr));
- break;
- default:
- snprintf(saddr->addrstr, sizeof(saddr->addrstr), "AF_UNKNOWN");
- break;
- }
-}
-
-int
-strtou16_strict(const char *str, uint16_t *result)
-{
- char *end;
- long val;
-
- assert_return(!empty_str(str) && result, -EINVAL);
-
- errno = 0;
- val = strtol(str, &end, 10);
-
- if (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
- return -EINVAL;
-
- if (errno != 0 && val == 0)
- return -EINVAL;
-
- if (end == str)
- return -EINVAL;
-
- if (*end != '\0')
- return -EINVAL;
-
- if (val < 1 || val > UINT16_MAX)
- return -EINVAL;
-
- if (result)
- *result = val;
- return 0;
-}
-
diff --git a/mcserverproxy/utils.h b/mcserverproxy/utils.h
deleted file mode 100644
index c36a36c..0000000
--- a/mcserverproxy/utils.h
+++ /dev/null
@@ -1,245 +0,0 @@
-#ifndef fooutilshfoo
-#define fooutilshfoo
-
-#include <stdio.h>
-#include <string.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <linux/if_packet.h>
-
-struct list_head {
- struct list_head *next;
- struct list_head *prev;
-};
-
-#define zmalloc(s) __zmalloc(__func__, __LINE__, s)
-void *__zmalloc(const char *fn, int line, size_t s);
-
-#define xstrdup(s) __xstrdup(__func__, __LINE__, s)
-char *__xstrdup(const char *fn, int line, const char *s);
-
-#define xstrndup(s, n) __xstrndup(__func__, __LINE__, s, n)
-char *__xstrndup(const char *fn, int line, const char *s, size_t n);
-
-#define xfree(s) __xfree(__func__, __LINE__, s)
-void __xfree(const char *fn, int line, void *ptr);
-
-void debug_resource_usage();
-
-/* Length of longest DNS name = 253 + trailing dot */
-#define FQDN_STR_LEN 254
-
-/* Length of longest port string = strlen("65535") */
-#define PORT_STR_LEN 5
-
-/* Length of longest address family string = strlen("AF_INETX") */
-#define AF_STR_LEN 8
-
-/* Length of longest addrstr, format = "AF_INETX <IPADDR> <PORT> */
-#define ADDRSTRLEN (AF_STR_LEN + 1 + INET6_ADDRSTRLEN + 1 + PORT_STR_LEN + 1)
-struct saddr {
- union {
- struct sockaddr_storage storage;
- struct sockaddr_in in4;
- struct sockaddr_in6 in6;
- struct sockaddr_ll ll;
- };
- socklen_t addrlen;
- char addrstr[ADDRSTRLEN];
- struct list_head list;
-};
-
-struct connection;
-
-typedef void(*connection_cb_t)(struct connection *, bool);
-
-struct connection {
- struct saddr remote;
- struct saddr local;
-
- struct list_head *addrs;
- unsigned next_addr;
-
- connection_cb_t cb;
-};
-
-struct uring_task;
-
-void socket_set_low_latency(int sfd);
-
-void connection_set_local(struct connection *conn, int fd);
-
-void connection_set_remote(struct connection *conn, struct saddr *remote);
-
-void connect_any(struct uring_task *task,
- struct list_head *addrs, struct connection *conn,
- connection_cb_t cb);
-
-char *saddr_addr(struct saddr *saddr, char *buf, size_t len);
-
-uint16_t saddr_port(struct saddr *saddr);
-
-void saddr_set_ipv4(struct saddr *saddr, in_addr_t ip, in_port_t port);
-
-void saddr_set_ipv6(struct saddr *saddr, const struct in6_addr *ip, in_port_t port);
-
-void saddr_set_addrstr(struct saddr *saddr);
-
-int strtou16_strict(const char *str, uint16_t *result);
-
-static inline bool empty_str(const char *str)
-{
- if (!str || str[0] == '\0')
- return true;
- else
- return false;
-}
-
-static inline bool streq(const char *a, const char *b)
-{
- return strcmp(a, b) == 0;
-}
-
-static inline bool strcaseeq(const char *a, const char *b)
-{
- return strcasecmp(a, b) == 0;
-}
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define chtobe32(x) __bswap_constant_32(x)
-#else
-#define chtobe32(x) (x)
-#endif
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define cinet_addr(a,b,c,d) ((uint32_t)((a)<<0|(b)<<8|(c)<<16|(d)<<24))
-#else
-#define cinet_addr(a,b,c,d) ((uint32_t)((a)<<24|(b)<<16|(c)<<8|(d)<<0))
-#endif
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
-
-static inline void list_init(struct list_head *list)
-{
- list->next = list;
- list->prev = list;
-}
-
-static inline void list_del(struct list_head *list)
-{
- list->next->prev = list->prev;
- list->prev->next = list->next;
-}
-
-static inline void list_add(struct list_head *new, struct list_head *list)
-{
- list->next->prev = new;
- new->next = list->next;
- new->prev = list;
- list->next = new;
-}
-
-static inline void list_replace(struct list_head *old, struct list_head *new)
-{
- old->prev->next = new;
- old->next->prev = new;
- new->next = old->next;
- new->prev = old->prev;
- old->next = old->prev = NULL;
-}
-
-static inline bool list_empty(struct list_head *list)
-{
- return list->next == list;
-}
-
-#define PIPE_RD 0
-#define PIPE_WR 1
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-
-#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
-
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-
-#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
-
-#define list_entry(ptr, type, member) \
- container_of(ptr, type, member)
-
-#define list_first_entry(ptr, type, member) \
- list_entry((ptr)->next, type, member)
-
-#define list_next_entry(pos, member) \
- list_entry((pos)->member.next, typeof(*(pos)), member)
-
-#define list_for_each(pos, head) \
- for (pos = (head)->next; pos != (head); pos = pos->next)
-
-#define list_for_each_entry(pos, head, member) \
- for (pos = list_first_entry(head, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_next_entry(pos, member))
-
-#define list_for_each_entry_safe(pos, n, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member), \
- n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/*
-#define _cleanup_(x) __attribute__((cleanup(x)))
-
-#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
- static inline void func##p(type *p) { \
- if (*p) \
- func(*p); \
- } \
- struct __useless_struct_to_allow_trailing_semicolon__
-
-static inline unsigned
-strv_length(char **strv)
-{
- unsigned len;
-
- for (len = 0; strv && *strv; strv++)
- len++;
-
- return len;
-}
-
-static inline void strv_free(char **l) {
- char **k;
- if (l) {
- for (k = l; *k; k++)
- free(k);
- free(l);
- }
-}
-DEFINE_TRIVIAL_CLEANUP_FUNC(char **, strv_free);
-#define _cleanup_strv_free_ _cleanup_(strv_freep)
-
-static inline void freep(void *p) {
- free(*(void**) p);
-}
-#define _cleanup_free_ _cleanup_(freep)
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(int, close);
-#define _cleanup_close_ _cleanup_(closep)
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(FILE *, fclose);
-#define _cleanup_fclose_ _cleanup_(fclosep)
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(DIR *, closedir);
-#define _cleanup_closedir_ _cleanup_(closedirp)
-
-*/
-
-#endif
-