aboutsummaryrefslogtreecommitdiff
path: root/client/applets/applet.c
blob: 3f02e60bd1f52e05e9233f9e0e6e970a36a82642 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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;
            }
        }
    }
}