Blob Blame History Raw
From 95b3cb3c134e5afc4f9b6f805aa65db6f46d966f Mon Sep 17 00:00:00 2001
From: "Zeeshan Ali (Khattak)" <zeeshanak@gnome.org>
Date: Wed, 19 Nov 2014 00:46:51 +0000
Subject: [PATCH] Private SPICE connection

This is a squash of all patches that:

* connect to local VMs through FD.
* add TCP-less SPICE device to new VMs.

https://bugzilla.gnome.org/show_bug.cgi?id=738573
---
 src/display.vala                    |  6 ++++--
 src/libvirt-machine-properties.vala |  2 +-
 src/libvirt-machine.vala            | 27 ++++++++++++++++++++++-----
 src/spice-display.vala              | 28 ++++++++++++++++++++++++----
 src/vm-configurator.vala            | 18 ++++++++++++++----
 src/vnc-display.vala                |  4 ++--
 6 files changed, 67 insertions(+), 18 deletions(-)

diff --git a/src/display.vala b/src/display.vala
index ffe1b0e..ba06ef0 100644
--- a/src/display.vala
+++ b/src/display.vala
@@ -3,7 +3,7 @@
 
 private abstract class Boxes.Display: GLib.Object, Boxes.IPropertiesProvider {
     public abstract string protocol { get; }
-    public abstract string uri { owned get; }
+    public abstract string? uri { owned get; }
 
     public BoxConfig? config { get; set; }
     public bool can_grab_mouse { get; protected set; }
@@ -19,6 +19,8 @@
     public signal void disconnected (bool connection_failed);
     public signal void got_error (string message);
 
+    public delegate int OpenFDFunc ();
+
     public abstract Gtk.Widget get_display (int n);
     public abstract Gdk.Pixbuf? get_pixbuf (int n) throws Boxes.Error;
     public abstract void set_enable_inputs (Gtk.Widget widget, bool enable);
@@ -28,7 +30,7 @@ public virtual bool should_keep_alive () {
         return false;
     }
 
-    public abstract void connect_it () throws GLib.Error;
+    public abstract void connect_it (OpenFDFunc? open_fd = null) throws GLib.Error;
     public abstract void disconnect_it ();
 
     public virtual void collect_logs (StringBuilder builder) {
diff --git a/src/libvirt-machine-properties.vala b/src/libvirt-machine-properties.vala
index 657875a..9dd2b3c 100644
--- a/src/libvirt-machine-properties.vala
+++ b/src/libvirt-machine-properties.vala
@@ -131,7 +131,7 @@ private string collect_logs () {
             });
 
             add_string_property (ref list, _("Virtualizer"), machine.source.uri);
-            if (machine.display != null)
+            if (machine.display != null && machine.display.uri != null)
                 property = add_string_property (ref list, _("URI"), machine.display.uri);
             break;
 
diff --git a/src/libvirt-machine.vala b/src/libvirt-machine.vala
index 22532b6..d22b664 100644
--- a/src/libvirt-machine.vala
+++ b/src/libvirt-machine.vala
@@ -48,7 +48,20 @@ public override async void connect_display (Machine.ConnectFlags flags) throws G
         }
 
         if (update_display ()) {
-            display.connect_it ();
+            Display.OpenFDFunc? open_fd = null;
+
+            if (source.uri.has_prefix ("qemu+unix"))
+                open_fd = () => {
+                    try {
+                        return domain.open_graphics_fd (0, 0);
+                    } catch (GLib.Error error) {
+                        critical ("Failed to open graphics for %s: %s", name, error.message);
+
+                        return -1;
+                    }
+                };
+
+            display.connect_it (open_fd);
         } else {
             show_display ();
             display.set_enable_audio (true);
@@ -337,23 +350,27 @@ public bool update_display () throws GLib.Error {
     }
 
     private Display? create_display () throws Boxes.Error {
-        string type, port, socket, host;
+        string type, port_str, socket, host;
 
         var xmldoc = domain_config.to_xml ();
         type = extract_xpath (xmldoc, "string(/domain/devices/graphics/@type)", true);
-        port = extract_xpath (xmldoc, @"string(/domain/devices/graphics[@type='$type']/@port)");
+        port_str = extract_xpath (xmldoc, @"string(/domain/devices/graphics[@type='$type']/@port)");
         socket = extract_xpath (xmldoc, @"string(/domain/devices/graphics[@type='$type']/@socket)");
         host = extract_xpath (xmldoc, @"string(/domain/devices/graphics[@type='$type']/@listen)");
+        var port = int.parse (port_str);
 
         if (host == null || host == "")
             host = "localhost";
 
         switch (type) {
         case "spice":
-            return new SpiceDisplay (this, config, host, int.parse (port));
+            if (port > 0)
+                return new SpiceDisplay (this, config, host, port);
+            else
+                return new SpiceDisplay.priv (this, config);
 
         case "vnc":
-            return new VncDisplay (config, host, int.parse (port));
+            return new VncDisplay (config, host, port);
 
         default:
             throw new Boxes.Error.INVALID ("unsupported display of type " + type);
diff --git a/src/spice-display.vala b/src/spice-display.vala
index da97e5a..485d561 100644
--- a/src/spice-display.vala
+++ b/src/spice-display.vala
@@ -4,7 +4,7 @@
 
 private class Boxes.SpiceDisplay: Boxes.Display {
     public override string protocol { get { return "SPICE"; } }
-    public override string uri { owned get { return session.uri; } }
+    public override string? uri { owned get { return session.uri; } }
     public GLib.ByteArray ca_cert { owned get { return session.ca; } set { session.ca = value; } }
 
     private weak Machine machine; // Weak ref for avoiding cyclic ref
@@ -124,6 +124,15 @@ public SpiceDisplay (Machine machine, BoxConfig config, string host, int port, i
         session.uri = uri;
     }
 
+    public SpiceDisplay.priv (Machine machine, BoxConfig config) {
+        this.machine = machine;
+        machine.notify["ui-state"].connect (ui_state_changed);
+
+        this.config = config;
+
+        config.sync_properties (gtk_session, gtk_session_sync_properties);
+    }
+
     public override Gtk.Widget get_display (int n) {
         var display = displays.lookup (n) as Spice.Display;
 
@@ -204,7 +213,7 @@ public override void collect_logs (StringBuilder builder) {
         }
     }
 
-    public override void connect_it () {
+    public override void connect_it (Display.OpenFDFunc? open_fd = null) {
         // We only initiate connection once
         if (connected)
             return;
@@ -212,11 +221,19 @@ public override void connect_it () {
 
         main_cleanup ();
 
-        // FIXME: vala does't want to put this in ctor..
+        // FIXME: vala does't want to put this in constructor..
         if (channel_new_id == 0)
             channel_new_id = session.channel_new.connect ((channel) => {
                 var id = channel.channel_id;
 
+                if (open_fd != null)
+                    channel.open_fd.connect (() => {
+                        int fd;
+
+                        fd = open_fd ();
+                        channel.open_fd (fd);
+                    });
+
                 if (channel is Spice.MainChannel) {
                     main_channel = channel as Spice.MainChannel;
                     main_event_id = main_channel.channel_event.connect (main_event);
@@ -251,7 +268,10 @@ public override void connect_it () {
             });
 
         session.password = password;
-        session.connect ();
+        if (open_fd != null)
+            session.open_fd (-1);
+        else
+            session.connect ();
     }
 
     public override void disconnect_it () {
diff --git a/src/vm-configurator.vala b/src/vm-configurator.vala
index 6b8f9c6..0e567c0 100644
--- a/src/vm-configurator.vala
+++ b/src/vm-configurator.vala
@@ -68,10 +68,7 @@ public static Domain create_domain_config (InstallerMedia install_media, string
         set_target_media_config (domain, target_path, install_media);
         install_media.setup_domain_config (domain);
 
-        var graphics = new DomainGraphicsSpice ();
-        graphics.set_autoport (true);
-        graphics.set_image_compression (DomainGraphicsSpiceImageCompression.OFF);
-        domain.add_device (graphics);
+        add_graphics_device (domain);
 
         // SPICE agent channel. This is needed for features like copy&paste between host and guest etc to work.
         var channel = new DomainChannel ();
@@ -245,9 +242,12 @@ public static async void update_existing_domain (Domain          domain,
         // First remove user and 'network' (used by system libvirt machines) interface device
         GLib.List<GVirConfig.DomainDevice> devices = null;
         DomainInterface iface = null;
+        DomainGraphicsSpice graphics = null;
         foreach (var device in domain.get_devices ()) {
             if (device is DomainInterfaceUser || device is DomainInterfaceNetwork)
                 iface = device as DomainInterface;
+            else if (device is DomainGraphicsSpice)
+                graphics = device as DomainGraphicsSpice;
             else
                 devices.prepend (device);
         }
@@ -259,6 +259,9 @@ public static async void update_existing_domain (Domain          domain,
             var virtio = iface.get_model () == "virtio";
             add_network_interface (domain, true, virtio);
         }
+
+        if (graphics != null)
+            add_graphics_device (domain);
     }
 
     public static void set_target_media_config (Domain         domain,
@@ -468,6 +471,13 @@ public static void add_network_interface (Domain domain, bool bridge, bool virti
         domain.add_device (iface);
     }
 
+    public static void add_graphics_device (Domain domain) {
+        var graphics = new DomainGraphicsSpice ();
+        graphics.set_autoport (false);
+        graphics.set_image_compression (DomainGraphicsSpiceImageCompression.OFF);
+        domain.add_device (graphics);
+    }
+
     private static DomainControllerUsb create_usb_controller (DomainControllerUsbModel model,
                                                               DomainControllerUsb?     master = null,
                                                               uint                     index = 0,
diff --git a/src/vnc-display.vala b/src/vnc-display.vala
index 67213ff..ccf3973 100644
--- a/src/vnc-display.vala
+++ b/src/vnc-display.vala
@@ -4,7 +4,7 @@
 
 private class Boxes.VncDisplay: Boxes.Display {
     public override string protocol { get { return "VNC"; } }
-    public override string uri { owned get { return @"vnc://$host:$port"; } }
+    public override string? uri { owned get { return @"vnc://$host:$port"; } }
     private Vnc.Display display;
     private string host;
     private int port;
@@ -114,7 +114,7 @@ public override void set_enable_inputs (Gtk.Widget widget, bool enable) {
         return display.get_pixbuf ();
     }
 
-    public override void connect_it () throws GLib.Error {
+    public override void connect_it (Display.OpenFDFunc? open_fd = null) throws GLib.Error {
         // We only initiate connection once
         if (connected)
             return;
-- 
2.5.5