#define _GNU_SOURCE
#include "channel.h"
#include "exchange.h"
#include <fcntl.h>
#include <stdlib.h>
#include <sys/mman.h>

int main(int argc, char **argv)
{
    if (argc != 3 || strlen(argv[2]) >= 64) {
        fprintf(stderr, "usage: %s SOCKET /SHM_NAME (under 64 bytes)\n", argv[0]);
        return EXIT_FAILURE;
    }
    char name[64] = {0};
    memcpy(name, argv[2], strlen(argv[2]));
    int result = EXIT_FAILURE, listener = -1, peer = -1;
    int initialized = 0, published = 0;
    int fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR, 0600);
    struct exchange *box = MAP_FAILED;
    if (fd == -1 || ftruncate(fd, (off_t)sizeof(*box)) == -1)
        goto out;
    box = mmap(NULL, sizeof(*box), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (box == MAP_FAILED || exchange_init(box) == -1)
        goto out;
    initialized = 1;
    listener = channel_open(argv[1], 1);
    if (listener == -1)
        goto out;
    peer = channel_accept(listener);
    if (peer == -1)
        goto out;
    published = 1;
    if (channel_send(peer, name, sizeof(name)) == -1 ||
        exchange_server(box) == -1 || channel_finished(peer) == -1)
        goto out;
    puts("exchange complete");
    result = EXIT_SUCCESS;
out:
    if (result != EXIT_SUCCESS)
        perror("POSIX server");
    if (initialized && (!published || result == EXIT_SUCCESS) &&
        exchange_destroy(box) == -1) {
        perror("sem_destroy");
        result = EXIT_FAILURE;
    }
    if (box != MAP_FAILED && munmap(box, sizeof(*box)) == -1) {
        perror("munmap");
        result = EXIT_FAILURE;
    }
    if (fd != -1) {
        if (close(fd) == -1) {
            perror("close");
            result = EXIT_FAILURE;
        }
        if (shm_unlink(name) == -1) {
            perror("shm_unlink");
            result = EXIT_FAILURE;
        }
    }
    if (peer != -1 && close(peer) == -1) {
        perror("peer close");
        result = EXIT_FAILURE;
    }
    if (listener != -1) {
        if (channel_remove(listener, argv[1]) == -1) {
            perror("listener cleanup");
            result = EXIT_FAILURE;
        }
    }
    return result;
}
