summaryrefslogtreecommitdiff
path: root/minecctl/minecctl-rcon.c
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-26 23:20:43 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-26 23:20:43 +0200
commita87e894ba3f3a8915389f651fb034f0d1835630c (patch)
tree70ca77275f6c79dc869c3bd1808d35e2239c0ced /minecctl/minecctl-rcon.c
parent957634c7c434b6c8d696ca8f4098e96a201fdfb0 (diff)
Split misc commands into a separate file
Diffstat (limited to 'minecctl/minecctl-rcon.c')
-rw-r--r--minecctl/minecctl-rcon.c470
1 files changed, 0 insertions, 470 deletions
diff --git a/minecctl/minecctl-rcon.c b/minecctl/minecctl-rcon.c
deleted file mode 100644
index c387b38..0000000
--- a/minecctl/minecctl-rcon.c
+++ /dev/null
@@ -1,470 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <ctype.h>
-#include <readline/readline.h>
-#include <readline/history.h>
-#include <alloca.h>
-#include <inttypes.h>
-#include <string.h>
-#include <stdarg.h>
-
-#include "utils.h"
-#include "minecctl.h"
-#include "minecctl-rcon.h"
-#include "server.h"
-#include "rcon-protocol.h"
-#include "misc.h"
-
-static void
-send_packet(int sfd, const char *buf, size_t len)
-{
- size_t off = 0;
- ssize_t r;
-
- while (true) {
- r = write(sfd, buf + off, len - off);
- if (r < 0) {
- if (errno == EINTR)
- continue;
- else
- die("Failed to write packet: %m");
- }
-
- off += r;
- if (off == len)
- break;
- }
-}
-
-/* Note: msg is null-terminated due to the mc protocol trailer */
-static void
-read_packet(int sfd, char *buf, size_t len, int32_t *id, int32_t *type, const char **msg)
-{
- size_t off = 0;
- ssize_t r;
- const char *error;
-
- while (true) {
- r = read(sfd, buf + off, len - off);
- if (r < 0) {
- if (errno == EINTR)
- continue;
- else
- die("Failed to read reply: %m");
- }
-
- if (r == 0)
- die("Failed, connection closed");
-
- off += r;
- if (rcon_protocol_packet_complete(buf, off))
- break;
-
- if (off >= len)
- die("Reply too large %zu and %zu", off, len);
- }
-
- if (!rcon_protocol_read_packet(buf, off, id, type, msg, &error))
- die("Failed to parse response: %s", error);
-}
-
-static void
-send_msg(int sfd, char *buf, size_t len, enum rcon_packet_type type,
- const char *msg, enum rcon_packet_type *rtype, const char **reply)
-{
- static uint32_t rcon_packet_id = 1;
- size_t plen;
- int32_t id;
-
- if (!rcon_protocol_create_packet(buf, len, &plen,
- rcon_packet_id, type, msg))
- die("Failed to create rcon packet");
-
- send_packet(sfd, buf, plen);
-
- read_packet(sfd, buf, len, &id, rtype, reply);
-
- /* FIXME: this should be shared */
- if (type == RCON_PACKET_LOGIN) {
- if (*rtype != RCON_PACKET_LOGIN_OK)
- die("Invalid reply id");
-
- if (id == RCON_PACKET_LOGIN_FAIL)
- *rtype = RCON_PACKET_LOGIN_FAIL;
- else if (id != rcon_packet_id)
- die("Invalid reply id");
- } else {
- if (id != rcon_packet_id)
- die("Invalid reply");
- }
-
- rcon_packet_id++;
-}
-
-static int
-rcon_login(struct cfg *cfg, struct server *server)
-{
- char buf[4096];
- int32_t rtype;
- const char *reply;
- int fd = -1;
-
- assert_die(cfg && server, "invalid arguments");
-
- if (list_empty(&server->rcon_addrs)) {
- error("%s: rcon address unknown", server->name);
- goto error;
- }
-
- fd = connect_any(&server->rcon_addrs, true);
- if (fd < 0) {
- error("%s: unable to connect", server->name);
- goto error;
- }
-
- if (!server->rcon_password)
- server->rcon_password = ask_password();
-
- if (!server->rcon_password) {
- error("%s: can't login - password missing", server->name);
- goto error;
- }
-
- send_msg(fd, buf, sizeof(buf), RCON_PACKET_LOGIN, server->rcon_password,
- &rtype, &reply);
-
- explicit_bzero(buf, sizeof(buf));
- free_password(&server->rcon_password);
-
- if (rtype == RCON_PACKET_LOGIN_OK)
- verbose("%s: login ok", server->name);
- else if (rtype == RCON_PACKET_LOGIN_FAIL) {
- info("%s: login failure, invalid password?", server->name);
- goto error;
- } else {
- error("%s: invalid return code: %" PRIi32, server->name, rtype);
- goto error;
- }
-
- return fd;
-
-error:
- close(fd);
- return -1;
-}
-
-static bool
-send_cmd(int sfd, const char *cmd)
-{
- char buf[4096];
- int32_t rtype;
- const char *reply;
-
- send_msg(sfd, buf, sizeof(buf), RCON_PACKET_COMMAND, cmd, &rtype, &reply);
-
- if (rtype != RCON_PACKET_RESPONSE) {
- die("Invalid return code: %" PRIi32, rtype);
- return false;
- }
-
-
- if (use_colors)
- info("%s%s%s", ANSI_GREY, reply, ANSI_NORMAL);
- else
- info("%s", reply);
-
- return true;
-}
-
-static void
-eat_whitespace(char **pos)
-{
- char *end;
- size_t len;
-
- while(isspace(**pos))
- (*pos)++;
-
- len = strlen(*pos);
- if (len == 0)
- return;
-
- end = *pos + len - 1;
- while (isspace(*end))
- end--;
- end++;
- *end = '\0';
-}
-
-/* midnight = 18000 */
-#define MCTIME_OFFSET 6000
-#define MCTIME_PER_DAY 24000
-#define MCTIME_PER_HOUR 1000
-#define MIN_PER_HOUR 60
-
-static inline unsigned
-mctime_days(unsigned mctime) {
- return (mctime / MCTIME_PER_DAY);
-}
-
-static inline unsigned
-mctime_hh(unsigned mctime) {
- return (mctime % MCTIME_PER_DAY) / MCTIME_PER_HOUR;
-}
-
-static inline unsigned
-mctime_mm(unsigned mctime) {
- return ((mctime % MCTIME_PER_HOUR) * MIN_PER_HOUR) / MCTIME_PER_HOUR;
-}
-
-static bool
-get_one_status(int fd, char *buf, size_t len, const char *cmd,
- size_t argc, const char *replyscan, const char **reply, ...)
-{
- int32_t rtype;
- va_list ap;
- int r;
-
- send_msg(fd, buf, len, RCON_PACKET_COMMAND, cmd, &rtype, reply);
- if (rtype != RCON_PACKET_RESPONSE)
- die("Invalid return code: %" PRIi32, rtype);
-
- va_start(ap, reply);
- r = vsscanf(*reply, replyscan, ap);
- va_end(ap);
-
- if (r == argc)
- return true;
- else
- return false;
-}
-
-bool
-do_status(struct cfg *cfg) {
- char buf[4096];
- char tbuf[4096];
- const char *reply;
- unsigned cplayers, maxplayers, gtime;
- unsigned epacks, apacks;
- unsigned bannedplayers, bannedips;
- int fd;
- struct server *server;
-
- server = server_get_default(cfg);
- fd = rcon_login(cfg, server);
- if (fd < 0)
- return false;
-
- if (get_one_status(fd, buf, sizeof(buf), "seed", 1,
- "Seed : [ %[^]]]", &reply, tbuf))
- info("Seed: %s", tbuf);
-
- if (get_one_status(fd, buf, sizeof(buf), "difficulty", 1,
- "The difficulty is %s", &reply, tbuf))
- info("Difficulty: %s", tbuf);
-
- if (get_one_status(fd, buf, sizeof(buf), "list", 2,
- "There are %u of a max %u players online",
- &reply, &cplayers, &maxplayers))
- info("Players: %u/%u", cplayers, maxplayers);
-
- if (get_one_status(fd, buf, sizeof(buf), "time query day", 1,
- "The time is %u", &reply, &gtime))
- info("In-game days: %u", gtime);
-
- if (get_one_status(fd, buf, sizeof(buf), "time query gametime", 1,
- "The time is %u", &reply, &gtime))
- info("World age: %ud:%02uh:%02um",
- mctime_days(gtime), mctime_hh(gtime), mctime_mm(gtime));
-
- if (get_one_status(fd, buf, sizeof(buf), "time query daytime", 1,
- "The time is %u", &reply, &gtime))
- info("Current in-game time: %02uh:%02um",
- mctime_hh(gtime + MCTIME_OFFSET), mctime_mm(gtime + MCTIME_OFFSET));
-
- if (get_one_status(fd, buf, sizeof(buf), "datapack list enabled", 2,
- "There are %u data packs enabled: %[^\n]", &reply, &epacks, tbuf))
- info("Enabled data packs (%u): %s", epacks, tbuf);
-
- if (get_one_status(fd, buf, sizeof(buf), "datapack list available", 2,
- "There are %u data packs available : %[^\n]", &reply, &apacks, tbuf))
- info("Available data packs (%u): %s", apacks, tbuf);
- else if (streq(reply, "There are no more data packs available"))
- info("Available data packs: none");
-
- if (get_one_status(fd, buf, sizeof(buf), "banlist players", 1,
- "There are %u bans", &reply, &bannedplayers))
- info("Banned players: %u", bannedplayers);
- else if (streq(reply, "There are no bans"))
- info("Banned players: 0");
-
- if (get_one_status(fd, buf, sizeof(buf), "banlist ips", 1,
- "There are %u bans", &reply, &bannedips))
- info("Banned IPs: %u", bannedips);
- else if (streq(reply, "There are no bans"))
- info("Banned IPs: 0");
-
- return true;
-}
-
-bool
-do_ping(_unused_ struct cfg *cfg) {
- die("Not implemented");
- return false;
-}
-
-static bool
-get_player_count(int fd, unsigned *current, unsigned *max)
-{
- char buf[4096];
- const char *reply;
- unsigned c, m;
-
- if (!get_one_status(fd, buf, sizeof(buf), "list", 2,
- "There are %u of a max %u players online",
- &reply, &c, &m))
- return false;
-
- if (current)
- *current = c;
-
- if (max)
- *max = m;
-
- return true;
-}
-
-static bool
-stop_one_server(struct cfg *cfg, struct server *server)
-{
- int fd;
- bool rv;
-
- fd = rcon_login(cfg, server);
- if (fd < 0)
- return false;
-
- if (cfg->force_stop) {
- unsigned current;
-
- if (!get_player_count(fd, &current, NULL)) {
- error("%s: unable to get player count, not stopping",
- server->name);
- return false;
- } else if (current > 0) {
- error("%s: has active players (use -f to force)",
- server->name);
- return false;
- }
- }
-
- info("%s: sending stop command", server->name);
- rv = send_cmd(fd, "stop");
- close(fd);
-
- return rv;
-}
-
-bool
-do_stop(struct cfg *cfg) {
- struct server *server;
-
- server = server_get_default(cfg);
- return stop_one_server(cfg, server);
-}
-
-bool
-do_stop_all(struct cfg *cfg) {
- struct server *server;
-
- list_for_each_entry(server, &cfg->servers, list) {
- server_read_config(cfg, server);
- stop_one_server(cfg, server);
- }
-
- return true;
-}
-
-bool
-do_pcount(struct cfg *cfg) {
- int fd;
- unsigned current, max;
- struct server *server;
-
- server = server_get_default(cfg);
- fd = rcon_login(cfg, server);
- if (fd < 0)
- return false;
-
- if (get_player_count(fd, &current, &max)) {
- info("Players: %u/%u", current, max);
- return true;
- } else {
- die("Failed to get player count");
- return false;
- }
-}
-
-bool
-do_console(struct cfg *cfg)
-{
- char *prompt;
- char *cmd;
- int fd;
- struct server *server;
-
- server = server_get_default(cfg);
- fd = rcon_login(cfg, server);
- if (fd < 0)
- return false;
-
- prompt = alloca(strlen(program_invocation_short_name) +
- STRLEN(" (") + strlen(server->name) + STRLEN("): ") + 1);
- sprintf(prompt, "%s (%s): ", program_invocation_short_name,
- server->name);
-
- while (true) {
- char *tmp;
-
- cmd = readline(prompt);
- if (!cmd)
- break;
-
- tmp = cmd;
- eat_whitespace(&tmp);
- if (*tmp == '\0') {
- xfree(cmd);
- continue;
- }
-
- if (streq(tmp, "q") || streq(tmp, "quit") ||
- streq(tmp, "/q") || streq(tmp, "/quit"))
- break;
-
- send_cmd(fd, tmp);
-
- if (streq(tmp, "stop") || streq(tmp, "/stop"))
- /* The server waits for us to close the connection */
- break;
-
- free(cmd);
- }
-
- xfree(cmd);
- return true;
-}
-
-bool
-do_command(struct cfg *cfg) {
- int fd;
- struct server *server;
-
- server = server_get_default(cfg);
- fd = rcon_login(cfg, server);
- if (fd < 0)
- return false;
-
- return send_cmd(fd, cfg->cmdstr);
-}
-