From 8c27290245b7bcc7cd2f72f3b4a7562294b43bbe Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Tue, 23 Jun 2020 16:25:36 +0200 Subject: Split directories better --- idle.c | 378 ----------------------------------------------------------------- 1 file changed, 378 deletions(-) delete mode 100644 idle.c (limited to 'idle.c') diff --git a/idle.c b/idle.c deleted file mode 100644 index c49846d..0000000 --- a/idle.c +++ /dev/null @@ -1,378 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include - -#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; -} - -- cgit v1.2.3