From c829fe7b03d4eaabb967ab4d9ecb7a7a8663c6db Mon Sep 17 00:00:00 2001 From: Henk Kalkwater Date: Mon, 7 Dec 2020 11:49:21 +0100 Subject: [PATCH] Initial commit --- CMakeLists.txt | 14 ++++ src/kerstezel.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++ src/kerstezel.h | 0 3 files changed, 227 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 src/kerstezel.c create mode 100644 src/kerstezel.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a0e6656 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,14 @@ +set(CMAKE_MINIMUM_VERSION_REQUIRED 3.0) +project(kerstezel-klant) + +if (MSVC) + add_compile_options(/W4 /WX) +else() + add_compile_options(-Wall -Wextra -pedantic -Werror) +endif() + + +set(KERSTEZEL_SOURCES src/kerstezel.c) +set(KERSTEZEL_HEADERS src/kerstezel.h) + +add_executable(kerstezel ${KERSTEZEL_SOURCES} ${KERSTEZEL_HEADERS}) diff --git a/src/kerstezel.c b/src/kerstezel.c new file mode 100644 index 0000000..6d24c15 --- /dev/null +++ b/src/kerstezel.c @@ -0,0 +1,213 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define LOGF(x, ...) do { logf_impl(x, __FILE__, __LINE__, __func__, __VA_ARGS__); } while(0); +#define LOG(x) do { log_impl(x, __FILE__, __LINE__, __func__); } while(0); +#define DEFAULT_PORT 9305 +#define MBUF_SIZE 2048 + +const char *SOCKET_ERROR = "Socket-fout"; + +typedef struct mbuf { + /// Internal buffer + char buffer[MBUF_SIZE]; + /// Socket/file descriptor + int sock; + /// Read position + size_t rpos, + /// Write position + wpos; + +} mbuf_t; + +void log_impl(const char *message, const char *file, int line, const char *func) { + fprintf(stderr, "%s:%d:%s: %s\n", file, line, func, message); +} +void logf_impl(const char *message, const char *file, int line, const char *func, ...) { + va_list args; + va_start(args, func); + fprintf(stderr, "%s:%d %s: ", file, line, func); + vfprintf(stderr, message, args); + fprintf(stderr, "\n"); + va_end(args); +} + +int quit_if_fail(int err, const char *failMessage) { + if (err < 0) { + int no = errno; + size_t stringSize = strlen(failMessage) + strlen(strerror(no)) + 2; + char *msg = (char *) malloc(stringSize); + strcpy(msg, failMessage); + strcat(msg, ": "); + strcat(msg, strerror(no)); + LOG(msg); + free(msg); + exit(EXIT_FAILURE); + } + return err; +} + +mbuf_t *mbuf_create(void) { + mbuf_t *res = malloc(sizeof(mbuf_t)); + res->rpos = 0; + res->wpos = 0; + res->sock = -1; + memset(res->buffer, 0, MBUF_SIZE * sizeof(char)); + return res; +} + +/** + * Reads until it encounters `c` from the given socket + * + * `c` is not included in the output. The output is null-terminated. + * + * @param c The character to stop reading + * @param out A pointer to allocated memory where the read line can be stored. + * @param max_size The max size. + */ +int mbuf_read_until(mbuf_t *buf, char c, char *out, size_t max_size) { + size_t i = 0; + ssize_t n; + + while (i < max_size) { + if (buf->rpos == buf->wpos) { + size_t wpos = buf->wpos % MBUF_SIZE; + if ((n = read(buf->sock, buf->buffer + wpos, MBUF_SIZE - wpos)) < 0) { + if (errno == EINTR) continue; + return -1; + } else if (n == 0) { + return 0; + } else { + buf->wpos += n; + } + } + + out[i++] = buf->buffer[buf->rpos++ % MBUF_SIZE]; + if (out[i - 1] == c) break; + } + + if (i == max_size) { + errno = EOVERFLOW; + //LOGF("Buffer is te klein (bijts gelezen %d > %d)", i, max_size); + return -1; + } + out[i - 1] = '\0'; + return i - 1; +} + +void do_trommel() { + //TODO: implement +} + +int do_handshake(mbuf_t *mbuf) { + char buf[1024]; + if (mbuf_read_until(mbuf, '\n', buf, sizeof(buf)) < 0) return -1; + int reslen = strlen(buf) - strlen("e gaat 'ie?"); + if (reslen < 2 || (reslen & 1)) { + errno = EPROTO; + return -1; + } + + size_t response_size = reslen + 4; + char *response = (char *) malloc(response_size); + response[0] = '\0'; + reslen /= 2; + for (int i = 0; i < reslen; i++) { + strcat(response, "go"); + } + strcat(response, "ed\n"); + if (write(mbuf->sock, response, response_size) < 0) return -1; + free(response); + return 0; +} + +int do_command_loop(mbuf_t *mbuf) { + char buf[1024]; + int len; + + while(1) { + if ( (len = mbuf_read_until(mbuf, '\n', buf, sizeof(buf))) < 0) return -1; + if (len == 0) return 0; + LOGF("COMMANDO: %s", buf); + if (strcmp(buf, "trommel") == 0) { + const char *ok = "oké\n"; + write(mbuf->sock, ok, strlen(ok) * sizeof(char)); + } else if (strcmp(buf, "ping") == 0) { + write(mbuf->sock, "pong\n", 5 * sizeof(char)); + } else { + const char *mesg = "onbekend commando\n"; + write(mbuf->sock, mesg, strlen(mesg) * sizeof(char)); + } + } + + return 0; +} + +int main(int argc, char *argv[]) { + if (argc < 3) { + const char *format = "GEBRUIK: %s [ADRES] [POORT]"; + size_t length = strlen(argv[0]) + strlen(format); + char *msg = (char *) malloc(length); + snprintf(msg, length, format, argv[0]); + LOG(msg); + free(msg); + return EXIT_FAILURE; + } + LOG("Kerstezel starten"); + + struct addrinfo hints, *servinfo, *p; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + int res, res2; + if ((res = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) { + LOGF("Fout bij het herleiden van de gastheernaam: %s", gai_strerror(res)); + exit(EXIT_FAILURE); + } + + mbuf_t *buf = mbuf_create(); + + char address[INET6_ADDRSTRLEN] = {0}; + for (p = servinfo; p != NULL; p = p->ai_next) { + void *ptr = NULL; + switch(p->ai_family) { + case AF_INET: + ptr = &((struct sockaddr_in *) p->ai_addr)->sin_addr; + break; + case AF_INET6: + ptr = &((struct sockaddr_in6 *) p->ai_addr)->sin6_addr; + break; + } + if (inet_ntop(p->ai_family, ptr, address, p->ai_addrlen) == NULL) { + LOGF("Kon adres niet omzetten: %s", strerror(errno)); + } else { + LOGF("Verbinden met %s", address); + } + res = socket(p->ai_family, SOCK_STREAM, 0); + if (res < 0) continue; + res2 = connect(res, p->ai_addr, sizeof(address)); + if (res2 == 0) break; + } + buf->sock = res; + + quit_if_fail(res, "Kon niet verbinden"); + //(void) quit_if_fail(connect(buf->sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)), "Kon niet verbinden"); + + (void) quit_if_fail(do_handshake(buf), "Handenschudden mislukt"); + LOG("Handjeschudden voltooid") + (void) quit_if_fail(do_command_loop(buf), "Fout"); + LOG("De andere kant heeft de verbinding verbroken"); + free(buf); + return 0; +} diff --git a/src/kerstezel.h b/src/kerstezel.h new file mode 100644 index 0000000..e69de29