From ea053d96f7e89e053d4af8d39b04c5428760345f Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Tue, 23 Jun 2020 20:56:22 +0200 Subject: Big renaming, move some more functionality to shared lib --- minecproxy/server-rcon.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 minecproxy/server-rcon.c (limited to 'minecproxy/server-rcon.c') diff --git a/minecproxy/server-rcon.c b/minecproxy/server-rcon.c new file mode 100644 index 0000000..1f8ef70 --- /dev/null +++ b/minecproxy/server-rcon.c @@ -0,0 +1,227 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} + -- cgit v1.2.3