Merged in get-keepalive-interval (pull request #472)

Fri, 29 Mar 2019 01:15:18 +0000

author
Gary Kramlich <grim@reaperworld.com>
date
Fri, 29 Mar 2019 01:15:18 +0000
changeset 39521
f4d92381a032
parent 39516
e3a0ba959194 (current diff)
parent 39520
7f9952eeb6a7 (diff)
child 39522
696fe0c9677f
child 39523
415b0705e48b
child 39532
04b8df1f20c3

Merged in get-keepalive-interval (pull request #472)

Make the keepalive interval configurable

Approved-by: Elliott Sales de Andrade
Approved-by: Gary Kramlich
Approved-by: Eion Robb

libpurple/protocol.h file | annotate | diff | comparison | revisions
libpurple/protocols/jabber/jabber.c file | annotate | diff | comparison | revisions
libpurple/util.c file | annotate | diff | comparison | revisions
libpurple/util.h file | annotate | diff | comparison | revisions
--- a/libpurple/connection.c	Fri Mar 22 03:36:29 2019 +0000
+++ b/libpurple/connection.c	Fri Mar 29 01:15:18 2019 +0000
@@ -40,8 +40,6 @@
 
 G_DEFINE_QUARK(purple-connection-error-quark, purple_connection_error);
 
-#define KEEPALIVE_INTERVAL 30
-
 typedef struct _PurpleConnectionPrivate  PurpleConnectionPrivate;
 
 /* Private data for a connection */
@@ -62,7 +60,7 @@
 	void *proto_data;             /* Protocol-specific data.           */
 
 	char *display_name;           /* How you appear to other people.   */
-	guint keepalive;              /* Keep-alive.                       */
+	GSource *keepalive;           /* Keep-alive.                       */
 
 	/* Wants to Die state.  This is set when the user chooses to log out, or
 	 * when the protocol is disconnected and should not be automatically
@@ -79,8 +77,6 @@
 	PurpleConnectionErrorInfo *error_info;
 
 	guint disconnect_timeout;  /* Timer used for nasty stack tricks         */
-	time_t last_received;      /* When we last received a packet. Set by the
-	                              protocols to avoid sending unneeded keepalives */
 };
 
 /* GObject property enums */
@@ -119,12 +115,6 @@
 	PurpleConnection *gc = data;
 	PurpleConnectionPrivate *priv = purple_connection_get_instance_private(gc);
 
-	/* Only send keep-alives if we haven't heard from the
-	 * server in a while.
-	 */
-	if ((time(NULL) - priv->last_received) < KEEPALIVE_INTERVAL)
-		return TRUE;
-
 	purple_protocol_server_iface_keepalive(priv->protocol, gc);
 
 	return TRUE;
@@ -142,14 +132,15 @@
 
 	if (on && !priv->keepalive)
 	{
-		purple_debug_info("connection", "Activating keepalive.\n");
-		priv->keepalive = g_timeout_add_seconds(KEEPALIVE_INTERVAL, send_keepalive, gc);
+		int interval = purple_protocol_server_iface_get_keepalive_interval(priv->protocol);
+		purple_debug_info("connection", "Activating keepalive to %d seconds.", interval);
+		priv->keepalive = g_main_context_find_source_by_id(NULL, g_timeout_add_seconds(interval, send_keepalive, gc));
 	}
-	else if (!on && priv->keepalive > 0)
+	else if (!on && priv->keepalive)
 	{
 		purple_debug_info("connection", "Deactivating keepalive.\n");
-		g_source_remove(priv->keepalive);
-		priv->keepalive = 0;
+		g_source_destroy(priv->keepalive);
+		priv->keepalive = NULL;
 	}
 }
 
@@ -625,7 +616,13 @@
 
 	g_return_if_fail(priv != NULL);
 
-	priv->last_received = time(NULL);
+	/*
+	 * For safety, actually this function shouldn't be called when the
+	 * keepalive mechanism is inactive.
+	 */
+	if (priv->keepalive) {
+		purple_timeout_reset(priv->keepalive, purple_protocol_server_iface_get_keepalive_interval(priv->protocol));
+	}
 }
 
 static PurpleConnectionErrorInfo *
--- a/libpurple/protocol.c	Fri Mar 22 03:36:29 2019 +0000
+++ b/libpurple/protocol.c	Fri Mar 29 01:15:18 2019 +0000
@@ -500,6 +500,12 @@
 	DEFINE_PROTOCOL_FUNC(protocol, keepalive, gc);
 }
 
+int
+purple_protocol_server_iface_get_keepalive_interval(PurpleProtocol *protocol)
+{
+	DEFINE_PROTOCOL_FUNC_WITH_RETURN(protocol, 30, get_keepalive_interval);
+}
+
 void
 purple_protocol_server_iface_alias_buddy(PurpleProtocol *protocol,
 		PurpleConnection *gc, const char *who, const char *alias)
--- a/libpurple/protocol.h	Fri Mar 22 03:36:29 2019 +0000
+++ b/libpurple/protocol.h	Fri Mar 29 01:15:18 2019 +0000
@@ -271,8 +271,11 @@
  *                   protocol's active connections. You'd want to do this if you
  *                   need to repeatedly send some kind of keepalive packet to
  *                   the server to avoid being disconnected. ("Regularly" is
- *                   defined by <literal>KEEPALIVE_INTERVAL</literal> in
+ *                   defined to be 30 unless get_keepalive_interval() is
+ *                   implemented to override it).
  *                   <filename>libpurple/connection.c</filename>.)
+ * @get_keepalive_interval: If implemented, this will override the default
+ *                          keepalive interval.
  * @alias_buddy:     Save/store buddy's alias on server list/roster
  * @group_buddy:     Change a buddy's group on a server list/roster
  * @rename_group:    Rename a group on a server list/roster
@@ -352,6 +355,8 @@
 
 	void (*keepalive)(PurpleConnection *connection);
 
+	int (*get_keepalive_interval)(void);
+
 	void (*alias_buddy)(PurpleConnection *connection, const char *who,
 						const char *alias);
 
@@ -903,6 +908,8 @@
 void purple_protocol_server_iface_keepalive(PurpleProtocol *protocol,
 		PurpleConnection *connection);
 
+int purple_protocol_server_iface_get_keepalive_interval(PurpleProtocol *protocol);
+
 void purple_protocol_server_iface_alias_buddy(PurpleProtocol *protocol,
 		PurpleConnection *connection, const char *who, const char *alias);
 
--- a/libpurple/protocols/jabber/jabber.c	Fri Mar 22 03:36:29 2019 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Fri Mar 29 01:15:18 2019 +0000
@@ -634,17 +634,19 @@
 void jabber_keepalive(PurpleConnection *gc)
 {
 	JabberStream *js = purple_connection_get_protocol_data(gc);
-	time_t now = time(NULL);
-
-	if (js->keepalive_timeout == 0 && (now - js->last_ping) >= PING_TIMEOUT) {
-		js->last_ping = now;
-
+
+	if (js->keepalive_timeout == 0) {
 		jabber_keepalive_ping(js);
 		js->keepalive_timeout = g_timeout_add_seconds(120,
 				(GSourceFunc)(jabber_keepalive_timeout), gc);
 	}
 }
 
+static int jabber_get_keepalive_interval(void)
+{
+	return PING_TIMEOUT;
+}
+
 static void
 jabber_recv_cb_ssl(gpointer data, PurpleSslConnection *gsc,
 		PurpleInputCondition cond)
@@ -4133,20 +4135,21 @@
 static void
 jabber_protocol_server_iface_init(PurpleProtocolServerIface *server_iface)
 {
-	server_iface->register_user   = jabber_register_account;
-	server_iface->unregister_user = jabber_unregister_account;
-	server_iface->set_info        = jabber_set_info;
-	server_iface->get_info        = jabber_buddy_get_info;
-	server_iface->set_status      = jabber_set_status;
-	server_iface->set_idle        = jabber_idle_set;
-	server_iface->add_buddy       = jabber_roster_add_buddy;
-	server_iface->remove_buddy    = jabber_roster_remove_buddy;
-	server_iface->keepalive       = jabber_keepalive;
-	server_iface->alias_buddy     = jabber_roster_alias_change;
-	server_iface->group_buddy     = jabber_roster_group_change;
-	server_iface->rename_group    = jabber_roster_group_rename;
-	server_iface->set_buddy_icon  = jabber_set_buddy_icon;
-	server_iface->send_raw        = jabber_protocol_send_raw;
+	server_iface->register_user          = jabber_register_account;
+	server_iface->unregister_user        = jabber_unregister_account;
+	server_iface->set_info               = jabber_set_info;
+	server_iface->get_info               = jabber_buddy_get_info;
+	server_iface->set_status             = jabber_set_status;
+	server_iface->set_idle               = jabber_idle_set;
+	server_iface->add_buddy              = jabber_roster_add_buddy;
+	server_iface->remove_buddy           = jabber_roster_remove_buddy;
+	server_iface->keepalive              = jabber_keepalive;
+	server_iface->get_keepalive_interval = jabber_get_keepalive_interval;
+	server_iface->alias_buddy            = jabber_roster_alias_change;
+	server_iface->group_buddy            = jabber_roster_group_change;
+	server_iface->rename_group           = jabber_roster_group_rename;
+	server_iface->set_buddy_icon         = jabber_set_buddy_icon;
+	server_iface->send_raw               = jabber_protocol_send_raw;
 }
 
 static void
--- a/libpurple/protocols/jabber/jabber.h	Fri Mar 22 03:36:29 2019 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Fri Mar 29 01:15:18 2019 +0000
@@ -191,11 +191,6 @@
 	time_t idle;
 	time_t old_idle;
 
-	/** When we last pinged the server, so we don't ping more
-	 *  often than once every minute.
-	 */
-	time_t last_ping;
-
 	JabberID *user;
 	JabberBuddy *user_jb;
 
--- a/libpurple/util.c	Fri Mar 22 03:36:29 2019 +0000
+++ b/libpurple/util.c	Fri Mar 29 01:15:18 2019 +0000
@@ -1137,6 +1137,17 @@
 	return g_string_free(string, FALSE);
 }
 
+
+/**************************************************************************/
+/* GLib Event Loop Functions                                              */
+/**************************************************************************/
+
+void purple_timeout_reset(GSource *source, gint64 seconds_from_now)
+{
+	g_source_set_ready_time(source, g_get_monotonic_time() + (seconds_from_now * G_USEC_PER_SEC));
+}
+
+
 /**************************************************************************
  * Markup Functions
  **************************************************************************/
--- a/libpurple/util.h	Fri Mar 22 03:36:29 2019 +0000
+++ b/libpurple/util.h	Fri Mar 29 01:15:18 2019 +0000
@@ -368,6 +368,43 @@
 
 
 /**************************************************************************/
+/* GLib Event Loop Functions                                              */
+/**************************************************************************/
+
+/**
+ * purple_timeout_reset:
+ * @source:           A #GTimeoutSource.
+ * @seconds_from_now: Seconds to add to current monotonic time.
+ *
+ * Resets a #GTimeoutSource to be dispatched after @seconds_from_now seconds,
+ * after which it'll continue dispatching at its specified interval.
+ *
+ * The #GSource API exposes a function g_source_set_ready_time(), which is
+ * meant to be used for implementing custom source types. It sets a #GSource
+ * to be dispatched when the given monotonic time is reached, and it's also
+ * the function that's used by the #GTimeoutSource implementation to keep
+ * dispatching at a specified interval.
+ *
+ * The #GTimeoutSource API doesn't expose a function to reset when a
+ * #GTimeoutSource will dispatch the next time, but because it works to
+ * directly call g_source_set_ready_time() on a #GTimeoutSource, and since
+ * it seems unlikely that the implementation will change, we just do that
+ * for now as a workaround for this API shortcoming.
+ *
+ * For the moment, these would be correct ways to achieve a similar effect,
+ * both of which are ugly:
+ *
+ * - Remove the old #GTimeoutSource by calling g_source_remove(), and add a
+ *   new #GTimeoutSource by calling g_timeout_add_seconds(). Destroying and
+ *   creating #GSource objects is unnecessarily expensive.
+ * - Implement a custom #GResettableTimeoutSource. This means duplicating
+ *   #GTimeoutSource and adding one function g_resettable_timeout_reset()
+ *   which simply calls g_source_set_ready_time().
+ */
+void purple_timeout_reset(GSource *source, gint64 seconds_from_now);
+
+
+/**************************************************************************/
 /* Markup Functions                                                       */
 /**************************************************************************/
 

mercurial