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

int main(int argc, char **argv)
{
    if (argc != 2) {
        fprintf(stderr, "usage: %s SOCKET\n", argv[0]);
        return EXIT_FAILURE;
    }
    int result = EXIT_FAILURE, fd = -1;
    int peer = channel_open(argv[1], 0);
    struct exchange *box = MAP_FAILED;
    struct stat info;
    if (peer == -1 || (fd = descriptor_receive(peer)) == -1 ||
        fstat(fd, &info) == -1)
        goto out;
    int required = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL;
    int seals = fcntl(fd, F_GET_SEALS);
    if (seals == -1)
        goto out;
    if (info.st_size != (off_t)sizeof(*box) || (seals & required) != required) {
        errno = EPROTO;
        goto out;
    }
    box = mmap(NULL, sizeof(*box), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (box == MAP_FAILED || exchange_client(box) == -1)
        goto out;
    result = EXIT_SUCCESS;
out:
    if (result != EXIT_SUCCESS)
        perror("memfd client");
    if (box != MAP_FAILED && munmap(box, sizeof(*box)) == -1) {
        perror("munmap");
        result = EXIT_FAILURE;
    }
    if (fd != -1 && close(fd) == -1) {
        perror("close");
        result = EXIT_FAILURE;
    }
    if (peer != -1 && close(peer) == -1) {
        perror("peer close");
        result = EXIT_FAILURE;
    }
    return result;
}
