From a87e894ba3f3a8915389f651fb034f0d1835630c Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Fri, 26 Jun 2020 23:20:43 +0200 Subject: Split misc commands into a separate file --- minecctl/minecctl-rcon.c | 470 ----------------------------------------------- 1 file changed, 470 deletions(-) delete mode 100644 minecctl/minecctl-rcon.c (limited to 'minecctl/minecctl-rcon.c') 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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, >ime)) - info("In-game days: %u", gtime); - - if (get_one_status(fd, buf, sizeof(buf), "time query gametime", 1, - "The time is %u", &reply, >ime)) - 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, >ime)) - 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, ¤t, 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, ¤t, &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); -} - -- cgit v1.2.3