rtsp-session: Use monotonic time for RTSP session timeout
authorKent-Inge Ingesson <kenti@axis.com>
Thu, 19 Feb 2015 08:43:16 +0000 (10:43 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Thu, 19 Feb 2015 08:43:30 +0000 (10:43 +0200)
Changed RTSP session timeout handling to monotonic time
and deprecating the API for current system time.

This fixes timeouts when the system time changes.

https://bugzilla.gnome.org/show_bug.cgi?id=743346

gst/rtsp-server/rtsp-session-pool.c
gst/rtsp-server/rtsp-session.c
gst/rtsp-server/rtsp-session.h

index 772390f..ea1ff18 100644 (file)
@@ -470,7 +470,7 @@ gst_rtsp_session_pool_remove (GstRTSPSessionPool * pool, GstRTSPSession * sess)
 
 typedef struct
 {
-  GTimeVal now;
+  gint64 now_monotonic_time;
   GstRTSPSessionPool *pool;
   GList *removed;
 } CleanupData;
@@ -480,11 +480,13 @@ cleanup_func (gchar * sessionid, GstRTSPSession * sess, CleanupData * data)
 {
   gboolean expired;
 
-  expired = gst_rtsp_session_is_expired (sess, &data->now);
+  expired = gst_rtsp_session_is_expired_usec (sess, data->now_monotonic_time);
+
   if (expired) {
     GST_DEBUG ("session expired");
     data->removed = g_list_prepend (data->removed, g_object_ref (sess));
   }
+
   return expired;
 }
 
@@ -509,7 +511,8 @@ gst_rtsp_session_pool_cleanup (GstRTSPSessionPool * pool)
 
   priv = pool->priv;
 
-  g_get_current_time (&data.now);
+  data.now_monotonic_time = g_get_monotonic_time ();
+
   data.pool = pool;
   data.removed = NULL;
 
@@ -661,11 +664,12 @@ static void
 collect_timeout (gchar * sessionid, GstRTSPSession * sess, GstPoolSource * psrc)
 {
   gint timeout;
-  GTimeVal now;
+  gint64 now_monotonic_time;
+
+  now_monotonic_time = g_get_monotonic_time ();
 
-  g_get_current_time (&now);
+  timeout = gst_rtsp_session_next_timeout_usec (sess, now_monotonic_time);
 
-  timeout = gst_rtsp_session_next_timeout (sess, &now);
   GST_INFO ("%p: next timeout: %d", sess, timeout);
   if (psrc->timeout == -1 || timeout < psrc->timeout)
     psrc->timeout = timeout;
index 1f4b650..052537e 100644 (file)
@@ -57,9 +57,9 @@ struct _GstRTSPSessionPrivate
 
   guint timeout;
   gboolean timeout_always_visible;
-  GTimeVal create_time;         /* immutable */
   GMutex last_access_lock;
-  GTimeVal last_access;
+  gint64 last_access_monotonic_time;
+  gint64 last_access_real_time;
   gint expire_count;
 
   GList *medias;
@@ -135,7 +135,7 @@ gst_rtsp_session_init (GstRTSPSession * session)
   g_mutex_init (&priv->lock);
   g_mutex_init (&priv->last_access_lock);
   priv->timeout = DEFAULT_TIMEOUT;
-  g_get_current_time (&priv->create_time);
+
   gst_rtsp_session_touch (session);
 }
 
@@ -559,7 +559,8 @@ gst_rtsp_session_touch (GstRTSPSession * session)
   priv = session->priv;
 
   g_mutex_lock (&priv->last_access_lock);
-  g_get_current_time (&priv->last_access);
+  priv->last_access_monotonic_time = g_get_monotonic_time ();
+  priv->last_access_real_time = g_get_real_time ();
   g_mutex_unlock (&priv->last_access_lock);
 }
 
@@ -591,6 +592,52 @@ gst_rtsp_session_allow_expire (GstRTSPSession * session)
 }
 
 /**
+ * gst_rtsp_session_next_timeout_usec:
+ * @session: a #GstRTSPSession
+ * @now: (transfer none): the current monotonic time
+ *
+ * Get the amount of milliseconds till the session will expire.
+ *
+ * Returns: the amount of milliseconds since the session will time out.
+ */
+gint
+gst_rtsp_session_next_timeout_usec (GstRTSPSession * session, gint64 now)
+{
+  GstRTSPSessionPrivate *priv;
+  gint res;
+  GstClockTime last_access, now_ns;
+
+  g_return_val_if_fail (GST_IS_RTSP_SESSION (session), -1);
+
+  priv = session->priv;
+
+  g_mutex_lock (&priv->last_access_lock);
+  if (g_atomic_int_get (&priv->expire_count) != 0) {
+    /* touch session when the expire count is not 0 */
+    priv->last_access_monotonic_time = g_get_monotonic_time ();
+    priv->last_access_real_time = g_get_real_time ();
+  }
+
+  last_access = GST_USECOND * (priv->last_access_monotonic_time);
+
+  /* add timeout allow for 5 seconds of extra time */
+  last_access += priv->timeout * GST_SECOND + (5 * GST_SECOND);
+  g_mutex_unlock (&priv->last_access_lock);
+
+  now_ns = GST_USECOND * now;
+
+  if (last_access > now_ns) {
+    res = GST_TIME_AS_MSECONDS (last_access - now_ns);
+  } else {
+    res = 0;
+  }
+
+  return res;
+}
+
+/****** Deprecated API *******/
+
+/**
  * gst_rtsp_session_next_timeout:
  * @session: a #GstRTSPSession
  * @now: (transfer none): the current system time
@@ -598,7 +645,11 @@ gst_rtsp_session_allow_expire (GstRTSPSession * session)
  * Get the amount of milliseconds till the session will expire.
  *
  * Returns: the amount of milliseconds since the session will time out.
+ *
+ * Deprecated: Use gst_rtsp_session_next_timeout_usec() instead.
  */
+#ifndef GST_REMOVE_DEPRECATED
+#ifndef GST_DISABLE_DEPRECATED
 gint
 gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now)
 {
@@ -614,23 +665,50 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now)
   g_mutex_lock (&priv->last_access_lock);
   if (g_atomic_int_get (&priv->expire_count) != 0) {
     /* touch session when the expire count is not 0 */
-    g_get_current_time (&priv->last_access);
+    priv->last_access_monotonic_time = g_get_monotonic_time ();
+    priv->last_access_real_time = g_get_real_time ();
   }
 
-  last_access = GST_TIMEVAL_TO_TIME (priv->last_access);
+  last_access = GST_USECOND * (priv->last_access_real_time);
+
   /* add timeout allow for 5 seconds of extra time */
   last_access += priv->timeout * GST_SECOND + (5 * GST_SECOND);
   g_mutex_unlock (&priv->last_access_lock);
 
   now_ns = GST_TIMEVAL_TO_TIME (*now);
 
-  if (last_access > now_ns)
+  if (last_access > now_ns) {
     res = GST_TIME_AS_MSECONDS (last_access - now_ns);
-  else
+  } else {
     res = 0;
+  }
 
   return res;
 }
+#endif
+#endif
+
+/**
+ * gst_rtsp_session_is_expired_usec:
+ * @session: a #GstRTSPSession
+ * @now: (transfer none): the current monotonic time
+ *
+ * Check if @session timeout out.
+ *
+ * Returns: %TRUE if @session timed out
+ */
+gboolean
+gst_rtsp_session_is_expired_usec (GstRTSPSession * session, gint64 now)
+{
+  gboolean res;
+
+  res = (gst_rtsp_session_next_timeout_usec (session, now) == 0);
+
+  return res;
+}
+
+
+/****** Deprecated API *******/
 
 /**
  * gst_rtsp_session_is_expired:
@@ -640,7 +718,11 @@ gst_rtsp_session_next_timeout (GstRTSPSession * session, GTimeVal * now)
  * Check if @session timeout out.
  *
  * Returns: %TRUE if @session timed out
+ *
+ * Deprecated: Use gst_rtsp_session_is_expired_usec() instead.
  */
+#ifndef GST_REMOVE_DEPRECATED
+#ifndef GST_DISABLE_DEPRECATED
 gboolean
 gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now)
 {
@@ -650,3 +732,5 @@ gst_rtsp_session_is_expired (GstRTSPSession * session, GTimeVal * now)
 
   return res;
 }
+#endif
+#endif
index d9c0f18..8bd6ca9 100644 (file)
@@ -95,8 +95,12 @@ guint                  gst_rtsp_session_get_timeout          (GstRTSPSession *se
 void                   gst_rtsp_session_touch                (GstRTSPSession *session);
 void                   gst_rtsp_session_prevent_expire       (GstRTSPSession *session);
 void                   gst_rtsp_session_allow_expire         (GstRTSPSession *session);
+gint                   gst_rtsp_session_next_timeout_usec    (GstRTSPSession *session, gint64 now);
+gboolean               gst_rtsp_session_is_expired_usec      (GstRTSPSession *session, gint64 now);
+#ifndef GST_DISABLE_DEPRECATED
 gint                   gst_rtsp_session_next_timeout         (GstRTSPSession *session, GTimeVal *now);
 gboolean               gst_rtsp_session_is_expired           (GstRTSPSession *session, GTimeVal *now);
+#endif
 
 /* handle media in a session */
 GstRTSPSessionMedia *  gst_rtsp_session_manage_media         (GstRTSPSession *sess,