Handle concurrent identity requests correctly
[moonshot-ui.git] / src / moonshot-msrpc-server.vala
1 using Rpc;
2 using MoonshotRpcInterface;
3
4 /* This class must be a singleton, because we use a global RPC
5  * binding handle. I cannot picture a situation where more than
6  * one instance of the same interface would be needed so this
7  * shouldn't be a problem.
8  *
9  * Shutdown is automatically done by the RPC runtime when the
10  * process ends
11  */
12 public class MoonshotServer : Object {
13     private static MainWindow main_window;
14
15     private static MoonshotServer instance = null;
16
17     public static void start (Gtk.Window window)
18     {
19         main_window = (MainWindow) window;
20         Rpc.server_start (MoonshotRpcInterface.spec, "/org/janet/Moonshot");
21     }
22
23     public static MoonshotServer get_instance ()
24     {
25         if (instance == null)
26             instance = new MoonshotServer ();
27         return instance;
28     }
29
30     [CCode (cname = "moonshot_get_identity")]
31     public static void moonshot_get_identity (Rpc.AsyncCall call,
32                                               string nai,
33                                               string password,
34                                               string service,
35                                               ref string nai_out,
36                                               ref string password_out,
37                                               ref string certificate_out)
38     {
39         bool result = false;
40         Mutex mutex = new Mutex ();
41         Cond cond = new Cond ();
42
43         mutex.lock ();
44
45         var request = new IdentityRequest (main_window,
46                                            nai,
47                                            password,
48                                            service);
49
50         // Pass execution to the main loop and block the RPC thread
51         request.set_data ("mutex", mutex);
52         request.set_data ("cond", cond);
53         request.set_return_identity_callback (this.return_identity_cb);
54         Idle.add (request.execute);
55
56         while (request.complete == false)
57             cond.wait (mutex);
58
59         nai_out = "";
60         password_out = "";
61         certificate_out = "";
62
63         var id_card = request.id_card;
64
65         if (id_card == null) {
66             foreach (string id_card_service in id_card.services)
67             {
68                 if (id_card_service == service)
69                     has_service = true;
70             }
71
72             if (has_service)
73             {
74                 // The strings are freed by the RPC runtime
75                 nai_out = id_card.nai;
76                 password_out = id_card.password;
77                 certificate_out = "certificate";
78
79                 result = true;
80             }
81         }
82
83         // The outputs must be set before this function is called. For this
84         // reason they are 'ref' not 'out' parameters - Vala assigns to the
85         // 'out' parameters only at the end of the function, which is too
86         // late.
87         call.return (&result);
88
89         cond.signal ();
90         mutex.unlock ();
91     }
92
93     // Called from the main loop thread when an identity has
94     // been selected
95     public void return_identity_cb (IdentityRequest request) {
96         Mutex mutex = request.get_data ("mutex");
97         Cond cond = request.get_data ("cond");
98
99         // Notify the RPC thread that the request is complete
100         mutex.lock ();
101         cond.signal ();
102
103         // Block the main loop until the RPC call has returned
104         // to avoid any races
105         cond.wait (mutex);
106         mutex.unlock ();
107     }
108 }