summaryrefslogtreecommitdiff
path: root/rcon.c
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-23 11:11:26 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-23 11:11:26 +0200
commitfd4f4ace264a91355df46186dd88f566fb451aa5 (patch)
tree49d8ea7bfc647a5d31c2f37b082d5fcef07842d9 /rcon.c
parent7c6a78910429f2fa6cb3f0570e66c782d2f17748 (diff)
Move rcon to server-rcon in preparation for separate rcon tool
Diffstat (limited to 'rcon.c')
-rw-r--r--rcon.c375
1 files changed, 0 insertions, 375 deletions
diff --git a/rcon.c b/rcon.c
deleted file mode 100644
index ef46d44..0000000
--- a/rcon.c
+++ /dev/null
@@ -1,375 +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 "rcon.h"
-
-struct rcon {
- struct server *server;
- struct connection conn;
- struct uring_task task;
- struct uring_task_buf tbuf;
-};
-
-static int32_t
-read_int(char **pos, size_t *len)
-{
- uint32_t val;
- char *p;
-
- assert_return(pos && *pos, 0);
-
- if (len && *len < 4)
- return 0;
-
- p = *pos;
- val = ((uint8_t)p[0] << 0);
- val += ((uint8_t)p[1] << 8);
- val += ((uint8_t)p[2] << 16);
- val += ((uint8_t)p[3] << 24);
-
- *pos += 4;
- if (len)
- *len -= 4;
-
- return (int32_t)val;
-}
-
-static void
-write_int(char **pos, size_t *len, int32_t orig)
-{
- uint32_t val = (uint32_t)orig;
- char *p;
-
- assert_return(pos && *pos);
-
- p = *pos;
- p[0] = (val >> 0) & 0xff;
- p[1] = (val >> 8) & 0xff;
- p[2] = (val >> 16) & 0xff;
- p[3] = (val >> 24) & 0xff;
-
- *pos += 4;
- if (len)
- *len += 4;
-}
-
-static void
-write_str(char **pos, size_t *len, const char *str)
-{
- size_t towrite;
-
- assert_return(pos && *pos && !empty_str(str));
-
- towrite = strlen(str);
- memcpy(*pos, str, towrite);
- *pos += towrite;
- if (len)
- *len += towrite;
-}
-
-static void
-write_end(char **pos, size_t *len)
-{
- char *p;
-
- assert_return(pos && *pos);
-
- p = *pos;
- p[0] = 0x00;
- p[1] = 0x00;
-
- *pos += 2;
- if (len)
- *len += 2;
-}
-
-enum rcon_packet_type {
- RCON_PACKET_LOGIN = 3,
- RCON_PACKET_LOGIN_OK = 2,
- RCON_PACKET_LOGIN_FAIL = -1,
- RCON_PACKET_COMMAND = 2,
- RCON_PACKET_RESPONSE = 0,
-};
-
-static void
-create_packet(struct rcon *rcon, int32_t reqid,
- enum rcon_packet_type type, const char *msg)
-{
- char *pos;
-
- assert_return(rcon && !empty_str(msg));
-
- /* Body */
- pos = &rcon->tbuf.buf[4];
- rcon->tbuf.len = 4;
- write_int(&pos, &rcon->tbuf.len, reqid);
- write_int(&pos, &rcon->tbuf.len, type);
- write_str(&pos, &rcon->tbuf.len, msg);
- write_end(&pos, &rcon->tbuf.len);
-
- /* Header (length of body) */
- pos = &rcon->tbuf.buf[0];
- write_int(&pos, NULL, rcon->tbuf.len - 4);
-
- debug(DBG_RCON, "created packet (reqid: %" PRIi32 ", type %" PRIi32
- ", len %zu, payload: %s)",
- reqid, type, rcon->tbuf.len, msg);
-}
-
-static int
-packet_complete(struct uring_task *task, int res)
-{
- char *pos;
- size_t len;
- int32_t plen;
-
- assert_return(task, 0);
- assert_task_alive_or(DBG_RCON, task, return -EINTR);
-
- pos = task->tbuf->buf;
- len = task->tbuf->len;
- if (task->tbuf->len < 14)
- return 0;
-
- plen = read_int(&pos, &len);
- debug(DBG_RCON, "reply size: %zu bytes, packet size %" PRIi32,
- task->tbuf->len, plen + 4);
-
- if (task->tbuf->len < plen + 4)
- return 0;
- else
- return 1;
-}
-
-static bool
-rcon_read_packet(struct rcon *rcon, int32_t *id,
- int32_t *type, char **rmsg)
-{
- char *pos;
- size_t len;
- int32_t plen;
-
- assert_return(rcon && id && type && rmsg, false);
-
- pos = rcon->tbuf.buf;
- len = rcon->tbuf.len;
- plen = read_int(&pos, &len);
- *id = read_int(&pos, &len);
- *type = read_int(&pos, &len);
- *rmsg = NULL;
-
- if (plen < 10) {
- error("invalid packet length: %" PRIi32, plen);
- return false;
- }
-
- if (len > 2) {
- *rmsg = pos;
- pos += len - 2;
- len = 2;
- }
-
- if (len < 2) {
- error("short message");
- return false;
- }
-
- if (pos[0] != '\0' || pos[1] != '\0') {
- error("invalid trailer");
- return false;
- }
-
- debug(DBG_RCON, "response - len: %" PRIi32 ", id: %" PRIi32
- ", type: %" PRIi32 ", msg: %s",
- plen, *id, *type, *rmsg);
-
- return true;
-}
-
-static void
-rcon_stop_reply(struct uring_task *task, int res)
-{
- struct rcon *rcon = container_of(task, struct rcon, task);
- int32_t id;
- int32_t type;
- char *msg;
-
- assert_return(task);
- assert_task_alive(DBG_RCON, task);
-
- if (res < 0) {
- debug(DBG_RCON, "res: %i", res);
- goto out;
- }
-
- debug(DBG_RCON, "packet complete");
- rcon_read_packet(rcon, &id, &type, &msg);
-
- if (id != 2) {
- error("rcon stop failed - reply id (%" PRIi32 ")", id);
- goto out;
- } else if (type != RCON_PACKET_RESPONSE) {
- error("rcon stop failed - reply type (%" PRIi32 ")", type);
- goto out;
- }
-
- verbose("rcon stop successful (%s)", msg);
-
-out:
- uring_task_put(&rcon->task);
-}
-
-static void
-rcon_stop_sent(struct uring_task *task, int res)
-{
- struct rcon *rcon = container_of(task, struct rcon, task);
-
- assert_return(task);
- assert_task_alive(DBG_RCON, task);
-
- if (res < 0) {
- debug(DBG_RCON, "res: %i", res);
- uring_task_put(&rcon->task);
- return;
- }
-
- debug(DBG_RCON, "stop cmd sent");
- uring_tbuf_read_until(&rcon->task, packet_complete, rcon_stop_reply);
-}
-
-static void
-rcon_login_reply(struct uring_task *task, int res)
-{
- struct rcon *rcon = container_of(task, struct rcon, task);
- int32_t id;
- int32_t type;
- char *msg;
-
- assert_return(task);
- assert_task_alive(DBG_RCON, task);
-
- if (res < 0) {
- debug(DBG_RCON, "res: %i", res);
- goto error;
- }
-
- debug(DBG_RCON, "packet complete");
- rcon_read_packet(rcon, &id, &type, &msg);
-
- if (id != 1) {
- error("rcon login failed - unexpected reply id (%" PRIi32 ")", id);
- goto error;
- } else if (type == RCON_PACKET_LOGIN_FAIL) {
- error("rcon login failed - incorrect password");
- goto error;
- } else if (type != RCON_PACKET_LOGIN_OK) {
- error("rcon login failed - unexpected reply type (%" PRIi32 ")", type);
- goto error;
- }
-
- debug(DBG_RCON, "rcon login successful");
- create_packet(rcon, 2, RCON_PACKET_COMMAND, "stop");
- uring_tbuf_write(&rcon->task, rcon_stop_sent);
- return;
-
-error:
- uring_task_put(&rcon->task);
-}
-
-static void
-rcon_login_sent(struct uring_task *task, int res)
-{
- struct rcon *rcon = container_of(task, struct rcon, task);
-
- assert_return(task);
- assert_task_alive(DBG_RCON, task);
-
- if (res < 0) {
- debug(DBG_RCON, "res: %i", res);
- uring_task_put(&rcon->task);
- return;
- }
-
- debug(DBG_RCON, "login sent");
- uring_tbuf_read_until(&rcon->task, packet_complete, rcon_login_reply);
-}
-
-static void
-rcon_connected_cb(struct connection *conn, bool connected)
-{
- struct rcon *rcon = container_of(conn, struct rcon, conn);
-
- assert_return(conn);
- assert_task_alive(DBG_RCON, &rcon->task);
-
- if (!connected) {
- error("rcon connection to remote server (%s) failed",
- rcon->server->name);
- uring_task_put(&rcon->task);
- return;
- }
-
- create_packet(rcon, 1, RCON_PACKET_LOGIN, rcon->server->rcon_password);
- uring_tbuf_write(&rcon->task, rcon_login_sent);
-}
-
-static void
-rcon_free(struct uring_task *task)
-{
- struct rcon *rcon = container_of(task, struct rcon, task);
-
- assert_return(task);
-
- debug(DBG_RCON, "task %p, idle %p", task, rcon);
- rcon->server->rcon = NULL;
- xfree(rcon);
-}
-
-void
-rcon_refdump(struct rcon *rcon)
-{
- assert_return_silent(rcon);
-
- uring_task_refdump(&rcon->task);
-}
-
-void
-rcon_delete(struct server *server)
-{
- assert_return_silent(server->rcon);
-
- debug(DBG_RCON, "closing fd %i", server->rcon->task.fd);
- uring_task_destroy(&server->rcon->task);
- server->rcon = NULL;
-}
-
-void
-rcon_init(struct server *server)
-{
- struct rcon *rcon;
-
- assert_return(server && !server->rcon && !list_empty(&server->rcons) && !empty_str(server->rcon_password));
-
- rcon = zmalloc(sizeof(*rcon));
- if (!rcon)
- die("malloc: %m");
-
- uring_task_init(&rcon->task, "rcon", &server->task, rcon_free);
- uring_task_set_buf(&rcon->task, &rcon->tbuf);
- rcon->server = server;
- server->rcon = rcon;
-
- connect_any(&rcon->task, &server->rcons, &rcon->conn, rcon_connected_cb);
-}