Fri, 29 Mar 2019 01:15:18 +0000
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
--- 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 */ /**************************************************************************/