[evolution-ews] I#77 - Can sometimes stop listening for server notifications
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-ews] I#77 - Can sometimes stop listening for server notifications
- Date: Fri, 7 Feb 2020 09:46:29 +0000 (UTC)
commit 74bd6251fc9e9d58ee224680c3dbb4e5e2f943b3
Author: Milan Crha <mcrha redhat com>
Date: Fri Feb 7 10:46:43 2020 +0100
I#77 - Can sometimes stop listening for server notifications
Closes https://gitlab.gnome.org/GNOME/evolution-ews/issues/77
src/server/e-ews-connection.c | 59 ++++++-----
src/server/e-ews-notification.c | 221 +++++++++++++++++++++++++++-------------
2 files changed, 182 insertions(+), 98 deletions(-)
---
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index c6f40827..cd4eaa8b 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -2035,16 +2035,14 @@ ews_connection_constructed (GObject *object)
static void
ews_connection_dispose (GObject *object)
{
- EEwsConnectionPrivate *priv;
-
- priv = E_EWS_CONNECTION_GET_PRIVATE (object);
+ EEwsConnection *cnc = E_EWS_CONNECTION (object);
g_mutex_lock (&connecting);
/* remove the connection from the hash table */
if (loaded_connections_permissions != NULL &&
- g_hash_table_lookup (loaded_connections_permissions, priv->hash_key) == (gpointer) object) {
- g_hash_table_remove (loaded_connections_permissions, priv->hash_key);
+ g_hash_table_lookup (loaded_connections_permissions, cnc->priv->hash_key) == (gpointer) object) {
+ g_hash_table_remove (loaded_connections_permissions, cnc->priv->hash_key);
if (g_hash_table_size (loaded_connections_permissions) == 0) {
g_hash_table_destroy (loaded_connections_permissions);
loaded_connections_permissions = NULL;
@@ -2053,39 +2051,46 @@ ews_connection_dispose (GObject *object)
g_mutex_unlock (&connecting);
- if (priv->soup_session) {
+ NOTIFICATION_LOCK (cnc);
+ if (cnc->priv->notification) {
+ e_ews_notification_stop_listening_sync (cnc->priv->notification);
+ g_clear_object (&cnc->priv->notification);
+ }
+ NOTIFICATION_UNLOCK (cnc);
+
+ if (cnc->priv->soup_session) {
g_signal_handlers_disconnect_by_func (
- priv->soup_session,
+ cnc->priv->soup_session,
ews_connection_authenticate, object);
- g_main_loop_quit (priv->soup_loop);
- g_thread_join (priv->soup_thread);
- priv->soup_thread = NULL;
+ g_main_loop_quit (cnc->priv->soup_loop);
+ g_thread_join (cnc->priv->soup_thread);
+ cnc->priv->soup_thread = NULL;
- g_main_loop_unref (priv->soup_loop);
- priv->soup_loop = NULL;
- g_main_context_unref (priv->soup_context);
- priv->soup_context = NULL;
+ g_main_loop_unref (cnc->priv->soup_loop);
+ cnc->priv->soup_loop = NULL;
+ g_main_context_unref (cnc->priv->soup_context);
+ cnc->priv->soup_context = NULL;
}
- g_clear_object (&priv->proxy_resolver);
- g_clear_object (&priv->source);
- g_clear_object (&priv->settings);
+ g_clear_object (&cnc->priv->proxy_resolver);
+ g_clear_object (&cnc->priv->source);
+ g_clear_object (&cnc->priv->settings);
- e_ews_connection_set_password (E_EWS_CONNECTION (object), NULL);
+ e_ews_connection_set_password (cnc, NULL);
- g_slist_free (priv->jobs);
- priv->jobs = NULL;
+ g_slist_free (cnc->priv->jobs);
+ cnc->priv->jobs = NULL;
- g_slist_free (priv->active_job_queue);
- priv->active_job_queue = NULL;
+ g_slist_free (cnc->priv->active_job_queue);
+ cnc->priv->active_job_queue = NULL;
- g_slist_free_full (priv->subscribed_folders, g_free);
- priv->subscribed_folders = NULL;
+ g_slist_free_full (cnc->priv->subscribed_folders, g_free);
+ cnc->priv->subscribed_folders = NULL;
- if (priv->subscriptions != NULL) {
- g_hash_table_destroy (priv->subscriptions);
- priv->subscriptions = NULL;
+ if (cnc->priv->subscriptions != NULL) {
+ g_hash_table_destroy (cnc->priv->subscriptions);
+ cnc->priv->subscriptions = NULL;
}
/* Chain up to parent's dispose() method. */
diff --git a/src/server/e-ews-notification.c b/src/server/e-ews-notification.c
index c2d03df1..c808245b 100644
--- a/src/server/e-ews-notification.c
+++ b/src/server/e-ews-notification.c
@@ -33,7 +33,7 @@ G_DEFINE_TYPE (EEwsNotification, e_ews_notification, G_TYPE_OBJECT)
struct _EEwsNotificationPrivate {
SoupSession *soup_session;
- EEwsConnection *connection; /* not referred */
+ GWeakRef connection_wk;
GByteArray *chunk;
GCancellable *cancellable;
};
@@ -61,6 +61,15 @@ struct _EEwsNotificationThreadData {
GSList *folders;
};
+static EEwsConnection *
+e_ews_notification_ref_connection (const EEwsNotification *notification)
+{
+ g_return_val_if_fail (E_IS_EWS_NOTIFICATION (notification), NULL);
+ g_return_val_if_fail (notification->priv != NULL, NULL);
+
+ return g_weak_ref_get (¬ification->priv->connection_wk);
+}
+
static void
ews_notification_authenticate (SoupSession *session,
SoupMessage *message,
@@ -69,11 +78,16 @@ ews_notification_authenticate (SoupSession *session,
gpointer data)
{
EEwsNotification *notification = data;
+ EEwsConnection *cnc;
g_return_if_fail (notification != NULL);
- g_return_if_fail (notification->priv->connection != NULL);
- e_ews_connection_utils_authenticate (notification->priv->connection, session, message, auth,
retrying);
+ cnc = e_ews_notification_ref_connection (notification);
+
+ if (cnc) {
+ e_ews_connection_utils_authenticate (cnc, session, message, auth, retrying);
+ g_clear_object (&cnc);
+ }
}
EEwsNotification *
@@ -92,22 +106,8 @@ e_ews_notification_set_connection (EEwsNotification *notification,
{
g_return_if_fail (E_IS_EWS_NOTIFICATION (notification));
g_return_if_fail (E_IS_EWS_CONNECTION (connection));
- g_return_if_fail (notification->priv->connection == NULL);
- notification->priv->connection = connection;
- g_object_weak_ref (
- G_OBJECT (notification->priv->connection),
- (GWeakNotify) g_nullify_pointer,
- ¬ification->priv->connection);
-}
-
-static EEwsConnection *
-e_ews_notification_get_connection (const EEwsNotification *notification)
-{
- g_return_val_if_fail (E_IS_EWS_NOTIFICATION (notification), NULL);
- g_return_val_if_fail (notification->priv != NULL, NULL);
-
- return notification->priv->connection;
+ g_weak_ref_set (¬ification->priv->connection_wk, connection);
}
static void
@@ -137,7 +137,7 @@ ews_notification_get_property (GObject *object,
case PROP_CONNECTION:
g_value_take_object (
value,
- e_ews_notification_get_connection (
+ e_ews_notification_ref_connection (
E_EWS_NOTIFICATION (object)));
return;
}
@@ -149,18 +149,24 @@ static void
ews_notification_constructed (GObject *object)
{
EEwsNotification *notif;
+ EEwsConnection *cnc;
CamelEwsSettings *ews_settings;
/* Chain up to parent's method. */
G_OBJECT_CLASS (e_ews_notification_parent_class)->constructed (object);
notif = E_EWS_NOTIFICATION (object);
- ews_settings = e_ews_connection_ref_settings (notif->priv->connection);
+ cnc = e_ews_notification_ref_connection (notif);
+
+ if (cnc) {
+ ews_settings = e_ews_connection_ref_settings (cnc);
- e_ews_connection_utils_prepare_auth_method (notif->priv->soup_session,
- camel_ews_settings_get_auth_mechanism (ews_settings));
+ e_ews_connection_utils_prepare_auth_method (notif->priv->soup_session,
+ camel_ews_settings_get_auth_mechanism (ews_settings));
- g_object_unref (ews_settings);
+ g_object_unref (ews_settings);
+ g_object_unref (cnc);
+ }
}
static void
@@ -183,18 +189,25 @@ ews_notification_dispose (GObject *object)
if (priv->cancellable != NULL)
g_clear_object (&priv->cancellable);
- if (priv->connection != NULL) {
- g_object_weak_unref (
- G_OBJECT (priv->connection),
- (GWeakNotify) g_nullify_pointer,
- &priv->connection);
- priv->connection = NULL;
- }
+ g_weak_ref_set (&priv->connection_wk, NULL);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_ews_notification_parent_class)->dispose (object);
}
+static void
+ews_notification_finalize (GObject *object)
+{
+ EEwsNotification *notif;
+
+ notif = E_EWS_NOTIFICATION (object);
+
+ g_weak_ref_clear (¬if->priv->connection_wk);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_ews_notification_parent_class)->finalize (object);
+}
+
static void
e_ews_notification_class_init (EEwsNotificationClass *class)
{
@@ -207,6 +220,7 @@ e_ews_notification_class_init (EEwsNotificationClass *class)
object_class->get_property = ews_notification_get_property;
object_class->constructed = ews_notification_constructed;
object_class->dispose = ews_notification_dispose;
+ object_class->finalize = ews_notification_finalize;
g_object_class_install_property (
object_class,
@@ -228,6 +242,8 @@ e_ews_notification_init (EEwsNotification *notification)
notification->priv = E_EWS_NOTIFICATION_GET_PRIVATE (notification);
+ g_weak_ref_init (¬ification->priv->connection_wk, NULL);
+
notification->priv->soup_session = soup_session_sync_new ();
soup_session_add_feature_by_type (notification->priv->soup_session,
@@ -251,6 +267,7 @@ e_ews_notification_subscribe_folder_sync (EEwsNotification *notification,
gchar **subscription_id,
GCancellable *cancellable)
{
+ EEwsConnection *cnc;
ESoapMessage *msg;
ESoapResponse *response;
ESoapParameter *param, *subparam;
@@ -264,20 +281,22 @@ e_ews_notification_subscribe_folder_sync (EEwsNotification *notification,
g_return_val_if_fail (notification != NULL, FALSE);
g_return_val_if_fail (notification->priv != NULL, FALSE);
+ cnc = e_ews_notification_ref_connection (notification);
+
/* Can happen during process shutdown */
- if (!notification->priv->connection)
+ if (!cnc)
return FALSE;
- settings = e_ews_connection_ref_settings (notification->priv->connection);
+ settings = e_ews_connection_ref_settings (cnc);
msg = e_ews_message_new_with_header (
settings,
- e_ews_connection_get_uri (notification->priv->connection),
- e_ews_connection_get_impersonate_user (notification->priv->connection),
+ e_ews_connection_get_uri (cnc),
+ e_ews_connection_get_impersonate_user (cnc),
"Subscribe",
NULL,
NULL,
- e_ews_connection_get_server_version (notification->priv->connection),
+ e_ews_connection_get_server_version (cnc),
E_EWS_EXCHANGE_2010_SP1,
FALSE,
FALSE);
@@ -285,7 +304,8 @@ e_ews_notification_subscribe_folder_sync (EEwsNotification *notification,
g_clear_object (&settings);
if (!msg) {
- g_warning ("%s: Failed to create Soup message for URI '%s'", G_STRFUNC,
e_ews_connection_get_uri (notification->priv->connection));
+ g_warning ("%s: Failed to create Soup message for URI '%s'", G_STRFUNC,
e_ews_connection_get_uri (cnc));
+ g_object_unref (cnc);
return FALSE;
}
@@ -325,6 +345,7 @@ e_ews_notification_subscribe_folder_sync (EEwsNotification *notification,
if (g_cancellable_is_cancelled (cancellable)) {
g_object_unref (msg);
+ g_object_unref (cnc);
return FALSE;
}
@@ -332,14 +353,16 @@ e_ews_notification_subscribe_folder_sync (EEwsNotification *notification,
e_ews_debug_dump_raw_soup_request (SOUP_MESSAGE (msg));
}
- if (!e_ews_connection_utils_prepare_message (notification->priv->connection,
notification->priv->soup_session, SOUP_MESSAGE (msg), cancellable)) {
+ if (!e_ews_connection_utils_prepare_message (cnc, notification->priv->soup_session, SOUP_MESSAGE
(msg), cancellable)) {
g_object_unref (msg);
+ g_object_unref (cnc);
return FALSE;
}
soup_session_send_message (notification->priv->soup_session, SOUP_MESSAGE (msg));
if (!SOUP_STATUS_IS_SUCCESSFUL (SOUP_MESSAGE (msg)->status_code)) {
g_object_unref (msg);
+ g_object_unref (cnc);
return FALSE;
}
@@ -354,6 +377,7 @@ e_ews_notification_subscribe_folder_sync (EEwsNotification *notification,
e_ews_debug_dump_raw_soup_response (SOUP_MESSAGE (msg));
}
g_object_unref (msg);
+ g_object_unref (cnc);
param = e_soap_response_get_first_parameter_by_name (response, "ResponseMessages", &error);
@@ -399,6 +423,7 @@ static gboolean
e_ews_notification_unsubscribe_folder_sync (EEwsNotification *notification,
const gchar *subscription_id)
{
+ EEwsConnection *cnc;
ESoapMessage *msg;
ESoapResponse *response;
ESoapParameter *param;
@@ -409,20 +434,22 @@ e_ews_notification_unsubscribe_folder_sync (EEwsNotification *notification,
g_return_val_if_fail (notification != NULL, FALSE);
g_return_val_if_fail (notification->priv != NULL, FALSE);
+ cnc = e_ews_notification_ref_connection (notification);
+
/* Can happen during process shutdown */
- if (!notification->priv->connection)
+ if (!cnc)
return FALSE;
- settings = e_ews_connection_ref_settings (notification->priv->connection);
+ settings = e_ews_connection_ref_settings (cnc);
msg = e_ews_message_new_with_header (
settings,
- e_ews_connection_get_uri (notification->priv->connection),
- e_ews_connection_get_impersonate_user (notification->priv->connection),
+ e_ews_connection_get_uri (cnc),
+ e_ews_connection_get_impersonate_user (cnc),
"Unsubscribe",
NULL,
NULL,
- e_ews_connection_get_server_version (notification->priv->connection),
+ e_ews_connection_get_server_version (cnc),
E_EWS_EXCHANGE_2010_SP1,
FALSE,
FALSE);
@@ -430,7 +457,8 @@ e_ews_notification_unsubscribe_folder_sync (EEwsNotification *notification,
g_clear_object (&settings);
if (!msg) {
- g_warning ("%s: Failed to create Soup message for URI '%s'", G_STRFUNC,
e_ews_connection_get_uri (notification->priv->connection));
+ g_warning ("%s: Failed to create Soup message for URI '%s'", G_STRFUNC,
e_ews_connection_get_uri (cnc));
+ g_object_unref (cnc);
return FALSE;
}
@@ -441,14 +469,16 @@ e_ews_notification_unsubscribe_folder_sync (EEwsNotification *notification,
soup_message_body_set_accumulate (SOUP_MESSAGE (msg)->response_body, TRUE);
- if (!e_ews_connection_utils_prepare_message (notification->priv->connection,
notification->priv->soup_session, SOUP_MESSAGE (msg), notification->priv->cancellable)) {
+ if (!e_ews_connection_utils_prepare_message (cnc, notification->priv->soup_session, SOUP_MESSAGE
(msg), notification->priv->cancellable)) {
g_object_unref (msg);
+ g_object_unref (cnc);
return FALSE;
}
soup_session_send_message (notification->priv->soup_session, SOUP_MESSAGE (msg));
if (!SOUP_STATUS_IS_SUCCESSFUL (SOUP_MESSAGE (msg)->status_code)) {
g_object_unref (msg);
+ g_object_unref (cnc);
return FALSE;
}
@@ -459,6 +489,7 @@ e_ews_notification_unsubscribe_folder_sync (EEwsNotification *notification,
response = e_soap_response_new_from_xmldoc (doc);
g_object_unref (msg);
+ g_object_unref (cnc);
param = e_soap_response_get_first_parameter_by_name (response, "ResponseMessages", &error);
@@ -609,8 +640,15 @@ ews_notification_fire_events_from_response (EEwsNotification *notification,
}
if (events != NULL) {
- if (notification->priv->connection)
- g_signal_emit_by_name (notification->priv->connection, "server-notification", events);
+ EEwsConnection *cnc;
+
+ cnc = e_ews_notification_ref_connection (notification);
+
+ if (cnc) {
+ g_signal_emit_by_name (cnc, "server-notification", events);
+ g_object_unref (cnc);
+ }
+
g_slist_free_full (events, (GDestroyNotify) e_ews_notification_event_free);
}
@@ -722,15 +760,58 @@ ews_notification_soup_got_chunk (SoupMessage *msg,
} while (keep_parsing);
}
+typedef struct _NotifcationCancelData {
+ SoupSession *session;
+ SoupMessage *msg;
+} NotifcationCancelData;
+
+static NotifcationCancelData *
+notifcation_cancel_data_new (SoupSession *session,
+ SoupMessage *msg)
+{
+ NotifcationCancelData *ncd;
+
+ ncd = g_slice_new (NotifcationCancelData);
+ ncd->session = g_object_ref (session);
+ ncd->msg = g_object_ref (msg);
+
+ return ncd;
+}
+
+static void
+notifcation_cancel_data_free (gpointer ptr)
+{
+ NotifcationCancelData *ncd = ptr;
+
+ if (ncd) {
+ g_clear_object (&ncd->session);
+ g_clear_object (&ncd->msg);
+ g_slice_free (NotifcationCancelData, ncd);
+ }
+}
+
+static void
+ews_notification_cancelled_cb (GCancellable *cancellable,
+ gpointer user_data)
+{
+ NotifcationCancelData *ncd = user_data;
+
+ g_return_if_fail (ncd != NULL);
+
+ soup_session_cancel_message (ncd->session, ncd->msg, SOUP_STATUS_CANCELLED);
+}
+
static gboolean
e_ews_notification_get_events_sync (EEwsNotification *notification,
const gchar *subscription_id,
- gboolean *out_fatal_error)
+ gboolean *out_fatal_error,
+ GCancellable *cancellable)
{
+ EEwsConnection *cnc;
ESoapMessage *msg;
CamelEwsSettings *settings;
gboolean ret;
- gulong handler_id;
+ gulong handler_id, cancel_handler_id;
guint status_code;
g_return_val_if_fail (out_fatal_error != NULL, FALSE);
@@ -739,18 +820,22 @@ e_ews_notification_get_events_sync (EEwsNotification *notification,
g_return_val_if_fail (notification != NULL, FALSE);
g_return_val_if_fail (notification->priv != NULL, FALSE);
- g_return_val_if_fail (notification->priv->connection != NULL, FALSE);
- settings = e_ews_connection_ref_settings (notification->priv->connection);
+ cnc = e_ews_notification_ref_connection (notification);
+
+ if (!cnc)
+ return FALSE;
+
+ settings = e_ews_connection_ref_settings (cnc);
msg = e_ews_message_new_with_header (
settings,
- e_ews_connection_get_uri (notification->priv->connection),
- e_ews_connection_get_impersonate_user (notification->priv->connection),
+ e_ews_connection_get_uri (cnc),
+ e_ews_connection_get_impersonate_user (cnc),
"GetStreamingEvents",
NULL,
NULL,
- e_ews_connection_get_server_version (notification->priv->connection),
+ e_ews_connection_get_server_version (cnc),
E_EWS_EXCHANGE_2010_SP1,
FALSE,
FALSE);
@@ -758,7 +843,8 @@ e_ews_notification_get_events_sync (EEwsNotification *notification,
g_clear_object (&settings);
if (!msg) {
- g_warning ("%s: Failed to create Soup message for URI '%s'", G_STRFUNC,
e_ews_connection_get_uri (notification->priv->connection));
+ g_warning ("%s: Failed to create Soup message for URI '%s'", G_STRFUNC,
e_ews_connection_get_uri (cnc));
+ g_object_unref (cnc);
return FALSE;
}
@@ -777,29 +863,30 @@ e_ews_notification_get_events_sync (EEwsNotification *notification,
SOUP_MESSAGE (msg), "got-chunk",
G_CALLBACK (ews_notification_soup_got_chunk), notification);
- if (!e_ews_connection_utils_prepare_message (notification->priv->connection,
notification->priv->soup_session, SOUP_MESSAGE (msg), notification->priv->cancellable)) {
+ if (!e_ews_connection_utils_prepare_message (cnc, notification->priv->soup_session, SOUP_MESSAGE
(msg), notification->priv->cancellable)) {
g_object_unref (msg);
+ g_object_unref (cnc);
return FALSE;
}
+ cancel_handler_id = g_cancellable_connect (cancellable, G_CALLBACK (ews_notification_cancelled_cb),
+ notifcation_cancel_data_new (notification->priv->soup_session, SOUP_MESSAGE (msg)),
notifcation_cancel_data_free);
+
status_code = soup_session_send_message (notification->priv->soup_session, SOUP_MESSAGE (msg));
+ if (cancel_handler_id > 0)
+ g_cancellable_disconnect (cancellable, cancel_handler_id);
+
ret = SOUP_STATUS_IS_SUCCESSFUL (status_code);
*out_fatal_error = SOUP_STATUS_IS_CLIENT_ERROR (status_code) || SOUP_STATUS_IS_SERVER_ERROR
(status_code);
g_signal_handler_disconnect (msg, handler_id);
g_object_unref (msg);
+ g_object_unref (cnc);
return ret;
}
-static void
-ews_notification_cancelled_cb (GCancellable *cancellable,
- SoupSession *session)
-{
- ews_notification_schedule_abort (session);
-}
-
static gpointer
e_ews_notification_get_events_thread (gpointer user_data)
{
@@ -815,18 +902,10 @@ e_ews_notification_get_events_thread (gpointer user_data)
goto exit;
do {
- gulong handler_id;
-
if (g_cancellable_is_cancelled (td->cancellable))
goto exit;
- handler_id = g_cancellable_connect (td->cancellable, G_CALLBACK
(ews_notification_cancelled_cb),
- g_object_ref (td->notification->priv->soup_session), g_object_unref);
-
- ret = e_ews_notification_get_events_sync (td->notification, subscription_id, &fatal_error);
-
- if (handler_id > 0)
- g_cancellable_disconnect (td->cancellable, handler_id);
+ ret = e_ews_notification_get_events_sync (td->notification, subscription_id, &fatal_error,
td->cancellable);
if (!ret && !g_cancellable_is_cancelled (td->cancellable)) {
g_debug ("%s: Failed to get notification events (SubscriptionId: '%s')", G_STRFUNC,
subscription_id);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]