// Recibe de un cliente y cuenta cuánto devuelve cada recv.
//   chunk_recv [-v] [-x tamaño] <puerto>
//     -v          imprime lo que devuelve cada llamada
//     -x tamaño   usa recv_all para leer registros de tamaño fijo
#define _POSIX_C_SOURCE 200809L

#include "io_util.h"

#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>

#define BUF_SIZE (1024 * 1024)

int main(int argc, char *argv[]) {
    bool verbose = false;
    long exact = 0;
    int opt;
    while ((opt = getopt(argc, argv, "vx:")) != -1) {
        if (opt == 'v') {
            verbose = true;
        } else if (opt == 'x') {
            exact = strtol(optarg, NULL, 10);
        } else {
            return EXIT_FAILURE;
        }
    }
    if (argc - optind != 1 || exact < 0 || exact > BUF_SIZE) {
        fprintf(stderr, "uso: %s [-v] [-x tamaño] <puerto>\n", argv[0]);
        return EXIT_FAILURE;
    }

    int listener = tcp_listen(parse_port(argv[optind]));
    if (listener == -1 || print_bound_port(listener) == -1) {
        return EXIT_FAILURE;
    }
    int conn = accept(listener, NULL, NULL);
    if (conn == -1) {
        perror("accept");
        return EXIT_FAILURE;
    }
    char *buf = malloc(BUF_SIZE);
    if (buf == NULL) {
        perror("malloc");
        return EXIT_FAILURE;
    }

    unsigned long long total = 0;
    unsigned long long bad = 0;
    long calls = 0;
    long smallest = 0;
    long largest = 0;
    for (;;) {
        ssize_t n = exact > 0 ? recv_all(conn, buf, (size_t)exact)
                              : recv(conn, buf, BUF_SIZE, 0);
        if (n == -1) {
            if (errno == EINTR) {
                continue;
            }
            perror("recv");
            return EXIT_FAILURE;
        }
        if (n == 0) {
            break;
        }
        calls++;
        if (calls == 1 || n < smallest) {
            smallest = n;
        }
        if (n > largest) {
            largest = n;
        }
        for (ssize_t i = 0; i < n; i++) {
            if ((unsigned char)buf[i] != (total + (unsigned long long)i) % 251) {
                bad++;
            }
        }
        total += (unsigned long long)n;
        if (verbose) {
            printf("%s %ld: %zd bytes\n", exact > 0 ? "registro" : "recv", calls, n);
        }
    }
    printf("%s: %ld llamadas, %llu bytes, menor %ld, mayor %ld\n",
           exact > 0 ? "recv_all" : "recv", calls, total, smallest, largest);
    printf("bytes fuera de lugar: %llu\n", bad);
    free(buf);
    close_checked(conn);
    close_checked(listener);
    return EXIT_SUCCESS;
}
