// half_open: deja conexiones a medio abrir. Envía SYN desde una dirección propia y nunca
// termina el handshake, porque en este laboratorio el router descarta los SYN-ACK que
// vuelven a esa dirección. Es la forma de ver una cola de SYN llena sin falsificar nada.
//
//   half_open <ip_propia> <ip_destino> <puerto> <cantidad> <segundos>
#define _POSIX_C_SOURCE 200809L
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>

int main(int argc, char **argv) {
    if (argc != 6) {
        fprintf(stderr, "uso: %s <ip_propia> <ip_destino> <puerto> <cantidad> <segundos>\n", argv[0]);
        return 2;
    }
    struct sockaddr_in local = {.sin_family = AF_INET};
    struct sockaddr_in peer = {.sin_family = AF_INET, .sin_port = htons((uint16_t)atoi(argv[3]))};
    if (inet_pton(AF_INET, argv[1], &local.sin_addr) != 1 ||
        inet_pton(AF_INET, argv[2], &peer.sin_addr) != 1) {
        fprintf(stderr, "dirección inválida\n");
        return 2;
    }
    int count = atoi(argv[4]);
    for (int i = 0; i < count; i++) {
        int fd = socket(AF_INET, SOCK_STREAM, 0);
        if (fd < 0) {
            perror("socket");
            return 1;
        }
        if (bind(fd, (struct sockaddr *)&local, sizeof local) < 0) {
            perror("bind");
            return 1;
        }
        // No bloqueante: connect vuelve de inmediato con EINPROGRESS, y el SYN ya salió.
        int flags = fcntl(fd, F_GETFL);
        if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
            perror("fcntl");
            return 1;
        }
        if (connect(fd, (struct sockaddr *)&peer, sizeof peer) < 0 && errno != EINPROGRESS) {
            perror("connect");
            return 1;
        }
    }
    printf("%d conexiones a medio abrir\n", count);
    if (fflush(stdout) != 0) {
        perror("fflush");
        return 1;
    }
    sleep((unsigned)atoi(argv[5]));
    return 0;
}
