From 99b2c70137fef05a5a18f439b9010ddba455f5cb Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sat, 27 Jun 2020 15:18:45 +0200 Subject: Create a shared mc protocol implementation and use it in the proxy and cmd line tool --- minecctl/mc-commands.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ minecctl/mc-commands.h | 6 ++++ minecctl/meson.build | 1 + minecctl/misc-commands.c | 15 ++++++++++ minecctl/misc-commands.h | 2 ++ minecctl/misc.c | 9 ++++-- minecctl/rcon-commands.c | 19 ++++++------ minecctl/rcon-commands.h | 2 +- 8 files changed, 118 insertions(+), 13 deletions(-) create mode 100644 minecctl/mc-commands.c create mode 100644 minecctl/mc-commands.h (limited to 'minecctl') diff --git a/minecctl/mc-commands.c b/minecctl/mc-commands.c new file mode 100644 index 0000000..0ac20d0 --- /dev/null +++ b/minecctl/mc-commands.c @@ -0,0 +1,77 @@ +#include + +#include "utils.h" +#include "minecctl.h" +#include "server.h" +#include "mc-commands.h" +#include "misc.h" +#include "mc-protocol.h" + +bool +do_mc_pcount(struct cfg *cfg, unsigned *online, unsigned *max) +{ + struct server *server; + struct saddr *saddr; + char buf[4096]; + size_t plen, off; + ssize_t r; + bool rv = false; + int fd; + + server = server_get_default(cfg); + + fd = connect_any(&server->mc_addrs, true); + if (fd < 0) { + error("%s: unable to connect", server->name); + return false; + } + + /* FIXME: connect_any needs to indicate the address it used */ + saddr = list_first_entry(&server->mc_addrs, struct saddr, list); + if (!saddr) { + error("No saddr"); + goto out; + } + + if (!mc_protocol_create_status_request(buf, sizeof(buf), &plen, saddr)) { + error("Failed to create req"); + goto out; + } + + /* FIXME: do proper checks for EINTR etc */ + off = 0; + while (off < plen) { + r = write(fd, buf + off, plen - off); + if (r <= 0) { + error("write failed: %zi (%m)", r); + goto out; + } + off += r; + } + + off = 0; + while (off < sizeof(buf)) { + r = read(fd, buf + off, sizeof(buf) - off); + if (r <= 0) { + error("Read failed %zi: %m", r); + goto out; + } + + off += r; + + if (mc_is_handshake_complete(buf, off)) { + rv = true; + break; + } + } + + if (!mc_protocol_parse_status_reply(buf, off, online, max)) { + error("Failed to get player count"); + return false; + } + +out: + close(fd); + return rv; +} + diff --git a/minecctl/mc-commands.h b/minecctl/mc-commands.h new file mode 100644 index 0000000..3140a73 --- /dev/null +++ b/minecctl/mc-commands.h @@ -0,0 +1,6 @@ +#ifndef foomccommandshfoo +#define foomccomanndshfoo + +bool do_mc_pcount(struct cfg *cfg, unsigned *online, unsigned *max); + +#endif diff --git a/minecctl/meson.build b/minecctl/meson.build index e3bddcc..7a41203 100644 --- a/minecctl/meson.build +++ b/minecctl/meson.build @@ -2,6 +2,7 @@ minecctl_sources = [ 'minecctl.c', 'server.c', 'rcon-commands.c', + 'mc-commands.c', 'misc-commands.c', 'misc.c', ] diff --git a/minecctl/misc-commands.c b/minecctl/misc-commands.c index 6b70c55..c64a005 100644 --- a/minecctl/misc-commands.c +++ b/minecctl/misc-commands.c @@ -2,6 +2,8 @@ #include "minecctl.h" #include "server.h" #include "misc-commands.h" +#include "rcon-commands.h" +#include "mc-commands.h" bool do_list(struct cfg *cfg) @@ -16,3 +18,16 @@ do_list(struct cfg *cfg) return true; } +bool +do_pcount(struct cfg *cfg) +{ + unsigned x, y; + + if (do_rcon_pcount(cfg, &y, &x)) + error("Rcon says %u/%u", y, x); + + if (do_mc_pcount(cfg, &y, &x)) + error("MC says %u/%u", y, x); + + return true; +} diff --git a/minecctl/misc-commands.h b/minecctl/misc-commands.h index e0dc675..8270601 100644 --- a/minecctl/misc-commands.h +++ b/minecctl/misc-commands.h @@ -3,5 +3,7 @@ bool do_list(struct cfg *cfg); +bool do_pcount(struct cfg *cfg); + #endif diff --git a/minecctl/misc.c b/minecctl/misc.c index bb33161..72eb03c 100644 --- a/minecctl/misc.c +++ b/minecctl/misc.c @@ -68,8 +68,13 @@ connect_any(struct list_head *addrs, bool may_fail) bool connected = false; int sfd; - if (list_empty(addrs)) - die("No address to connect to"); + /* FIXME: check callers and coordinate debug msg */ + if (list_empty(addrs)) { + if (may_fail) + return -1; + else + die("No address to connect to"); + } list_for_each_entry(saddr, addrs, list) { verbose("Attempting connection to %s", saddr->addrstr); diff --git a/minecctl/rcon-commands.c b/minecctl/rcon-commands.c index 02b970f..cf43c5e 100644 --- a/minecctl/rcon-commands.c +++ b/minecctl/rcon-commands.c @@ -387,23 +387,22 @@ do_stop_all(struct cfg *cfg) { } bool -do_pcount(struct cfg *cfg) { - int fd; - unsigned current, max; +do_rcon_pcount(struct cfg *cfg, unsigned *online, unsigned *max) +{ struct server *server; + bool rv; + int fd; 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; - } + rv = get_player_count(fd, online, max); + + close(fd); + + return rv; } bool diff --git a/minecctl/rcon-commands.h b/minecctl/rcon-commands.h index 5366bf9..1714dd5 100644 --- a/minecctl/rcon-commands.h +++ b/minecctl/rcon-commands.h @@ -9,7 +9,7 @@ bool do_stop(struct cfg *cfg); bool do_stop_all(struct cfg *cfg); -bool do_pcount(struct cfg *cfg); +bool do_rcon_pcount(struct cfg *cfg, unsigned *online, unsigned *max); bool do_console(struct cfg *cfg); -- cgit v1.2.3