// Muestra por qué aparece "Address already in use". Atiende a un cliente, cierra
// primero (y por eso la conexión queda en TIME_WAIT de este lado) y termina.
//   reuse_demo [-r] <puerto>      -r activa SO_REUSEADDR
#define _POSIX_C_SOURCE 200809L

#include "io_util.h"

#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    bool reuse = false;
    int opt;
    while ((opt = getopt(argc, argv, "r")) != -1) {
        if (opt != 'r') {
            return EXIT_FAILURE;
        }
        reuse = true;
    }
    if (argc - optind != 1) {
        fprintf(stderr, "uso: %s [-r] <puerto>\n", argv[0]);
        return EXIT_FAILURE;
    }
    int listener = socket(AF_INET, SOCK_STREAM, 0);
    if (listener == -1) {
        perror("socket");
        return EXIT_FAILURE;
    }
    if (reuse) {
        int on = 1;
        if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) == -1) {
            perror("setsockopt");
            return EXIT_FAILURE;
        }
    }
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(parse_port(argv[optind]));
    if (bind(listener, (struct sockaddr *)&addr, sizeof addr) == -1) {
        perror("bind");
        return EXIT_FAILURE;
    }
    if (listen(listener, 1) == -1) {
        perror("listen");
        return EXIT_FAILURE;
    }
    if (print_bound_port(listener) == -1) {
        return EXIT_FAILURE;
    }
    int conn = accept(listener, NULL, NULL);
    if (conn == -1) {
        perror("accept");
        return EXIT_FAILURE;
    }
    if (send_all(conn, "chau\n", 5) == -1) {
        return EXIT_FAILURE;
    }
    close_checked(conn);
    close_checked(listener);
    return EXIT_SUCCESS;
}
