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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4802>
This commit is contained in:
Jochen Henneberg 2023-06-08 09:35:44 +02:00 committed by GStreamer Marge Bot
parent ebf7966a26
commit df41d11a7d

View file

@ -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;