Handle concurrent identity requests correctly
[moonshot-ui.git] / src / moonshot-msrpc-server.vala
index 660f0e6..5aa3a6e 100644 (file)
@@ -1,58 +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.
- */
-/* Fixme: can you make *this* an async callback? */
-public class IdentityRequest : Object {
-    private MainWindow main_window;
-    private Identity **result;
-    private unowned Mutex mutex;
-    private unowned Cond cond;
-
-    public IdentityRequest (Gtk.Window window,
-                            Identity **_result,
-                            Mutex _mutex,
-                            Cond _cond)
-    {
-        main_window = (MainWindow)window;
-        result = _result;
-        mutex = _mutex;
-        cond = _cond;
-    }
-
-    public bool main_loop_cb ()
-    {
-        // Execution is passed from the RPC get_identity() call to
-        // here, where we are inside the main loop thread.
-        main_window.set_callback (this.id_card_selected_cb);
-        return false;
-    }
-
-    public bool id_card_selected_cb ()
-    {
-        var id_card = this.main_window.selected_id_card_widget.id_card;
-
-        mutex.lock ();
-        *result = new Identity();
-
-        (*result)->identity = "identity";
-        (*result)->password = id_card.password;
-        (*result)->service = "certificate";
-
-        print ("Result %x, *%x - strs %x, %x, %x\n", (uint)result, (uint)(*result), (uint)((*result)->identity), (uint)((*result)->password), (uint)((*result)->service));
-
-        cond.signal ();
-        mutex.unlock ();
-
-        // 'result' is freed by the RPC runtime
-
-        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
@@ -62,7 +10,6 @@ public class IdentityRequest : Object {
  * process ends
  */
 public class MoonshotServer : Object {
-    private static int counter;
     private static MainWindow main_window;
 
     private static MoonshotServer instance = null;
@@ -80,39 +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,
-                                              Identity **result)
+                                              string nai,
+                                              string password,
+                                              string service,
+                                              ref string nai_out,
+                                              ref string password_out,
+                                              ref string certificate_out)
     {
+        bool result = false;
         Mutex mutex = new Mutex ();
         Cond cond = new Cond ();
 
         mutex.lock ();
 
-        *result = null;
-        IdentityRequest request = new IdentityRequest (main_window, result, mutex, cond);
+        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);
 
-        // Pass execution to the main loop thread and wait for
-        // the 'send' action to be signalled.
-        Idle.add (request.main_loop_cb);
-        while (*result == null)
+        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");
 
-        call.return (null);
+        // 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 ();
     }
 }