Handle concurrent identity requests correctly
[moonshot-ui.git] / src / moonshot-msrpc-server.vala
index ff718d2..5aa3a6e 100644 (file)
@@ -1,46 +1,6 @@
 using Rpc;
 using MoonshotRpcInterface;
 
-/* This class is the closure when we pass execution from the RPC thread
- * to the GLib main loop thread; we need to be executing inside the main
- * loop before we can access any state or make any Gtk+ calls.
- */
-public class IdentityRequest : Object {
-    private Rpc.AsyncCall call;
-    private MainWindow main_window;
-    private char **p_identity;
-    private char **p_password;
-    private char **p_service;
-
-    public IdentityRequest (Rpc.AsyncCall _call,
-                            Gtk.Window window,
-                            char **_p_identity,
-                            char **_p_password,
-                            char **_p_service)
-    {
-        call = _call;
-        p_identity = _p_identity;
-        p_password = _p_password;
-        p_service = _p_service;
-    }
-
-    public bool main_loop_cb ()
-    {
-        main_window.set_callback (id_card_selected_cb);
-        return false;
-    }
-
-    public bool id_card_selected_cb ()
-    {
-        var id_card = this.main_window.selected_id_card_widget.id_card;
-
-        *p_identity = "identity";
-        *p_password = id_card.password;
-        *p_service = "certificate";
-        return false;
-    }
-}
-
 /* This class must be a singleton, because we use a global RPC
  * binding handle. I cannot picture a situation where more than
  * one instance of the same interface would be needed so this
@@ -49,9 +9,7 @@ public class IdentityRequest : Object {
  * Shutdown is automatically done by the RPC runtime when the
  * process ends
  */
-
 public class MoonshotServer : Object {
-    private static int counter;
     private static MainWindow main_window;
 
     private static MoonshotServer instance = null;
@@ -69,33 +27,82 @@ public class MoonshotServer : Object {
         return instance;
     }
 
-    /* Note that these RPC callbacks execute outside the GLib main loop,
-     * in threads owned by the RPC runtime
-     */
-
-    [CCode (cname = "moonshot_ping")]
-    public static int ping (string msg)
-    {
-        stdout.printf ("%s\n", msg);
-        return counter ++;
-    }
-
     [CCode (cname = "moonshot_get_identity")]
     public static void moonshot_get_identity (Rpc.AsyncCall call,
-                                              string in_identity,
-                                              string in_password,
-                                              string in_service,
-                                              char **out_identity,
-                                              char **out_password,
-                                              char **out_service)
+                                              string nai,
+                                              string password,
+                                              string service,
+                                              ref string nai_out,
+                                              ref string password_out,
+                                              ref string certificate_out)
     {
-        IdentityRequest request = new IdentityRequest (call,
-                                                       main_window,
-                                                       out_identity,
-                                                       out_password,
-                                                       out_service);
-
-        // Pass execution to the main loop thread
-        Idle.add (request.main_loop_cb);
+        bool result = false;
+        Mutex mutex = new Mutex ();
+        Cond cond = new Cond ();
+
+        mutex.lock ();
+
+        var request = new IdentityRequest (main_window,
+                                           nai,
+                                           password,
+                                           service);
+
+        // Pass execution to the main loop and block the RPC thread
+        request.set_data ("mutex", mutex);
+        request.set_data ("cond", cond);
+        request.set_return_identity_callback (this.return_identity_cb);
+        Idle.add (request.execute);
+
+        while (request.complete == false)
+            cond.wait (mutex);
+
+        nai_out = "";
+        password_out = "";
+        certificate_out = "";
+
+        var id_card = request.id_card;
+
+        if (id_card == null) {
+            foreach (string id_card_service in id_card.services)
+            {
+                if (id_card_service == service)
+                    has_service = true;
+            }
+
+            if (has_service)
+            {
+                // The strings are freed by the RPC runtime
+                nai_out = id_card.nai;
+                password_out = id_card.password;
+                certificate_out = "certificate";
+
+                result = true;
+            }
+        }
+
+        // The outputs must be set before this function is called. For this
+        // reason they are 'ref' not 'out' parameters - Vala assigns to the
+        // 'out' parameters only at the end of the function, which is too
+        // late.
+        call.return (&result);
+
+        cond.signal ();
+        mutex.unlock ();
+    }
+
+    // Called from the main loop thread when an identity has
+    // been selected
+    public void return_identity_cb (IdentityRequest request) {
+        Mutex mutex = request.get_data ("mutex");
+        Cond cond = request.get_data ("cond");
+
+        // Notify the RPC thread that the request is complete
+        mutex.lock ();
+        cond.signal ();
+
+        // Block the main loop until the RPC call has returned
+        // to avoid any races
+        cond.wait (mutex);
+        mutex.unlock ();
     }
 }