From 9c8f5b1318e64560c7a7b63f0f29ce90deb15c78 Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Wed, 30 Mar 2011 03:00:30 +0300 Subject: [PATCH] Send keep-alive packets A new TpCMParamSpec called "keepalive-interval" was added to configure the gap between successive PING messages. It has the XChat-GNOME default of 30s. Fixes: https://bugs.freedesktop.org/35058 --- data/idle.manager | 2 ++ src/idle-connection.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/protocol.c | 5 +++++ 3 files changed, 55 insertions(+), 0 deletions(-) diff --git a/data/idle.manager b/data/idle.manager index 7c8e05e..1b981ce 100644 --- a/data/idle.manager +++ b/data/idle.manager @@ -11,10 +11,12 @@ param-username = s param-port = q param-password = s secret param-charset = s +param-keepalive-interval = u param-quit-message = s param-use-ssl = b param-password-prompt = b default-port = 6667 default-charset = UTF-8 +default-keepalive-interval = 30 default-use-ssl = false default-password-prompt = false diff --git a/src/idle-connection.c b/src/idle-connection.c index 99ad92a..59812d3 100644 --- a/src/idle-connection.c +++ b/src/idle-connection.c @@ -3,6 +3,7 @@ * * Copyright (C) 2006-2007 Collabora Limited * Copyright (C) 2006-2007 Nokia Corporation + * Copyright (C) 2011 Debarshi Ray * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -56,6 +57,8 @@ * be subject to this mechanism. */ +#define DEFAULT_KEEPALIVE_INTERVAL 30 /* sec */ + #define MSG_QUEUE_UNLOAD_AT_A_TIME 1 #define MSG_QUEUE_TIMEOUT 2 @@ -124,6 +127,7 @@ enum { PROP_REALNAME, PROP_USERNAME, PROP_CHARSET, + PROP_KEEPALIVE_INTERVAL, PROP_QUITMESSAGE, PROP_USE_SSL, PROP_PASSWORD_PROMPT, @@ -148,6 +152,7 @@ struct _IdleConnectionPrivate { char *realname; char *username; char *charset; + guint keepalive_interval; char *quit_message; gboolean use_ssl; gboolean password_prompt; @@ -164,6 +169,9 @@ struct _IdleConnectionPrivate { /* UNIX time the last message was sent on */ time_t last_msg_sent; + /* GSource id for keep alive message timeout */ + guint keepalive_timeout; + /* GSource id for message queue unloading timeout */ guint msg_queue_timeout; @@ -210,6 +218,8 @@ static void connection_disconnect_cb(IdleConnection *conn, TpConnectionStatusRea static gboolean idle_connection_hton(IdleConnection *obj, const gchar *input, gchar **output, GError **_error); static void idle_connection_ntoh(IdleConnection *obj, const gchar *input, gchar **output); +static void _send_with_priority(IdleConnection *conn, const gchar *msg, guint priority); + static void idle_connection_init(IdleConnection *obj) { IdleConnectionPrivate *priv = IDLE_CONNECTION_GET_PRIVATE(obj); @@ -265,6 +275,10 @@ static void idle_connection_set_property(GObject *obj, guint prop_id, const GVal priv->charset = g_value_dup_string(value); break; + case PROP_KEEPALIVE_INTERVAL: + priv->keepalive_interval = g_value_get_uint(value); + break; + case PROP_QUITMESSAGE: g_free(priv->quit_message); priv->quit_message = g_value_dup_string(value); @@ -316,6 +330,10 @@ static void idle_connection_get_property(GObject *obj, guint prop_id, GValue *va g_value_set_string(value, priv->charset); break; + case PROP_KEEPALIVE_INTERVAL: + g_value_set_uint(value, priv->keepalive_interval); + break; + case PROP_QUITMESSAGE: g_value_set_string(value, priv->quit_message); break; @@ -343,6 +361,11 @@ static void idle_connection_dispose (GObject *object) { priv->dispose_has_run = TRUE; + if (priv->keepalive_timeout) { + g_source_remove(priv->keepalive_timeout); + priv->keepalive_timeout = 0; + } + if (priv->msg_queue_timeout) g_source_remove(priv->msg_queue_timeout); @@ -443,6 +466,9 @@ static void idle_connection_class_init(IdleConnectionClass *klass) { param_spec = g_param_spec_string("charset", "Character set", "The character set to use to communicate with the outside world", "NULL", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT); g_object_class_install_property(object_class, PROP_CHARSET, param_spec); + param_spec = g_param_spec_uint("keepalive-interval", "Keepalive interval", "Seconds between keepalive packets, or 0 to disable", 0, G_MAXUINT, DEFAULT_KEEPALIVE_INTERVAL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT); + g_object_class_install_property(object_class, PROP_KEEPALIVE_INTERVAL, param_spec); + param_spec = g_param_spec_string("quit-message", "Quit message", "The quit message to send to the server when leaving IRC", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT); g_object_class_install_property(object_class, PROP_QUITMESSAGE, param_spec); @@ -652,6 +678,7 @@ static void _start_connecting_continue(IdleConnection *conn) { irc_handshakes(conn); } +static gboolean keepalive_timeout_cb(gpointer user_data); static gboolean msg_queue_timeout_cb(gpointer user_data); static void sconn_status_changed_cb(IdleServerConnectionIface *sconn, IdleServerConnectionState state, IdleServerConnectionStateReason reason, IdleConnection *conn) { @@ -699,6 +726,9 @@ static void sconn_status_changed_cb(IdleServerConnectionIface *sconn, IdleServer break; case SERVER_CONNECTION_STATE_CONNECTED: + if (priv->keepalive_interval != 0 && priv->keepalive_timeout == 0) + priv->keepalive_timeout = g_timeout_add_seconds(priv->keepalive_interval, keepalive_timeout_cb, conn); + if ((priv->msg_queue_timeout == 0) && (g_queue_get_length(priv->msg_queue) > 0)) { IDLE_DEBUG("we had messages in queue, start unloading them now"); @@ -723,6 +753,24 @@ static void sconn_received_cb(IdleServerConnectionIface *sconn, gchar *raw_msg, g_free(converted); } +static gboolean keepalive_timeout_cb(gpointer user_data) { + IdleConnection *conn = IDLE_CONNECTION(user_data); + IdleConnectionPrivate *priv = IDLE_CONNECTION_GET_PRIVATE(conn); + gchar cmd[IRC_MSG_MAXLEN + 1]; + gint64 ping_time; + + if (priv->sconn_status != SERVER_CONNECTION_STATE_CONNECTED) { + priv->keepalive_timeout = 0; + return FALSE; + } + + ping_time = g_get_real_time(); + g_snprintf(cmd, IRC_MSG_MAXLEN + 1, "PING %" G_GINT64_FORMAT, ping_time); + _send_with_priority(conn, cmd, SERVER_CMD_MIN_PRIORITY); + + return TRUE; +} + static gboolean msg_queue_timeout_cb(gpointer user_data) { IdleConnection *conn = IDLE_CONNECTION(user_data); IdleConnectionPrivate *priv = IDLE_CONNECTION_GET_PRIVATE(conn); diff --git a/src/protocol.c b/src/protocol.c index f2fd36e..368c199 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -34,6 +34,7 @@ #define ENGLISH_NAME "IRC" #define VCARD_FIELD_NAME "x-" PROTOCOL_NAME #define DEFAULT_PORT 6667 +#define DEFAULT_KEEPALIVE_INTERVAL 30 /* sec */ G_DEFINE_TYPE (IdleProtocol, idle_protocol, TP_TYPE_BASE_PROTOCOL) @@ -99,6 +100,9 @@ static const TpCMParamSpec idle_params[] = { filter_username }, { "charset", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING, TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, "UTF-8" }, + { "keepalive-interval", DBUS_TYPE_UINT32_AS_STRING, G_TYPE_UINT, + TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, + GUINT_TO_POINTER (DEFAULT_KEEPALIVE_INTERVAL) }, { "quit-message", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING, 0 }, { "use-ssl", DBUS_TYPE_BOOLEAN_AS_STRING, G_TYPE_BOOLEAN, TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, GINT_TO_POINTER (FALSE) }, @@ -137,6 +141,7 @@ new_connection (TpBaseProtocol *protocol G_GNUC_UNUSED, "realname", tp_asv_get_string (params, "fullname"), "username", tp_asv_get_string (params, "username"), "charset", tp_asv_get_string (params, "charset"), + "keepalive-interval", tp_asv_get_uint32 (params, "keepalive-interval", NULL), "quit-message", tp_asv_get_string (params, "quit-message"), "use-ssl", tp_asv_get_boolean (params, "use-ssl", NULL), "password-prompt", tp_asv_get_boolean (params, "password-prompt", -- 1.7.4.2