[evolution-data-server] Add camel_network_service_can_reach_sync().



commit c2f18ec8201d4ef001766094f333f7c0d4ff22cc
Author: Matthew Barnes <mbarnes redhat com>
Date:   Fri Nov 22 16:16:32 2013 -0500

    Add camel_network_service_can_reach_sync().
    
    Just wrappers g_network_monitor_can_reach() using the service's own
    GSocketConnectable, but also updates the "host-reachable" property.
    External callers can use this to synchronously update the property,
    in case they need an up-to-date result to make a decision.
    
    Also adds equivalent asynchronous functions:
    
      camel_network_service_can_reach()
      camel_network_service_can_reach_finish()

 camel/camel-network-service.c           |  250 +++++++++++++++++++++++--------
 camel/camel-network-service.h           |   13 ++
 docs/reference/camel/camel-sections.txt |    3 +
 3 files changed, 202 insertions(+), 64 deletions(-)
---
diff --git a/camel/camel-network-service.c b/camel/camel-network-service.c
index 03855c0..f2a0e4c 100644
--- a/camel/camel-network-service.c
+++ b/camel/camel-network-service.c
@@ -395,6 +395,30 @@ network_service_client_event_cb (GSocketClient *client,
        }
 }
 
+static gboolean
+network_service_notify_host_reachable_cb (gpointer user_data)
+{
+       g_object_notify (G_OBJECT (user_data), "host-reachable");
+
+       return G_SOURCE_REMOVE;
+}
+
+static void
+network_service_notify_host_reachable (CamelNetworkService *service)
+{
+       CamelSession *session;
+
+       session = camel_service_ref_session (CAMEL_SERVICE (service));
+
+       camel_session_idle_add (
+               session, G_PRIORITY_DEFAULT_IDLE,
+               network_service_notify_host_reachable_cb,
+               g_object_ref (service),
+               (GDestroyNotify) g_object_unref);
+
+       g_object_unref (session);
+}
+
 static void
 network_service_set_host_reachable (CamelNetworkService *service,
                                     gboolean host_reachable)
@@ -420,7 +444,7 @@ network_service_set_host_reachable (CamelNetworkService *service,
 
        g_mutex_unlock (&priv->property_lock);
 
-       g_object_notify (G_OBJECT (service), "host-reachable");
+       network_service_notify_host_reachable (service);
 
        /* Disconnect immediately if the host is not reachable.
         * Then connect lazily when the host becomes reachable. */
@@ -438,48 +462,13 @@ network_service_set_host_reachable (CamelNetworkService *service,
        }
 }
 
-static void
-network_service_can_reach_cb (GObject *source_object,
-                              GAsyncResult *result,
-                              gpointer user_data)
-{
-       CamelNetworkService *service;
-       GError *error = NULL;
-
-       service = CAMEL_NETWORK_SERVICE (user_data);
-
-       g_network_monitor_can_reach_finish (
-               G_NETWORK_MONITOR (source_object), result, &error);
-
-       if (error == NULL) {
-               network_service_set_host_reachable (service, TRUE);
-
-       } else if (G_IS_IO_ERROR (error, G_IO_ERROR_CANCELLED)) {
-               /* Ignore cancellations. */
-
-       } else if (G_IS_IO_ERROR (error, G_IO_ERROR_HOST_UNREACHABLE)) {
-               network_service_set_host_reachable (service, FALSE);
-
-       } else if (G_IS_RESOLVER_ERROR (error, G_RESOLVER_ERROR_NOT_FOUND)) {
-               network_service_set_host_reachable (service, FALSE);
-
-       } else {
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-       }
-
-       if (error != NULL)
-               g_error_free (error);
-
-       g_object_unref (service);
-}
-
 static gboolean
 network_service_update_host_reachable_idle_cb (gpointer user_data)
 {
        CamelNetworkService *service;
        CamelNetworkServicePrivate *priv;
-       GSocketConnectable *connectable;
-       GCancellable *cancellable;
+       GCancellable *old_cancellable;
+       GCancellable *new_cancellable;
 
        service = CAMEL_NETWORK_SERVICE (user_data);
        priv = CAMEL_NETWORK_SERVICE_GET_PRIVATE (service);
@@ -490,37 +479,22 @@ network_service_update_host_reachable_idle_cb (gpointer user_data)
        priv->update_host_reachable = NULL;
        g_mutex_unlock (&priv->update_host_reachable_lock);
 
-       connectable = camel_network_service_ref_connectable (service);
+       new_cancellable = g_cancellable_new ();
 
        g_mutex_lock (&priv->network_monitor_cancellable_lock);
+       old_cancellable = priv->network_monitor_cancellable;
+       priv->network_monitor_cancellable = g_object_ref (new_cancellable);
+       g_mutex_unlock (&priv->network_monitor_cancellable_lock);
 
-       cancellable = priv->network_monitor_cancellable;
-       priv->network_monitor_cancellable = NULL;
-
-       if (cancellable != NULL) {
-               g_cancellable_cancel (cancellable);
-               g_object_unref (cancellable);
-               cancellable = NULL;
-       }
-
-       if (connectable == NULL) {
-               network_service_set_host_reachable (service, FALSE);
-       } else {
-               cancellable = g_cancellable_new ();
-
-               g_network_monitor_can_reach_async (
-                       priv->network_monitor,
-                       connectable, cancellable,
-                       network_service_can_reach_cb,
-                       g_object_ref (service));
-       }
-
-       priv->network_monitor_cancellable = cancellable;
+       g_cancellable_cancel (old_cancellable);
 
-       g_mutex_unlock (&priv->network_monitor_cancellable_lock);
+       /* XXX This updates the "host-reachable" property on its own.
+        *     There's nothing else to do with the result so omit the
+        *     GAsyncReadyCallback; just needs to run asynchronously. */
+       camel_network_service_can_reach (service, new_cancellable, NULL, NULL);
 
-       if (connectable != NULL)
-               g_object_unref (connectable);
+       g_clear_object (&old_cancellable);
+       g_clear_object (&new_cancellable);
 
        return FALSE;
 }
@@ -982,3 +956,151 @@ camel_network_service_starttls (CamelNetworkService *service,
        return tls_client_connection;
 }
 
+/**
+ * camel_network_service_can_reach_sync:
+ * @service: a #CamelNetworkService
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Attempts to determine whether or not the host described by @service's
+ * #CamelNetworkService:connectable property can be reached, without actually
+ * trying to connect to it.
+ *
+ * If @service believes an attempt to connect will succeed, the function
+ * returns %TRUE.  Otherwise the function returns %FALSE and sets @error
+ * to an appropriate error (such as %G_IO_ERROR_HOST_UNREACHABLE).
+ *
+ * The function will also update the @service's
+ * #CamelNetworkService:host-reachable property based on the result.
+ *
+ * Returns: whether the host for @service can be reached
+ *
+ * Since: 3.12
+ **/
+gboolean
+camel_network_service_can_reach_sync (CamelNetworkService *service,
+                                      GCancellable *cancellable,
+                                      GError **error)
+{
+       CamelNetworkServicePrivate *priv;
+       GSocketConnectable *connectable;
+       gboolean can_reach = FALSE;
+       gboolean update_property;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_NETWORK_SERVICE (service), FALSE);
+
+       priv = CAMEL_NETWORK_SERVICE_GET_PRIVATE (service);
+       g_return_val_if_fail (priv != NULL, FALSE);
+
+       connectable = camel_network_service_ref_connectable (service);
+
+       if (connectable != NULL) {
+               can_reach = g_network_monitor_can_reach (
+                       priv->network_monitor, connectable,
+                       cancellable, &local_error);
+       } else {
+               local_error = g_error_new_literal (
+                       G_IO_ERROR,
+                       G_IO_ERROR_HOST_UNREACHABLE,
+                       _("No host information available"));
+       }
+
+       update_property =
+               can_reach ||
+               G_IS_IO_ERROR (local_error, G_IO_ERROR_HOST_UNREACHABLE) ||
+               G_IS_RESOLVER_ERROR (local_error, G_RESOLVER_ERROR_NOT_FOUND);
+
+       if (update_property)
+               network_service_set_host_reachable (service, can_reach);
+
+       g_clear_object (&connectable);
+
+       return can_reach;
+}
+
+/* Helper for camel_network_service_can_reach() */
+static void
+network_service_can_reach_thread (GSimpleAsyncResult *simple,
+                                  GObject *object,
+                                  GCancellable *cancellable)
+{
+       GError *local_error = NULL;
+
+       camel_network_service_can_reach_sync (
+               CAMEL_NETWORK_SERVICE (object), cancellable, &local_error);
+
+       if (local_error != NULL)
+               g_simple_async_result_take_error (simple, local_error);
+}
+
+/**
+ * camel_network_service_can_reach:
+ * @service: a #CamelNetworkService
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously attempts to determine whether or not the host described by
+ * @service's #CamelNetworkService:connectable property can be reached, without
+ * actually trying to connect to it.
+ *
+ * For more details, see camel_network_service_can_reach_sync().
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_network_service_can_reach_finish() to get the result of the
+ * operation.
+ *
+ * Since: 3.12
+ **/
+void
+camel_network_service_can_reach (CamelNetworkService *service,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
+{
+       GSimpleAsyncResult *simple;
+
+       simple = g_simple_async_result_new (
+               G_OBJECT (service), callback, user_data,
+               camel_network_service_can_reach);
+
+       g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+       g_simple_async_result_run_in_thread (
+               simple, network_service_can_reach_thread,
+               G_PRIORITY_DEFAULT, cancellable);
+
+       g_object_unref (simple);
+}
+
+/**
+ * camel_network_service_can_reach_finish:
+ * @service: a #CamelNetworkService
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_network_service_can_reach().
+ *
+ * Returns: whether the host for @service can be reached
+ *
+ * Since: 3.12
+ **/
+gboolean
+camel_network_service_can_reach_finish (CamelNetworkService *service,
+                                        GAsyncResult *result,
+                                        GError **error)
+{
+       GSimpleAsyncResult *simple;
+
+       g_return_val_if_fail (
+               g_simple_async_result_is_valid (
+               result, G_OBJECT (service),
+               camel_network_service_can_reach), FALSE);
+
+       simple = G_SIMPLE_ASYNC_RESULT (result);
+
+       /* Assume success unless a GError is set. */
+       return !g_simple_async_result_propagate_error (simple, error);
+}
+
diff --git a/camel/camel-network-service.h b/camel/camel-network-service.h
index dd819a5..6f5da59 100644
--- a/camel/camel-network-service.h
+++ b/camel/camel-network-service.h
@@ -100,6 +100,19 @@ GIOStream *        camel_network_service_starttls
                                        (CamelNetworkService *service,
                                         GIOStream *base_stream,
                                         GError **error);
+gboolean       camel_network_service_can_reach_sync
+                                       (CamelNetworkService *service,
+                                        GCancellable *cancellable,
+                                        GError **error);
+void           camel_network_service_can_reach
+                                       (CamelNetworkService *service,
+                                        GCancellable *cancellable,
+                                        GAsyncReadyCallback callback,
+                                        gpointer user_data);
+gboolean       camel_network_service_can_reach_finish
+                                       (CamelNetworkService *service,
+                                        GAsyncResult *result,
+                                        GError **error);
 
 G_END_DECLS
 
diff --git a/docs/reference/camel/camel-sections.txt b/docs/reference/camel/camel-sections.txt
index 4f7f024..111e576 100644
--- a/docs/reference/camel/camel-sections.txt
+++ b/docs/reference/camel/camel-sections.txt
@@ -1391,6 +1391,9 @@ camel_network_service_set_connectable
 camel_network_service_get_host_reachable
 camel_network_service_connect_sync
 camel_network_service_starttls
+camel_network_service_can_reach_sync
+camel_network_service_can_reach
+camel_network_service_can_reach_finish
 <SUBSECTION Standard>
 CAMEL_NETWORK_SERVICE
 CAMEL_IS_NETWORK_SERVICE


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]