From 19172140bac454b65a47a10e295c0f72126627e6 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Fri, 7 Apr 2023 21:24:22 +0000 Subject: [PATCH] Add NTP inspired latency tracking and time sync --- include/rfb-proto.h | 9 +++++++++ src/server.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/include/rfb-proto.h b/include/rfb-proto.h index 76983ec..a929260 100644 --- a/include/rfb-proto.h +++ b/include/rfb-proto.h @@ -45,6 +45,7 @@ enum rfb_client_to_server_msg_type { RFB_CLIENT_TO_SERVER_KEY_EVENT = 4, RFB_CLIENT_TO_SERVER_POINTER_EVENT = 5, RFB_CLIENT_TO_SERVER_CLIENT_CUT_TEXT = 6, + RFB_CLIENT_TO_SERVER_NTP = 160, RFB_CLIENT_TO_SERVER_SET_DESKTOP_SIZE = 251, RFB_CLIENT_TO_SERVER_QEMU = 255, }; @@ -67,6 +68,7 @@ enum rfb_encodings { RFB_ENCODING_QEMU_EXT_KEY_EVENT = -258, RFB_ENCODING_EXTENDEDDESKTOPSIZE = -308, RFB_ENCODING_PTS = -1000, + RFB_ENCODING_NTP = -1001, }; #define RFB_ENCODING_JPEG_HIGHQ -23 @@ -77,6 +79,7 @@ enum rfb_server_to_client_msg_type { RFB_SERVER_TO_CLIENT_SET_COLOUR_MAP_ENTRIES = 1, RFB_SERVER_TO_CLIENT_BELL = 2, RFB_SERVER_TO_CLIENT_SERVER_CUT_TEXT = 3, + RFB_SERVER_TO_CLIENT_NTP = 160, }; enum rfb_vencrypt_subtype { @@ -228,3 +231,9 @@ struct rfb_vencrypt_plain_auth_msg { uint32_t password_len; char text[0]; } RFB_PACKED; + +struct rfb_ntp_msg { + uint8_t type; + uint8_t padding[3]; + uint32_t t0, t1, t2, t3; +} RFB_PACKED; diff --git a/src/server.c b/src/server.c index 762d011..703bbf2 100644 --- a/src/server.c +++ b/src/server.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -93,6 +94,13 @@ static uint64_t nvnc__htonll(uint64_t x) #endif } +static uint64_t gettime_us(clockid_t clock) +{ + struct timespec ts = { 0 }; + clock_gettime(clock, &ts); + return ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000ULL; +} + static void client_close(struct nvnc_client* client) { nvnc_log(NVNC_LOG_INFO, "Closing client connection %p: ref %d", client, @@ -512,6 +520,7 @@ static int on_client_set_encodings(struct nvnc_client* client) case RFB_ENCODING_EXTENDEDDESKTOPSIZE: case RFB_ENCODING_QEMU_EXT_KEY_EVENT: case RFB_ENCODING_PTS: + case RFB_ENCODING_NTP: client->encodings[n++] = encoding; } @@ -1034,6 +1043,43 @@ static int on_client_set_desktop_size_event(struct nvnc_client* client) return sizeof(*msg) + msg->number_of_screens * sizeof(struct rfb_screen); } +static void print_ntp_stats(const struct rfb_ntp_msg *msg) +{ +#if 0 + int32_t t0 = ntohl(msg->t0); + int32_t t1 = ntohl(msg->t1); + int32_t t2 = ntohl(msg->t2); + int32_t t3 = ntohl(msg->t3); + + int32_t round_trip_time = (t3 - t0) - (t2 - t1); + int32_t time_difference = ((t1 - t0) + (t2 - t3)) / 2; + + nvnc_log(NVNC_LOG_DEBUG, "NTP: rtt: %.2f ms, time-difference: %.2f ms", + round_trip_time / 1e3, time_difference / 1e3); +#endif +} + +static int on_client_ntp(struct nvnc_client* client) +{ + struct rfb_ntp_msg msg; + + if (client->buffer_len - client->buffer_index < sizeof(msg)) + return 0; + + memcpy(&msg, client->msg_buffer + client->buffer_index, sizeof(msg)); + + if (msg.t3 != 0) { + print_ntp_stats(&msg); + return sizeof(msg); + } + + msg.t1 = htonl(gettime_us(CLOCK_MONOTONIC)); + msg.t2 = msg.t1; // TODO: Update this when the message is dequeued. + + stream_write(client->net_stream, &msg, sizeof(msg), NULL, NULL); + return sizeof(msg); +} + static int on_client_message(struct nvnc_client* client) { if (client->buffer_len - client->buffer_index < 1) @@ -1059,6 +1105,8 @@ static int on_client_message(struct nvnc_client* client) return on_client_qemu_event(client); case RFB_CLIENT_TO_SERVER_SET_DESKTOP_SIZE: return on_client_set_desktop_size_event(client); + case RFB_CLIENT_TO_SERVER_NTP: + return on_client_ntp(client); } nvnc_log(NVNC_LOG_WARNING, "Got uninterpretable message from client: %p (ref %d)",