summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--idle.c189
-rw-r--r--server.c3
-rw-r--r--uring.c4
3 files changed, 109 insertions, 87 deletions
diff --git a/idle.c b/idle.c
index fc6be9b..ce0dfc4 100644
--- a/idle.c
+++ b/idle.c
@@ -6,6 +6,7 @@
#include <arpa/inet.h>
#include <string.h>
#include <ctype.h>
+#include <errno.h>
#include "main.h"
#include "uring.h"
@@ -22,9 +23,8 @@ struct idle {
unsigned next_remote;
struct sockaddr_in46 remote;
char remotestr[ADDRSTRLEN];
- char remotebuf[4096];
- size_t remotebuflen;
- size_t remotebufdone;
+
+ struct uring_task_buf tbuf;
};
static void
@@ -64,8 +64,8 @@ write_varint(char **pos, int32_t orig)
/*
* return value:
- * positive = need more bytes
- * zero = value decoded
+ * positive = varint parsed
+ * zero = need more bytes
* negative = error
*/
static inline int
@@ -86,13 +86,13 @@ read_varint(char **pos, size_t *remain, int32_t *res)
}
if (consumed > *remain)
- return 1;
+ return 0;
else if (consumed > MC_VARINT_MAX_BYTES)
return -1;
*remain -= consumed;
*res = (int32_t)val;
- return 0;
+ return 1;
}
static inline void
@@ -115,7 +115,77 @@ write_cmd(char **pos, const char *begin, const char *end)
write_bytes(pos, begin, end - begin);
}
+static int
+idle_check_handshake_complete(struct cfg *cfg, struct uring_task *task, int res)
+{
+ size_t remain;
+ char *pos;
+ int32_t mclen;
+ int r;
+
+ remain = task->tbuf->len;
+ pos = task->tbuf->buf;
+
+ r = read_varint(&pos, &remain, &mclen);
+ if (r < 0) {
+ fprintf(stderr, "Failed to parse message length\n");
+ return -EINVAL;
+ } else if (r == 0) {
+ return 0;
+ } else if (mclen < 2) {
+ fprintf(stderr, "Short MC message\n");
+ return -EINVAL;
+ }
+
+ fprintf(stderr, "MC message len: %" PRIi32 "\n", mclen);
+ fprintf(stderr, "Remain: %zu\n", remain);
+
+ if (mclen < remain)
+ return 0;
+
+ fprintf(stderr, "Complete message\n");
+ return 1;
+}
+
#define ONLINE_NEEDLE "\"online\""
+static int
+get_player_count(struct cfg *cfg, 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;
+
+ online = memmem(pos, remain, ONLINE_NEEDLE, strlen(ONLINE_NEEDLE));
+ if (!online) {
+ fprintf(stderr, "Could not find online count in JSON\n");
+ return -1;
+ }
+
+ remain -= (online - pos);
+
+ end = memchr(online, '}', remain);
+ if (!end) {
+ fprintf(stderr, "Could not parse JSON (no end)\n");
+ return -1;
+ }
+ *end = '\0';
+
+ if (sscanf(online, ONLINE_NEEDLE " : %u", &count) != 1) {
+ fprintf(stderr, "Could not parse JSON (online count)\n");
+ return -1;
+ }
+
+ return count;
+}
+
static void
idle_check_handshake_reply(struct cfg *cfg, struct uring_task *task, int res)
{
@@ -124,14 +194,13 @@ idle_check_handshake_reply(struct cfg *cfg, struct uring_task *task, int res)
int32_t jsonlen;
char *pos;
size_t remain;
+ int player_count;
int r;
fprintf(stderr, "%s: received %i bytes\n", __func__, res);
if (res < 0)
goto error;
- idle->remotebuflen += res;
-
/*
fprintf(stderr, "Received MC message (%i bytes):\n", res);
for (int i = 0; i < res; i++)
@@ -139,35 +208,29 @@ idle_check_handshake_reply(struct cfg *cfg, struct uring_task *task, int res)
fprintf(stderr, "\n");
*/
- remain = idle->remotebuflen;
- pos = idle->remotebuf;
+ remain = idle->tbuf.len;
+ pos = idle->tbuf.buf;
r = read_varint(&pos, &remain, &mclen);
- if (r < 0) {
- fprintf(stderr, "Failed to parse message length\n");
- goto error;
- } else if (r > 0) {
- goto read_more;
- } else if (mclen < 2) {
- fprintf(stderr, "Short MC message\n");
+ if (r <= 0 || mclen < 2 || mclen < remain) {
+ /* Should not happen since the msg has been checked already */
+ fprintf(stderr, "Invalid message\n");
goto error;
}
- fprintf(stderr, "MC message len: %" PRIi32 "\n", mclen);
- fprintf(stderr, "Remain: %zu\n", remain);
-
- if (mclen < remain)
- goto read_more;
+ fprintf(stderr, "%s: MC message len: %" PRIi32 "\n", __func__, mclen);
+ fprintf(stderr, "%s: Remain: %zu\n", __func__, remain);
if (*pos != MC_STATUS_REPLY) {
fprintf(stderr, "Unknown server reply\n");
goto error;
}
+
pos++;
remain--;
r = read_varint(&pos, &remain, &jsonlen);
- if (r != 0) {
+ if (r <= 0) {
fprintf(stderr, "Could not read JSON length\n");
goto error;
}
@@ -185,41 +248,12 @@ idle_check_handshake_reply(struct cfg *cfg, struct uring_task *task, int res)
fprintf(stderr, "%c", pos[i]);
fprintf(stderr, "\n");
- /*
- * 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;
+ player_count = get_player_count(cfg, pos, remain);
+ fprintf(stderr, "We have %i players\n", player_count);
- online = memmem(pos, remain, ONLINE_NEEDLE, strlen(ONLINE_NEEDLE));
- if (!online) {
- fprintf(stderr, "Could not find online count in JSON\n");
- goto error;
- }
-
- remain -= (online - pos);
-
- end = memchr(online, '}', remain);
- if (!end) {
- fprintf(stderr, "Could not parse JSON (no end)\n");
- goto error;
- }
- *end = '\0';
-
- if (sscanf(online, ONLINE_NEEDLE " : %u", &count) != 1) {
- fprintf(stderr, "Could not parse JSON (online count)\n");
+ if (player_count < 0)
goto error;
- }
-
- fprintf(stderr, "We have %u players\n", count);
- if (count > 0)
+ else if (player_count > 0)
idle->server->idle_count = 0;
else {
idle->server->idle_count++;
@@ -231,17 +265,8 @@ idle_check_handshake_reply(struct cfg *cfg, struct uring_task *task, int res)
return;
-read_more:
- if (idle->remotebuflen >= sizeof(idle->remotebuflen))
- goto error;
-
- uring_read(cfg, &idle->idlecheck, idle->remotebuf + idle->remotebuflen,
- sizeof(idle->remotebuf) - idle->remotebuflen,
- 0, idle_check_handshake_reply);
- return;
-
error:
- /* FIXME */
+ uring_task_close_fd(cfg, task);
return;
}
@@ -252,19 +277,11 @@ idle_check_handshake_sent(struct cfg *cfg, struct uring_task *task, int res)
fprintf(stderr, "%s: sent %i bytes\n", __func__, res);
if (res < 0) {
+ uring_task_close_fd(cfg, task);
return;
}
- idle->remotebufdone += res;
- if (idle->remotebufdone < idle->remotebuflen)
- uring_write(cfg, &idle->idlecheck,
- idle->remotebuf + idle->remotebufdone,
- idle->remotebuflen - idle->remotebufdone,
- idle_check_handshake_sent);
- else {
- idle->remotebuflen = 0;
- uring_read(cfg, &idle->idlecheck, idle->remotebuf, sizeof(idle->remotebuf), 0, idle_check_handshake_reply);
- }
+ uring_tbuf_read_until(cfg, &idle->idlecheck, idle_check_handshake_complete, idle_check_handshake_reply);
}
static void idle_check_connect_next_remote(struct cfg *cfg, struct idle *idle);
@@ -275,11 +292,13 @@ idle_check_remote_connected(struct cfg *cfg, struct uring_task *task, int res)
struct idle *idle = container_of(task, struct idle, idlecheck);
char buf[1024];
char *pos;
- char *cmdbuf = idle->remotebuf;
+ char *cmdbuf = idle->tbuf.buf;
uint16_t port = 25565;
+ /* FIXME: Write real remote addr and port */
fprintf(stderr, "%s: connected %i\n", __func__, res);
if (res < 0) {
+ uring_task_close_fd(cfg, task);
idle_check_connect_next_remote(cfg, idle);
return;
}
@@ -298,14 +317,13 @@ idle_check_remote_connected(struct cfg *cfg, struct uring_task *task, int res)
write_byte(&pos, MC_GET_STATUS);
write_cmd(&cmdbuf, buf, pos);
- idle->remotebufdone = 0;
- idle->remotebuflen = (cmdbuf - idle->remotebuf);
- fprintf(stderr, "Sending MC message (%zu bytes):\n", idle->remotebuflen);
- for (pos = idle->remotebuf; pos < cmdbuf; pos++)
+ idle->tbuf.len = (cmdbuf - idle->tbuf.buf);
+ fprintf(stderr, "Sending MC message (%zu bytes):\n", idle->tbuf.len);
+ for (pos = idle->tbuf.buf; pos < cmdbuf; pos++)
fprintf(stderr, "0x%02hhx ", *pos);
fprintf(stderr, "\n");
- uring_write(cfg, &idle->idlecheck, idle->remotebuf, idle->remotebuflen, idle_check_handshake_sent);
+ uring_tbuf_write(cfg, &idle->idlecheck, idle_check_handshake_sent);
}
/* FIXME: Parts of this could be shared with proxy.c, probably in server.c */
@@ -329,7 +347,7 @@ again:
if (!remote) {
fprintf(stderr, "No more remote addresses to attempt\n");
- /* FIXME: put tasks */
+ /* FIXME: put tasks? */
return;
}
@@ -445,8 +463,9 @@ idle_init(struct cfg *cfg, struct server *server)
perrordie("timerfd_settime");
uring_task_init(&idle->task, "idle", &server->task, idle_free);
- uring_task_init(&idle->idlecheck, "idlecheck", &idle->task, idle_check_free);
uring_task_set_fd(&idle->task, ifd);
+ uring_task_init(&idle->idlecheck, "idlecheck", &idle->task, idle_check_free);
+ uring_task_set_buf(&idle->idlecheck, &idle->tbuf);
idle->server = server;
server->idle = idle;
diff --git a/server.c b/server.c
index 4102d99..6443c7a 100644
--- a/server.c
+++ b/server.c
@@ -122,7 +122,7 @@ server_dump(struct server *scfg)
struct sockaddr_in46 *remote;
char abuf[ADDRSTRLEN];
- fprintf(stderr, "Dumping server %s\n", scfg->name);
+ fprintf(stderr, "\nDumping server %s\n", scfg->name);
switch (scfg->type) {
case SERVER_TYPE_ANNOUNCE:
fprintf(stderr, " * Type: announce\n");
@@ -145,6 +145,7 @@ server_dump(struct server *scfg)
fprintf(stderr, " * RCon:\n");
list_for_each_entry(remote, &scfg->rcons, list)
fprintf(stderr, " * %s\n", sockaddr_to_str(remote, abuf, sizeof(abuf)));
+ fprintf(stderr, "\n");
}
static void
diff --git a/uring.c b/uring.c
index 561be25..30cf513 100644
--- a/uring.c
+++ b/uring.c
@@ -119,7 +119,9 @@ uring_task_set_fd(struct uring_task *task, int fd)
void
uring_task_close_fd(struct cfg *cfg, struct uring_task *task)
{
- fprintf(stderr, "%s called with task 0x%p\n", __func__, task);
+ fprintf(stderr, "%s: called with task %s (0x%p)\n",
+ __func__, task->name, task);
+
if (task->fd < 0)
return;