#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>

static void fmt_inaddr(char *buffer, const struct sockaddr_in *inaddr) {
    uint8_t a = (uint8_t) inaddr->sin_addr.s_addr;
    uint8_t b = (uint8_t) (inaddr->sin_addr.s_addr >> 8);
    uint8_t c = (uint8_t) (inaddr->sin_addr.s_addr >> 16);
    uint8_t d = (uint8_t) (inaddr->sin_addr.s_addr >> 24);
    uint16_t port = ntohs(inaddr->sin_port);
    sprintf(buffer, "%hhu.%hhu.%hhu.%hhu:%hu", a, b, c, d, port);
}

int main(int argc, const char **argv) {
    int fd = socket(AF_INET, SOCK_STREAM, 0);

    if (fd < 0) {
        perror("socket()");
        return EXIT_FAILURE;
    }

    struct sockaddr_in sa;
    socklen_t slen;
    char buffer[256];

    memset(&sa, 0, sizeof(sa));
    sa.sin_family = AF_INET;
    sa.sin_port = htons(4321);
    sa.sin_addr.s_addr = INADDR_ANY;

    if (bind(fd, (const struct sockaddr *) &sa, sizeof(sa)) != 0) {
        perror("bind()");
        return EXIT_FAILURE;
    }

    if (listen(fd, 64) != 0) {
        perror("listen()");
        return EXIT_FAILURE;
    }

    while (1) {
        int rfd;

        slen = sizeof(sa);
        if ((rfd = accept(fd, (struct sockaddr *) &sa, &slen)) < 0) {
            perror("accept()");
            return EXIT_FAILURE;
        }

        fmt_inaddr(buffer, &sa);
        printf("Received connection from %s\n", buffer);

        while (1) {
            ssize_t len;

            if ((len = recv(rfd, buffer, sizeof(buffer), 0)) < 0) {
                perror("recv()");
                break;
            }

            if (len == 0) {
                break;
            }

            if (len >= 4 && !strncmp(buffer, "quit", 4)) {
                break;
            }

            fwrite(buffer, 1, len, stdout);

            if ((len = send(rfd, buffer, len, 0)) < 0) {
                perror("send()");
                break;
            }
        }

        printf("Connection closed\n");
        close(rfd);
    }

    return 0;
}