Client library: make MT-safe; add get_default_identity()
authorSam Thursfield <samthursfield@codethink.co.uk>
Tue, 5 Jul 2011 10:49:02 +0000 (11:49 +0100)
committerSam Thursfield <samthursfield@codethink.co.uk>
Tue, 5 Jul 2011 10:49:02 +0000 (11:49 +0100)
libmoonshot/libmoonshot-dbus.c
libmoonshot/libmoonshot.h
src/dbus-client.vala
src/moonshot-server.vala
tests/basic.c

index 04d6da6..17a7246 100644 (file)
@@ -52,8 +52,6 @@
  * waiting for calls.
  */
 
-static DBusGProxy *moonshot_dbus_proxy = NULL;
-
 static DBusGProxy *dbus_connect (MoonshotError **error)
 {
     DBusConnection  *connection;
@@ -148,6 +146,24 @@ static DBusGProxy *dbus_connect (MoonshotError **error)
     return g_proxy; 
 }
 
+static DBusGProxy *get_dbus_proxy (MoonshotError **error)
+{
+    static DBusGProxy    *dbus_proxy = NULL;
+    static GStaticMutex   init_lock = G_STATIC_MUTEX_INIT;
+
+    g_static_mutex_lock (&init_lock);
+
+    if (dbus_proxy == NULL)
+        dbus_proxy = dbus_connect (error);
+
+    if (dbus_proxy != NULL)
+        g_object_ref (dbus_proxy);
+
+    g_static_mutex_unlock (&init_lock);
+
+    return dbus_proxy;
+}
+
 int moonshot_get_identity (const char     *nai,
                            const char     *password,
                            const char     *service,
@@ -159,18 +175,18 @@ int moonshot_get_identity (const char     *nai,
                            char          **subject_alt_name_constraint_out,
                            MoonshotError **error)
 {
-    GError   *g_error = NULL;
-    int success;
+    GError     *g_error = NULL;
+    DBusGProxy *dbus_proxy;
+    int         success;
 
-    if (moonshot_dbus_proxy == NULL)
-        moonshot_dbus_proxy = dbus_connect (error);
+    dbus_proxy = get_dbus_proxy (error);
 
     if (*error != NULL)
         return;
 
-    g_return_if_fail (DBUS_IS_G_PROXY (moonshot_dbus_proxy));
+    g_return_if_fail (DBUS_IS_G_PROXY (dbus_proxy));
 
-    dbus_g_proxy_call (moonshot_dbus_proxy,
+    dbus_g_proxy_call (dbus_proxy,
                        "GetIdentity",
                        &g_error,
                        G_TYPE_STRING, nai,
@@ -186,6 +202,8 @@ int moonshot_get_identity (const char     *nai,
                        G_TYPE_BOOLEAN, &success,
                        G_TYPE_INVALID);
 
+    g_object_unref (dbus_proxy);
+
     if (g_error != NULL) {
         *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
                                      g_error->message);
@@ -202,13 +220,52 @@ int moonshot_get_identity (const char     *nai,
     return TRUE;
 }
 
+int moonshot_get_default_identity (char          **nai_out,
+                                   char          **password_out,
+                                   char          **server_certificate_hash_out,
+                                   char          **ca_certificate_out,
+                                   char          **subject_name_constraint_out,
+                                   char          **subject_alt_name_constraint_out,
+                                   MoonshotError **error)
+{
+    GError     *g_error = NULL;
+    DBusGProxy *dbus_proxy;
+    int         success = FALSE;
+
+    dbus_proxy = get_dbus_proxy (error);
+
+    if (*error != NULL)
+        return FALSE;
 
+    g_return_if_fail (DBUS_IS_G_PROXY (dbus_proxy));
 
-    /**
-     * Returns the default identity - most recently used.
-     *
-     * @param nai_out NAI stored in the ID card
-     * @param password_out Password stored in the ID card
-     *
-     * @return true on success, false if no identities are stored
-     */
+    dbus_g_proxy_call (dbus_proxy,
+                       "GetDefaultIdentity",
+                       &g_error,
+                       G_TYPE_INVALID,
+                       G_TYPE_STRING, nai_out,
+                       G_TYPE_STRING, password_out,
+                       G_TYPE_STRING, server_certificate_hash_out,
+                       G_TYPE_STRING, ca_certificate_out,
+                       G_TYPE_STRING, subject_name_constraint_out,
+                       G_TYPE_STRING, subject_alt_name_constraint_out,
+                       G_TYPE_BOOLEAN, &success,
+                       G_TYPE_INVALID);
+
+    g_object_unref (dbus_proxy);
+
+    if (g_error != NULL) {
+        *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
+                                     g_error->message);
+        return FALSE;
+    }
+
+    if (success == FALSE) {
+        *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED,
+                                     "No identity was returned by the Moonshot "
+                                     "user interface.");
+        return FALSE;
+    }
+
+    return TRUE;
+}
index 65924b7..2429314 100644 (file)
@@ -55,10 +55,10 @@ void moonshot_error_free (MoonshotError *error);
  * @password: Password for the identity, or %NULL.
  * @service: Service constraint for the required identity, or %NULL.
  * @nai_out: A pointer to a string which receives the name and issuer of the
- *       selected identity.
+ *           selected identity.
  * @password_out: A pointer to a string which receives the password.
  * @server_certificate_hash_out: Receives a hash of the identity server's
- *                           certificate, or %NULL.
+ *                               certificate, or %NULL.
  * @ca_certificate_out: The CA certificate, if @server_certificate_hash was
  *                      %NULL.
  * @subject_name_constraint_out: Set if @ca_certificate is set, otherwise %NULL.
@@ -94,4 +94,32 @@ int moonshot_get_identity (const char     *nai,
                            char          **subject_alt_name_constraint_out,
                            MoonshotError **error);
 
+/**
+ * moonshot_get_default_identity:
+ * @nai_out: A pointer to a string which receives the name and issuer of the
+ *           identity.
+ * @password_out: A pointer to a string which receives the password.
+ * @server_certificate_hash_out: Receives a hash of the identity server's
+ *                               certificate, or %NULL.
+ * @ca_certificate_out: The CA certificate, if @server_certificate_hash was
+ *                      %NULL.
+ * @subject_name_constraint_out: Set if @ca_certificate is set, otherwise %NULL.
+ * @subject_alt_name_constraint_out: Set if @ca_certificate is set, otherwise
+ *                                   %NULL.
+ * @error: Return location for a #MoonshotError, or %NULL.
+ *
+ * This function calls the Moonshot server to request the default identity
+ * (the one most recently used). Its semantics are otherwise the same as
+ * moonshot_get_identity().
+ *
+ * Return value: %TRUE if an identity was available, otherwise %FALSE.
+ */
+int moonshot_default_get_identity (char          **nai_out,
+                                   char          **password_out,
+                                   char          **server_certificate_hash_out,
+                                   char          **ca_certificate_out,
+                                   char          **subject_name_constraint_out,
+                                   char          **subject_alt_name_constraint_out,
+                                   MoonshotError **error);
+
 #endif
index de30262..3844eef 100644 (file)
@@ -3,7 +3,8 @@ interface Moonshot : Object {
     public abstract bool get_identity (string nai, string password, string service,
                                        out string nai_out, out string password_out,
                                        out string server_certificate_hash, out string ca_certificate, out string subject_name_constraint, out string subject_alt_name_constraint) throws DBus.Error;
-    public abstract bool get_default_identity (out string nai_out, out string password_out) throws DBus.Error;
+    public abstract bool get_default_identity (out string nai_out, out string password_out,
+                                               out string server_certificate_hash, out string ca_certificate, out string subject_name_constraint, out string subject_alt_name_constraint) throws DBus.Error;
 }
 
 void main () {
@@ -16,7 +17,12 @@ void main () {
                                                "/org/janet/moonshot");
 
 
-        if (demo.get_default_identity (out nai_out, out password_out))
+        if (demo.get_default_identity (out nai_out,
+                                       out password_out,
+                                       out certificate_out,
+                                       out a,
+                                       out b,
+                                       out c))
         {
             stdout.printf ("default identity: %s %s\n", nai_out, password_out);
         }
index f83d5ea..145d6bf 100644 (file)
@@ -54,7 +54,11 @@ public class MoonshotServer : Object {
     }
 
     public async bool get_default_identity (out string nai_out,
-                                            out string password_out)
+                                            out string password_out,
+                                            out string server_certificate_hash,
+                                            out string ca_certificate,
+                                            out string subject_name_constraint,
+                                            out string subject_alt_name_constraint)
     {
         var request = new IdentityRequest.default (main_window);
         request.set_callback ((IdentityRequest) => get_default_identity.callback());
@@ -63,12 +67,18 @@ public class MoonshotServer : Object {
 
         nai_out = "";
         password_out = "";
+        server_certificate_hash = "";
+        ca_certificate = "";
+        subject_name_constraint = "";
+        subject_alt_name_constraint = "";
 
         if (request.id_card != null)
         {
             nai_out = request.id_card.nai;
             password_out = request.id_card.password;
 
+            server_certificate_hash = "certificate";
+
             // User should have been prompted if there was no p/w.
             return_val_if_fail (nai_out != null, false);
             return_val_if_fail (password_out != null, false);
index 8bd09a0..0d1e127 100644 (file)
@@ -2,32 +2,79 @@
 
 #include "libmoonshot.h"
 
-void test_connect ()
+/* FIXME: Using XDG_HOME_DIR and a test runner, we could give
+ * moonshot-ui a set of test identities and assert that they
+ * are returned correctly
+ */
+
+gpointer test_func (gpointer data)
 {
+    MoonshotError **error = data;
+    gboolean        success;
+
     char *nai,
          *password,
          *server_certificate_hash,
          *ca_certificate,
          *subject_name_constraint,
          *subject_alt_name_constraint;
-    int success;
+
+    success = moonshot_get_default_identity (&nai,
+                                             &password,
+                                             &server_certificate_hash,
+                                             &ca_certificate,
+                                             &subject_name_constraint,
+                                             &subject_alt_name_constraint,
+                                             error);
+
+    g_print ("Got id: %s %s\n", nai, password);
+
+    return GINT_TO_POINTER (success);
+}
+
+
+void test_connect ()
+{
     MoonshotError *error = NULL;
+    gboolean       success;
+
+    success = GPOINTER_TO_INT (test_func (&error));
+
+    if (success)
+        return;
+
+    g_print ("FAIL: %s\n", error->message);
+    g_assert_not_reached ();
+}
+
+void test_multithread ()
+{
+    const int N = 100;
+
+    GThread       *thread[N];
+    MoonshotError *error[N];
+    gboolean       success[N];
+
+    GError *g_error = NULL;
+    int i;
+
+    for (i=0; i<N; i++) {
+        error[i] = NULL;
+        thread[i] = g_thread_create (test_func,
+                                     &error[i],
+                                     TRUE,
+                                     &g_error);
+        g_assert_no_error (g_error);
+    }
+
+    for (i=0; i<N; i++)
+        success[i] = GPOINTER_TO_INT (g_thread_join (thread[i]));
 
-    success = moonshot_get_identity ("test",
-                                     "test",
-                                     "test",
-                                     &nai,
-                                     &password,
-                                     &server_certificate_hash,
-                                     &ca_certificate,
-                                     &subject_name_constraint,
-                                     &subject_alt_name_constraint,
-                                     &error);
-
-    if (success == 0) {
-        g_print ("FAIL %s\n", error->message);
-    } else {
-        g_print ("PASS\n");
+    for (i=0; i<N; i++) {
+        if (! success[i]) {
+            g_print ("FAIL[%i]: %s\n", i, error[i]->message);
+            g_assert_not_reached ();
+        }
     }
 }
 
@@ -35,6 +82,7 @@ void test_connect ()
  *   - server not available (dbus fail)
  *   - no identities available (moonshot fail)
  *   - valgrind
+ *   - mt
  */
 
 int main (int argc, char *argv[])
@@ -43,6 +91,7 @@ int main (int argc, char *argv[])
     g_test_init (&argc, &argv, NULL);
 
     g_test_add_func ("/basic/connect", test_connect);
+    g_test_add_func ("/basic/multithread", test_multithread);
 
     g_test_run ();
 }