// Servidor UDP de hora: a cada datagrama responde con la hora del servidor.
//   time_server <puerto>
#define _POSIX_C_SOURCE 200809L

#include "io_util.h"

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

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "uso: %s <puerto>\n", argv[0]);
        return EXIT_FAILURE;
    }
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd == -1) {
        perror("socket");
        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[1]));
    if (bind(fd, (struct sockaddr *)&addr, sizeof addr) == -1) {
        perror("bind");
        return EXIT_FAILURE;
    }
    if (print_bound_port(fd) == -1) {
        return EXIT_FAILURE;
    }

    // No hay listen ni accept: un solo socket recibe de todos los clientes.
    for (;;) {
        char request[512];
        struct sockaddr_in peer;
        socklen_t peer_len = sizeof peer;
        ssize_t n = recvfrom(fd, request, sizeof request, 0,
                             (struct sockaddr *)&peer, &peer_len);
        if (n == -1) {
            if (errno != EINTR) {
                perror("recvfrom");
            }
            continue;
        }
        char ip[INET_ADDRSTRLEN];
        if (inet_ntop(AF_INET, &peer.sin_addr, ip, sizeof ip) == NULL) {
            perror("inet_ntop");
            continue;
        }
        printf("datagrama de %zd bytes desde %s:%u\n", n, ip, ntohs(peer.sin_port));
        fflush(stdout);

        time_t now = time(NULL);
        struct tm utc;
        char reply[64];
        if (now == (time_t)-1 || gmtime_r(&now, &utc) == NULL ||
            strftime(reply, sizeof reply, "%H:%M:%S UTC\n", &utc) == 0) {
            fprintf(stderr, "no se pudo obtener la hora\n");
            continue;
        }
        // Cada datagrama lleva su destino: la dirección de quien preguntó.
        if (sendto(fd, reply, strlen(reply), 0,
                   (struct sockaddr *)&peer, peer_len) == -1) {
            perror("sendto");
        }
    }
}
