From df41d11a7d7f844e593a10f6a6a0858333fbf7ec Mon Sep 17 00:00:00 2001 From: Jochen Henneberg Date: Thu, 8 Jun 2023 09:35:44 +0200 Subject: [PATCH] netclientclock: Handle time server reset correctly If the time server is restarted with a time in the past the net client clock will not report the new time anymore as this would mean that the clock moves back in time which it does not do. Now the clock will be kept alive but marked as corrupted and will not be re-used from the cache. Part-of: --- .../libs/gst/net/gstnetclientclock.c | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/subprojects/gstreamer/libs/gst/net/gstnetclientclock.c b/subprojects/gstreamer/libs/gst/net/gstnetclientclock.c index 6c55f0a5cc..54f6de7eb1 100644 --- a/subprojects/gstreamer/libs/gst/net/gstnetclientclock.c +++ b/subprojects/gstreamer/libs/gst/net/gstnetclientclock.c @@ -137,12 +137,14 @@ struct _GstNetClientInternalClock GSocketAddress *servaddr; GCancellable *cancel; gboolean made_cancel_fd; + gboolean marked_corrupted; GstClockTime timeout_expiration; GstClockTime roundtrip_limit; GstClockTime rtt_avg; GstClockTime minimum_update_interval; GstClockTime last_remote_poll_interval; + GstClockTime last_remote_time; GstClockTime remote_avg_old; guint skipped_updates; GstClockTime last_rtts[MEDIAN_PRE_FILTERING_WINDOW]; @@ -230,6 +232,7 @@ gst_net_client_internal_clock_init (GstNetClientInternalClock * self) self->last_remote_poll_interval = GST_CLOCK_TIME_NONE; self->skipped_updates = 0; self->last_rtts_missing = MEDIAN_PRE_FILTERING_WINDOW; + self->marked_corrupted = FALSE; self->remote_avg_old = 0; } @@ -374,6 +377,11 @@ gst_net_client_internal_clock_observe_times (GstNetClientInternalClock * self, G_GUINT64_FORMAT " local2 %" G_GUINT64_FORMAT, local_1, remote_1, remote_2, local_2); + /* if we are ahead of time the time server may have been reset */ + if (self->last_remote_time > remote_1 || self->marked_corrupted) + goto corrupted; + self->last_remote_time = remote_1; + /* If the server told us a poll interval and it's bigger than the * one configured via the property, use the server's */ if (self->last_remote_poll_interval != GST_CLOCK_TIME_NONE && @@ -649,6 +657,14 @@ bogus_observation: /* Schedule a new packet again soon */ self->timeout_expiration = gst_util_get_timestamp () + (GST_SECOND / 4); return; + +corrupted: + if (!self->marked_corrupted) { + GST_ERROR_OBJECT (self, "Remote clock time reverted, mark clock invalid"); + self->marked_corrupted = TRUE; + } + GST_OBJECT_UNLOCK (self); + return; } static gpointer @@ -1196,7 +1212,13 @@ gst_net_client_clock_finalize (GObject * object) update_clock_cache (cache); } else { GstClock *sysclock = gst_system_clock_obtain (); - GstClockTime time = gst_clock_get_time (sysclock) + 60 * GST_SECOND; + GstClockTime time = gst_clock_get_time (sysclock); + GstNetClientInternalClock *internal_clock = + GST_NET_CLIENT_INTERNAL_CLOCK (cache->clock); + + /* only defer deletion if the clock is not marked corrupted */ + if (!internal_clock->marked_corrupted) + time += 60 * GST_SECOND; cache->remove_id = gst_clock_new_single_shot_id (sysclock, time); gst_clock_id_wait_async (cache->remove_id, remove_clock_cache, cache, @@ -1365,6 +1387,9 @@ gst_net_client_clock_constructed (GObject * object) GstNetClientInternalClock *internal_clock = GST_NET_CLIENT_INTERNAL_CLOCK (tmp->clock); + if (internal_clock->marked_corrupted) + break; + if (strcmp (internal_clock->address, self->priv->address) == 0 && internal_clock->port == self->priv->port) { cache = tmp;