#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>

#define NTP_TIMESTAMP_DELTA 2208988800ull
#define NTP_PORT 123

typedef struct {
    uint8_t li_vn_mode;
    uint8_t stratum;
    uint8_t poll;
    int8_t precision;

    uint32_t rootDelay;
    uint32_t rootDispersion;
    uint32_t refId;

    uint32_t refTm_s;
    uint32_t refTm_f;
    uint32_t origTm_s;
    uint32_t origTm_f;
    uint32_t rxTm_s;
    uint32_t rxTm_f;
    uint32_t txTm_s;
    uint32_t txTm_f;
} ntp_packet;

void set_ntp_mode(ntp_packet *packet, int version, int mode) {
    packet->li_vn_mode = (0 << 6) | ((version & 0x7) << 3) | (mode & 0x7);
}

void set_transmit_time(ntp_packet *packet) {
    struct timeval tv;
    gettimeofday(&tv, NULL);

    uint32_t seconds = tv.tv_sec + NTP_TIMESTAMP_DELTA;
    uint32_t fraction = (uint32_t)((double)tv.tv_usec * (1LL << 32) * 1.0e-6);

    packet->txTm_s = htonl(seconds);
    packet->txTm_f = htonl(fraction);
}

void send_ntp_packet(const char *ip, int mode) {
    int sockfd;
    struct sockaddr_in addr;
    ntp_packet packet;

    memset(&packet, 0, sizeof(ntp_packet));

    set_ntp_mode(&packet, 4, mode);
    packet.stratum = 1;
    packet.poll = 4;
    packet.precision = -20;
    set_transmit_time(&packet);

    sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sockfd < 0) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(NTP_PORT);
    addr.sin_addr.s_addr = inet_addr(ip);

    if (sendto(sockfd, (char *)&packet, sizeof(packet), 0,
               (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("sendto failed");
    } else {
        printf("NTP packet sent (mode %d) to %s\n", mode, ip);
    }

    close(sockfd);
}

int main() {
    const char *peer_ip = "192.168.1.100"; // Replace with actual peer IP

    // Send Symmetric Active packet
    send_ntp_packet(peer_ip, 1);

    // Simulate receiving and responding with Symmetric Passive packet
    sleep(1); // simulate processing time
    send_ntp_packet(peer_ip, 2);

    return 0;
}

