Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
218 changes: 191 additions & 27 deletions 02-ntp/ntp-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,22 @@ void demonstrate_epoch_conversion(void) {
* Use demonstrate_epoch_conversion() to verify your conversion logic
*/
void get_current_ntp_time(ntp_timestamp_t *ntp_ts){
struct timeval tv;
struct timezone tz;
struct tm *today;

printf("get_current_ntp_time() - TO BE IMPLEMENTED\n");
gettimeofday(&tv, &tz);
today = localtime(&tv.tv_sec);
uint64_t seconds = tv.tv_sec + NTP_EPOCH_OFFSET;
uint64_t fraction = (uint64_t)tv.tv_usec * NTP_FRACTION_SCALE / USEC_INCREMENTS;

ntp_ts->seconds = (uint32_t)seconds;
ntp_ts->fraction = (uint32_t)fraction;
// DONE
// TODO: Implement this function
// Hint: Use gettimeofday(), convert epoch, scale microseconds
memset(ntp_ts, 0, sizeof(ntp_timestamp_t));
// memset(ntp_ts, 0, sizeof(ntp_timestamp_t));
}

//STUDENT TODO
Expand Down Expand Up @@ -366,11 +378,27 @@ void get_current_ntp_time(ntp_timestamp_t *ntp_ts){
* ERROR HANDLING:
* If conversion fails, use snprintf to write "INVALID_TIME" to buffer
*/


void ntp_time_to_string(const ntp_timestamp_t *ntp_ts, char *buffer, size_t buffer_size, int local) {
printf("ntp_time_to_string() - TO BE IMPLEMENTED\n");
// printf("ntp_time_to_string() - TO BE IMPLEMENTED\n");
// TODO: Implement this function
// Hint: Convert NTP to Unix time, use localtime/gmtime, format with snprintf
snprintf(buffer, buffer_size, "TO BE IMPLEMENTED");
time_t unix_time = (time_t)NTP_TO_UNIX_SECONDS(ntp_ts->seconds);
struct tm *tm_info;

if (local == LOCAL_TIME)
tm_info = localtime(&unix_time);
else
tm_info = gmtime(&unix_time);

snprintf(buffer, buffer_size,
"%04d-%02d-%02d %02d:%02d:%02d",
tm_info->tm_year + 1900,
tm_info->tm_mon + 1,
tm_info->tm_mday,
tm_info->tm_hour,
tm_info->tm_min,
tm_info->tm_sec);
}

//STUDENT TODO
Expand All @@ -397,10 +425,8 @@ void ntp_time_to_string(const ntp_timestamp_t *ntp_ts, char *buffer, size_t buff
* Use NTP_FRACTION_SCALE (2^32) constant for the division
*/
double ntp_time_to_double(const ntp_timestamp_t* timestamp) {
printf("ntp_time_to_double() - TO BE IMPLEMENTED\n");
// TODO: Implement this function
// Hint: Convert both parts to double and add
return 0.0;
return (double)timestamp->seconds +
((double)timestamp->fraction / NTP_FRACTION_SCALE);
}

//STUDENT TODO
Expand All @@ -419,9 +445,12 @@ double ntp_time_to_double(const ntp_timestamp_t* timestamp) {
* Output: "Transmit Time: 2025-09-15 13:36:14.541216 (Local Time)"
*/
void print_ntp_time(const ntp_timestamp_t *ts, const char* label, int local){
printf("print_ntp_time() - TO BE IMPLEMENTED - %s\n", label);
// printf("print_ntp_time() - TO BE IMPLEMENTED - %s\n", label);
// TODO: Implement this function
// Hint: Use ntp_time_to_string and printf
char buff[TIME_BUFF_SIZE];
ntp_time_to_string(ts, buff, sizeof(buff), local);
printf("%s: %s\n", label, buff);
}

/*
Expand Down Expand Up @@ -449,9 +478,11 @@ void print_ntp_time(const ntp_timestamp_t *ts, const char* label, int local){
* Network protocols require consistent byte order across different architectures
*/
void ntp_ts_to_net(ntp_timestamp_t* timestamp){
printf("ntp_ts_to_net() - TO BE IMPLEMENTED\n");
//printf("ntp_ts_to_net() - TO BE IMPLEMENTED\n");
// TODO: Implement this function
// Hint: Use htonl() on both seconds and fraction fields
timestamp->seconds = htonl(timestamp->seconds);
timestamp->fraction = htonl(timestamp->fraction);
}

//STUDENT TODO
Expand All @@ -473,9 +504,10 @@ void ntp_ts_to_net(ntp_timestamp_t* timestamp){
* Host processing requires native byte order for correct arithmetic
*/
void ntp_ts_to_host(ntp_timestamp_t* timestamp){
printf("ntp_ts_to_host() - TO BE IMPLEMENTED\n");
// TODO: Implement this function
// Hint: Use ntohl() on both seconds and fraction fields
timestamp->seconds = ntohl(timestamp->seconds);
timestamp->fraction = ntohl(timestamp->fraction);
}

//STUDENT TODO
Expand All @@ -498,9 +530,17 @@ void ntp_ts_to_host(ntp_timestamp_t* timestamp){
* CALL THIS: Before sending packet over network
*/
void ntp_to_net(ntp_packet_t* packet){
printf("ntp_to_net() - TO BE IMPLEMENTED\n");
//printf("ntp_to_net() - TO BE IMPLEMENTED\n");
// TODO: Implement this function
// Hint: Convert 32-bit fields with htonl(), timestamps with ntp_ts_to_net()
packet->root_delay = htonl(packet->root_delay);
packet->root_dispersion = htonl(packet->root_dispersion);
packet->reference_id = htonl(packet->reference_id);

ntp_ts_to_net(&packet->ref_time);
ntp_ts_to_net(&packet->orig_time);
ntp_ts_to_net(&packet->recv_time);
ntp_ts_to_net(&packet->xmit_time);
}

//STUDENT TODO
Expand All @@ -522,9 +562,16 @@ void ntp_to_net(ntp_packet_t* packet){
* CALL THIS: After receiving packet from network
*/
void ntp_to_host(ntp_packet_t* packet){
printf("ntp_to_host() - TO BE IMPLEMENTED\n");
// TODO: Implement this function
// Hint: Convert 32-bit fields with ntohl(), timestamps with ntp_ts_to_host()
packet->root_delay = ntohl(packet->root_delay);
packet->root_dispersion = ntohl(packet->root_dispersion);
packet->reference_id = ntohl(packet->reference_id);

ntp_ts_to_host(&packet->ref_time);
ntp_ts_to_host(&packet->orig_time);
ntp_ts_to_host(&packet->recv_time);
ntp_ts_to_host(&packet->xmit_time);
}

/*
Expand Down Expand Up @@ -575,9 +622,18 @@ int build_ntp_request(ntp_packet_t* packet) {
return RC_BAD_PACKET;
}
memset(packet, 0, sizeof(ntp_packet_t));

SET_NTP_LI_VN_MODE(packet,
NTP_LI_UNSYNC,
NTP_VERSION,
NTP_MODE_CLIENT);

packet->stratum = 0;
packet->poll = 6;
packet->precision = -20;

get_current_ntp_time(&packet->xmit_time);
// After you implement this, uncomment the line below to debug:
// debug_print_bit_fields(packet);
debug_print_bit_fields(packet);

return RC_OK;
}
Expand Down Expand Up @@ -622,10 +678,28 @@ int build_ntp_request(ntp_packet_t* packet) {
* RC_OK (0) on success, RC_BUFF_TOO_SMALL (-2) if buffer too small
*/
int decode_reference_id(uint8_t stratum, uint32_t ref_id, char *buff, int buff_sz){
printf("decode_reference_id() - TO BE IMPLEMENTED\n");
// TODO: Implement this function
// Hint: Check buffer sizes, handle ref_id==0, stratum>=2 (IP), stratum<2 (ASCII)
snprintf(buff, buff_sz, "TO BE IMPLEMENTED");
if (!buff || buff_sz < 5)
return RC_BUFF_TOO_SMALL;

if (ref_id == 0) {
snprintf(buff, buff_sz, "NONE");
return RC_OK;
}

if (stratum < 2) {
char c[5];
c[0] = (ref_id >> 24) & 0xFF;
c[1] = (ref_id >> 16) & 0xFF;
c[2] = (ref_id >> 8) & 0xFF;
c[3] = ref_id & 0xFF;
c[4] = '\0';
snprintf(buff, buff_sz, "%s", c);
} else {
struct in_addr addr;
addr.s_addr = htonl(ref_id);
inet_ntop(AF_INET, &addr, buff, buff_sz);
}

return RC_OK;
}

Expand Down Expand Up @@ -703,18 +777,34 @@ int calculate_ntp_offset(const ntp_packet_t* request,
printf("calculate_ntp_offset() - TO BE IMPLEMENTED\n");
// TODO: Implement this function
// Hint: Extract T1-T4 timestamps, apply NTP formulas, calculate dispersion
if (!request || !response || !result) {
return -1;
if (!request || !response || !result || !recv_time) {
return RC_BAD_PACKET;
}

// Initialize result with dummy values
result->delay = 0.0;
result->offset = 0.0;
result->final_dispersion = 0.0;
memset(&result->server_time, 0, sizeof(ntp_timestamp_t));
memset(&result->client_time, 0, sizeof(ntp_timestamp_t));

return 0;

double T1 = ntp_time_to_double(&request->xmit_time);
double T2 = ntp_time_to_double(&response->recv_time);
double T3 = ntp_time_to_double(&response->xmit_time);
double T4 = ntp_time_to_double(recv_time);

result->delay = (T4 - T1) - (T3 - T2);
result->offset = ((T2 - T1) + (T3 - T4)) / 2.0;

result->server_time = response->xmit_time;
result->client_time = *recv_time;

result->final_dispersion =
GET_NTP_Q1616_TS(response->root_dispersion) +
(GET_NTP_Q1616_TS(response->root_delay) / 2.0) +
(result->delay / 2.0);

return RC_OK;
}

/*
Expand Down Expand Up @@ -758,9 +848,51 @@ int calculate_ntp_offset(const ntp_packet_t* request,
* Transmit Time (T3): 2025-09-15 09:09:34.348244 (Local Time)
*/
void print_ntp_packet_info(const ntp_packet_t* packet, const char* label, int packet_type) {
printf("print_ntp_packet_info() - TO BE IMPLEMENTED - %s Packet\n", label);
//printf("print_ntp_packet_info() - TO BE IMPLEMENTED - %s Packet\n", label);
// TODO: Implement this function
// Hint: Use printf for fields, GET_NTP_* macros for bit fields, decode_reference_id, print_ntp_time
char refid_buff[64];

printf("--- %s Packet ---\n", label);

printf("Leap Indicator: %d\n", GET_NTP_LI(packet));
printf("Version: %d\n", GET_NTP_VN(packet));
printf("Mode: %d\n", GET_NTP_MODE(packet));

printf("Stratum: %d\n", packet->stratum);
printf("Poll: %d\n", packet->poll);
printf("Precision: %d\n", packet->precision);

decode_reference_id(packet->stratum,
packet->reference_id,
refid_buff,
sizeof(refid_buff));

printf("Reference ID: [0x%08x] %s\n",
packet->reference_id,
refid_buff);

printf("Root Delay: %u\n",
GET_NTP_Q1616_SEC(packet->root_delay));

printf("Root Dispersion %u\n",
GET_NTP_Q1616_SEC(packet->root_dispersion));

print_ntp_time(&packet->ref_time,
"Reference Time",
LOCAL_TIME);

print_ntp_time(&packet->orig_time,
"Original Time (T1)",
LOCAL_TIME);

print_ntp_time(&packet->recv_time,
"Receive Time (T2)",
LOCAL_TIME);

print_ntp_time(&packet->xmit_time,
"Transmit Time (T3)",
LOCAL_TIME);
}

//STUDENT TODO
Expand Down Expand Up @@ -792,7 +924,39 @@ void print_ntp_results(const ntp_result_t* result) {
char svr_time_buff[TIME_BUFF_SIZE];
char cli_time_buff[TIME_BUFF_SIZE];

printf("print_ntp_results() - TO BE IMPLEMENTED\n");
//printf("print_ntp_results() - TO BE IMPLEMENTED\n");
//Hint: Note that you really dont have to do much here other than
// Print out data that is passed in teh result arguement
}
ntp_time_to_string(&result->server_time,
svr_time_buff,
sizeof(svr_time_buff),
LOCAL_TIME);

ntp_time_to_string(&result->client_time,
cli_time_buff,
sizeof(cli_time_buff),
LOCAL_TIME);

printf("\n=== NTP Time Synchronization Results ===\n");

printf("Server: pool.ntp.org\n");

printf("Server Time: %s (local time)\n", svr_time_buff);
printf("Local Time: %s (local time)\n", cli_time_buff);

printf("Round Trip Delay: %.6f\n\n", result->delay);

printf("Time Offset: %.6f seconds\n", result->offset);
printf("Final dispersion %.6f\n\n", result->final_dispersion);

double offset_ms = fabs(result->offset * 1000.0);
double disp_ms = result->final_dispersion * 1000.0;

if (result->offset > 0) {
printf("Your clock is running BEHIND by %.2fms\n", offset_ms);
} else {
printf("Your clock is running AHEAD by %.2fms\n", offset_ms);
}

printf("Your estimated time error will be +/- %.2fms\n", disp_ms);
}
Loading