diff options
Diffstat (limited to 'client/applets/applet.c')
-rw-r--r-- | client/applets/applet.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/client/applets/applet.c b/client/applets/applet.c new file mode 100644 index 0000000..3f02e60 --- /dev/null +++ b/client/applets/applet.c @@ -0,0 +1,151 @@ +#include "applet.h" + +#include <libac.h> +#include <stdio.h> +#include <sys/socket.h> +#include <err.h> +#include <errno.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <stdbool.h> +#include <stdint.h> + +static int fd = 0; +void *connection = NULL; + +const char *get_world(enum ac_world world) { + switch (world) { + case overworld: return "overworld"; + case nether: return "nether"; + case end: return "end"; + default: return "unknown"; + } +} + +static void cleanup(void) { + if (connection) ac_disconnect(connection, false); + if (fd) close(fd); + ac_free(); +} + +static void intr(int signum) {} + +static int on_send(const void *sock, + const void *buffer, + const size_t len) { + size_t pos; + const uint8_t *ptr = buffer; + int retval; + for (pos = 0U; pos < len; pos += retval) { + size_t n = len - pos; + retval = (int) send(fd, &ptr[pos], (int) n, 0); + if (retval < 0) { + const int e = errno; + perror("Cannot write to socket"); + return e; + } + } + return 0; +} + +/* Move init to a separate function from main() so we do not need to keep those stack variables all the time. */ +static void init(void) { + const char *id = getenv("ID"); + const char *token = getenv("TOKEN"); + if (!id) errx(64, "Required envvar: ID"); + if (!token) errx(64, "Required envvar: TOKEN"); + + atexit(cleanup); + int r; + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) <= 0) err(errno, "Cannot create socket"); + struct in_addr ad = { + .s_addr = 127 | 0 << 8 | 0 << 16 | 1 << 24 + }; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(PORT), + .sin_addr = ad + }; + if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) err(errno, "Cannot connect to server"); + libac_config_t libac_conf = { + .tok = NULL, +#ifdef DEBUG + .out = stderr, +#else + .out = NULL +#endif + }; + if ((r = ac_init(&libac_conf))) errx(r, "Cannot start libac: %d.", r); + ac_connection_parameters_t param = { + .host = "127.0.0.1", + .port = PORT, + .id = (char *) id, + .token = (char *) token, + .version = 0, + .sock = &fd, + .on_send = on_send + }; + if ((r = ac_connect(param, &connection))) errx(r, "Cannot connect to server: %d.", r); + struct sigaction sa; + sa.sa_handler = intr; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction(SIGINT, &sa, NULL) == -1) err(errno, "Cannot set SIGINT handler."); + if (sigaction(SIGTERM, &sa, NULL) == -1) err(errno, "Cannot set SIGTERM handler."); +} + +int main(void) { + init(); + int r; + int bytes; + uint8_t buffer[1024U]; + ac_obj_t *obj = NULL; + bool ready = false; + while (1) { + if ((bytes = (int) recv(fd, buffer, sizeof(buffer), 0)) <= 0) { + if (bytes < 0) { + if (errno == EAGAIN) continue; + if (errno == EINTR) { + printf("Exit.\n"); + return 0; + } + err(errno, "Cannot read from socket"); + } + errx(1, "Connection aborted"); + } + size_t pos = 0; + size_t read = 0; + bool again = false; + while (pos < bytes || again) { + if (again) { + r = ac_receive(connection, NULL, 0, 0, &obj, NULL); + again = false; + } else { + r = ac_receive(connection, buffer, pos, bytes, &obj, &read); + pos += read; + } + if (r == AC_E_AGAIN) { + again = true; + } else if (r) { + errx(r, "Cannot parse server response: %d.", r); + } + if (!ready) { + enum ac_connection_state state; + if ((r = ac_get_state(connection, &state))) { + errx(r, "Cannot read state: %d.", r); + } + if (state == AC_STATE_READY) { + printf("Connected.\n"); + ready = true; + continue; + } + } + if (!obj) { + continue; + } + } + } +} |