aboutsummaryrefslogtreecommitdiff
path: root/client/applets/applet.c
diff options
context:
space:
mode:
Diffstat (limited to 'client/applets/applet.c')
-rw-r--r--client/applets/applet.c151
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;
+ }
+ }
+ }
+}