Use MS RPC server on Windows
authorSam Thursfield <samthursfield@codethink.co.uk>
Tue, 17 May 2011 18:12:46 +0000 (19:12 +0100)
committerSam Thursfield <samthursfield@codethink.co.uk>
Fri, 20 May 2011 13:58:50 +0000 (14:58 +0100)
Makefile.am
configure.ac
src/moonshot-msrpc-server.vala [new file with mode: 0644]
src/moonshot-msrpc.acf [new file with mode: 0644]
src/moonshot-msrpc.idl [new file with mode: 0644]
src/moonshot-msrpc.vapi [new file with mode: 0644]
src/moonshot-window.vala

index c50e3d2..f5dac9d 100644 (file)
@@ -2,8 +2,7 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
 
 SUBDIRS = po
 
-bin_PROGRAMS = src/moonshot src/dbus-client
-
+bin_PROGRAMS = src/moonshot
 
 AM_CPPFLAGS = \
        -include config.h \
@@ -12,22 +11,57 @@ AM_CPPFLAGS = \
 
 AM_VALAFLAGS = \
        config.vapi \
-       --pkg gtk+-2.0 --pkg dbus-glib-1
+       --pkg gtk+-2.0
 
 src_moonshot_SOURCES = \
         src/moonshot-id.vala \
         src/moonshot-add-dialog.vala \
         src/moonshot-idcard-widget.vala \
         src/moonshot-custom-vbox.vala \
-       src/moonshot-identities-manager.vala \
-        src/moonshot-dbus-server.vala \
+        src/moonshot-identities-manager.vala \
         src/moonshot-window.vala
 
-src_dbus_client_SOURCES = \
-        src/dbus-client.vala
-
 src_moonshot_LDADD = \
         $(moonshot_LIBS)
 
+if IPC_MSRPC
+
+AM_CPPFLAGS += -Isrc
+
+AM_VALAFLAGS += \
+       --pkg msrpc-1.0 \
+       --define=IPC_MSRPC
+
+noinst_HEADERS = src/moonshot-msrpc.h
+
+src_moonshot_SOURCES += \
+        src/moonshot-msrpc-server.vala \
+        src/moonshot-msrpc_s.c \
+        src/moonshot-msrpc.vapi
+
+BUILT_SOURCES = src/moonshot-msrpc.h src/moonshot-msrpc_s.c src/moonshot-msrpc_c.c
+
+DISTCLEANFILES = ${BUILT_SOURCES}
+
+src/moonshot-msrpc.h: src/moonshot-msrpc.idl src/moonshot-msrpc.acf
+       ${AM_V_GEN} ${MIDL_WRAPPER} -o src -m "${MIDL}" $^
+
+src/moonshot-msrpc_s.c: src/moonshot-msrpc.h
+
+else
+
+# IPC_DBUS
+
+AM_VALAFLAGS += --pkg dbus-glib-1
+
+src_moonshot_SOURCES += src/moonshot-dbus-server.vala
+
+bin_PROGRAMS += src/dbus-client
+
+src_dbus_client_SOURCES = \
+        src/dbus-client.vala
+
 src_dbus_client_LDADD = \
         $(moonshot_LIBS)
+
+endif
index 6f361e4..8f51dbf 100644 (file)
@@ -17,13 +17,43 @@ AC_PROG_CC
 AM_PROG_CC_C_O
 AM_PROG_VALAC([0.9])
 
+# Platform-specific checks
+AC_CANONICAL_HOST
+
+case "$host" in
+  *-*-mingw*)
+    AC_PATH_MSRPC_MINGW([0.1.0], :,
+      AC_MSG_ERROR([
+*** msrpc-mingw 0.1.0 or better is required.]))
+
+
+    AC_PATH_PROG([MIDL], [midl], no)
+    if test "$MIDL" = "no"; then
+       AC_MSG_ERROR([
+*** Could not find the Microsoft interface compiler MIDL.EXE.
+*** This program is available as part of the MS Windows SDK, in
+*** the Win32 Development Tools package.])
+    fi
+
+    IPC="msrpc-glib2-1.0"
+    ;;
+  *)
+    IPC="dbus-glib"
+    ;;
+esac
+
+AC_SUBST(MIDL)
+
+AM_CONDITIONAL([IPC_MSRPC], [test "$IPC" = "msrpc-glib2-1.0"])
+AM_CONDITIONAL([IPC_DBUS], [test "$IPC" = "dbus-glib"])
+
 # Dependencies
 PKG_CHECK_MODULES(moonshot,[
         atk >= 1.20
         glib-2.0 >= 2.24
         gobject-2.0 >= 2.24
         gtk+-2.0 >= 2.20
-        dbus-glib-1
+        $IPC
 ])
 
 # i18n stuff
diff --git a/src/moonshot-msrpc-server.vala b/src/moonshot-msrpc-server.vala
new file mode 100644 (file)
index 0000000..ff718d2
--- /dev/null
@@ -0,0 +1,101 @@
+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
+ * shouldn't be a problem.
+ *
+ * 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;
+
+    public static void start (Gtk.Window window)
+    {
+        main_window = (MainWindow) window;
+        Rpc.server_start (MoonshotRpcInterface.spec, "/org/janet/Moonshot");
+    }
+
+    public static MoonshotServer get_instance ()
+    {
+        if (instance == null)
+            instance = new MoonshotServer ();
+        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)
+    {
+        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);
+    }
+}
diff --git a/src/moonshot-msrpc.acf b/src/moonshot-msrpc.acf
new file mode 100644 (file)
index 0000000..af441f2
--- /dev/null
@@ -0,0 +1,9 @@
+[
+  implicit_handle (handle_t moonshot_binding_handle)
+
+]
+interface moonshot
+{
+       [async] moonshot_get_identity();
+}
+
diff --git a/src/moonshot-msrpc.idl b/src/moonshot-msrpc.idl
new file mode 100644 (file)
index 0000000..7174418
--- /dev/null
@@ -0,0 +1,20 @@
+[
+    uuid(15aea4d8-222c-4b42-9225-63a7277811ae),
+    version(1.0)
+]
+interface moonshot
+{
+    int moonshot_ping ([in, string] const char *message);
+
+    /* The DBus API returns the 3 output parameters as an array. MSRPC
+     * and Vala combine to make this very difficult; easier to use
+     * output parameters.
+     */
+    void moonshot_get_identity ([in, string] const char *in_identity,
+                                [in, string] const char *in_password,
+                                [in, string] const char *in_service,
+                                [out, string] char **out_identity,
+                                [out, string] char **out_password,
+                                [out, string] char **out_service);
+}
+
diff --git a/src/moonshot-msrpc.vapi b/src/moonshot-msrpc.vapi
new file mode 100644 (file)
index 0000000..a346883
--- /dev/null
@@ -0,0 +1,24 @@
+/* Binding between the MIDL-generated C code for the RPC interface and Vala */
+
+using Rpc;
+
+[CCode (cheader_filename = "moonshot-msrpc.h")]
+
+namespace MoonshotRpcInterface {
+    [CCode (cname = "moonshot_v1_0_s_ifspec")]
+    public const InterfaceHandle spec;
+
+    [CCode (cname = "moonshot_binding_handle")]
+    public BindingHandle binding_handle;
+
+    [CCode (cname = "moonshot_ping")]
+    public int ping (string message);
+
+    [CCode (cname = "moonshot_get_message")]
+    public void moonshot_get_identity (string in_identity,
+                                       string in_password,
+                                       string in_service,
+                                       char **out_identity,
+                                       char **out_password,
+                                       char **out_service);
+}
index 2eb7d28..463c2cc 100644 (file)
@@ -19,7 +19,7 @@ class MainWindow : Window
 
     private IdentitiesManager identities_manager;
 
-    private MoonshotServer dbus_server;
+    private MoonshotServer ipc_server;
 
     public IdCardWidget selected_id_card_widget;
 
@@ -61,7 +61,7 @@ class MainWindow : Window
         load_gss_eap_id_file();
         //load_id_cards();
         connect_signals();
-        init_dbus_server();
+        init_ipc_server();
     }
 
     private bool visible_func (TreeModel model, TreeIter iter)
@@ -617,8 +617,15 @@ class MainWindow : Window
         this.destroy.connect (Gtk.main_quit);
     }
 
-    private void init_dbus_server ()
+    private void init_ipc_server ()
     {
+#if IPC_MSRPC
+        /* Errors will currently be sent via g_log - ie. to an
+         * obtrusive message box, on Windows
+         */
+        this.ipc_server = MoonshotServer.get_instance ();
+        MoonshotServer.start (this);
+#else
         try {
             var conn = DBus.Bus.get (DBus.BusType.SESSION);
             dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus",
@@ -629,14 +636,15 @@ class MainWindow : Window
             uint reply = bus.request_name ("org.janet.Moonshot", (uint) 0);
             assert (reply == DBus.RequestNameReply.PRIMARY_OWNER);
 
-            this.dbus_server = new MoonshotServer (this);
-            conn.register_object ("/org/janet/moonshot", dbus_server);
+            this.ipc_server = new MoonshotServer (this);
+            conn.register_object ("/org/janet/moonshot", ipc_server);
 
         }
         catch (DBus.Error e)
         {
             stderr.printf ("%s\n", e.message);
         }
+#endif
     }
 
     public static int main(string[] args)