Merge pull request #2980 from danilo-delbusso/bug/rdp-gray_CA-322672

CA-322672: Do not stop polling for RDP capabilities on VMs
This commit is contained in:
Konstantina Chremmou 2022-05-09 15:15:39 +01:00 committed by GitHub
commit d0fdc5360b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 153 additions and 156 deletions

View File

@ -78,17 +78,17 @@ namespace XenAdmin.ConsoleView
/// Whether to ignore VNC resize events. We turn this on when changing
/// the scaling settings, because this in turn triggers a VNC resize.
/// </summary>
private bool ignoringResizes = false;
private bool ignoringResizes;
private bool ignoreScaleChange = false;
private bool ignoreScaleChange;
internal readonly ConsoleKeyHandler KeyHandler = new ConsoleKeyHandler();
private bool hasRDP { get { return source != null && source.HasRDP(); } }
private bool HasRDP => source != null && source.HasRDP();
private bool RDPEnabled { get { return source != null && source.RDPEnabled(); } }
private bool RDPEnabled => source != null && source.RDPEnabled();
private bool RDPControlEnabled { get { return source != null && source.RDPControlEnabled(); } }
private bool RDPControlEnabled => source != null && source.RDPControlEnabled();
public bool IsRDPControlEnabled() { return RDPControlEnabled; }
@ -113,11 +113,11 @@ namespace XenAdmin.ConsoleView
IntPtr _ = Handle;
#pragma warning restore 0219
this.parentVNCView = parent;
this.scaleCheckBox.Checked = false;
parentVNCView = parent;
scaleCheckBox.Checked = false;
this.source = source;
this.guestMetrics = source.Connection.Resolve(source.guest_metrics);
if (this.guestMetrics != null)
guestMetrics = source.Connection.Resolve(source.guest_metrics);
if (guestMetrics != null)
guestMetrics.PropertyChanged += guestMetrics_PropertyChanged;
log.DebugFormat("'{0}' console: Register Server_PropertyChanged event listener on {0}", this.source.Name());
this.source.PropertyChanged += Server_PropertyChanged;
@ -165,26 +165,27 @@ namespace XenAdmin.ConsoleView
log.DebugFormat("'{0}' console: Update power state (on VNCTabView constructor)", this.source.Name());
updatePowerState();
this.vncScreen = new XSVNCScreen(source, new EventHandler(RDPorVNCResizeHandler), this, elevatedUsername, elevatedPassword);
vncScreen = new XSVNCScreen(source, new EventHandler(RDPorVNCResizeHandler), this, elevatedUsername, elevatedPassword);
ShowGpuWarningIfRequired(vncScreen.MustConnectRemoteDesktop());
vncScreen.GpuStatusChanged += ShowGpuWarningIfRequired;
if (source.IsControlDomainZero(out var _) || source.IsHVM() && !hasRDP) //Linux HVM guests should only have one console: the console switch button vanishes altogether.
if (source.IsControlDomainZero(out var _) || source.IsHVM() && !HasRDP) //Linux HVM guests should only have one console: the console switch button vanishes altogether.
{
toggleConsoleButton.Visible = false;
}
else
{
toggleConsoleButton.Visible = true;
this.vncScreen.OnDetectRDP = this.OnDetectRDP;
this.vncScreen.OnDetectVNC = this.OnDetectVNC;
this.vncScreen.UserCancelledAuth += this.OnUserCancelledAuth;
this.vncScreen.VncConnectionAttemptCancelled += this.OnVncConnectionAttemptCancelled;
vncScreen.UserCancelledAuth += OnUserCancelledAuth;
vncScreen.VncConnectionAttemptCancelled += OnVncConnectionAttemptCancelled;
}
vncScreen.OnDetectRDP = OnDetectRDP;
vncScreen.OnDetectVNC = OnDetectVNC;
LastDesktopSize = vncScreen.DesktopSize;
this.insKeyTimer = new System.Threading.Timer(new TimerCallback(notInsKeyPressed));
insKeyTimer = new System.Threading.Timer(new TimerCallback(notInsKeyPressed));
Properties.Settings.Default.PropertyChanged += Default_PropertyChanged;
@ -196,11 +197,11 @@ namespace XenAdmin.ConsoleView
KeyHandler.AddKeyHandler(ConsoleShortcutKey.CTRL_ALT_INS, cancelWaitForInsKeyAndSendCAD);
this.vncScreen.Parent = this.contentPanel;
this.vncScreen.Dock = DockStyle.Fill;
vncScreen.Parent = contentPanel;
vncScreen.Dock = DockStyle.Fill;
string rdpLabel = GuessNativeConsoleLabel(source);
this.toggleConsoleButton.Text = rdpLabel;
toggleConsoleButton.Text = rdpLabel;
UpdateFullScreenButton();
@ -298,8 +299,8 @@ namespace XenAdmin.ConsoleView
source.PropertyChanged -= new PropertyChangedEventHandler(Server_PropertyChanged);
source.Connection.Cache.DeregisterCollectionChanged<VM>(VM_CollectionChangedWithInvoke);
if (this.guestMetrics != null)
this.guestMetrics.PropertyChanged -= guestMetrics_PropertyChanged;
if (guestMetrics != null)
guestMetrics.PropertyChanged -= guestMetrics_PropertyChanged;
if (source.IsControlDomainZero(out Host host))
{
@ -527,11 +528,11 @@ namespace XenAdmin.ConsoleView
var newGuestMetrics = source.Connection.Resolve(source.guest_metrics);
//unsubscribing from the previous instance's event
if (this.guestMetrics != null)
this.guestMetrics.PropertyChanged -= guestMetrics_PropertyChanged;
if (guestMetrics != null)
guestMetrics.PropertyChanged -= guestMetrics_PropertyChanged;
this.guestMetrics = newGuestMetrics;
if (this.guestMetrics != null)
guestMetrics = newGuestMetrics;
if (guestMetrics != null)
guestMetrics.PropertyChanged += guestMetrics_PropertyChanged;
EnableRDPIfCapable();
@ -591,17 +592,10 @@ namespace XenAdmin.ConsoleView
private void EnableRDPIfCapable()
{
if (!toggleConsoleButton.Visible && hasRDP)
{
// The toggle button is not visible now, because RDP had not been enabled on the VM when we started the console.
// However, the current guest_metrics indicates that RDP is now supported (HasRDP==true). (eg. XenTools has been installed in the meantime.)
// This means that now we should show and enable the toggle RDP button and start polling (if allowed) RDP as well.
var enable = source.CanUseRDP();
if(enable)
log.DebugFormat("'{0}' console: Enabling RDP button, because RDP capability has appeared.", source);
toggleConsoleButton.Visible = true;
toggleConsoleButton.Enabled = true;
}
toggleConsoleButton.Visible = toggleConsoleButton.Enabled = enable;
}
private void Server_EnabledPropertyChanged(object sender, PropertyChangedEventArgs e)
@ -924,7 +918,7 @@ namespace XenAdmin.ConsoleView
try
{
ignoringResizes = true;
this.vncScreen.Scaling = this.scaleCheckBox.Checked;
vncScreen.Scaling = scaleCheckBox.Checked;
}
finally
{
@ -936,7 +930,7 @@ namespace XenAdmin.ConsoleView
private void sendCAD_Click(object sender, EventArgs e)
{
this.vncScreen.SendCAD();
vncScreen.SendCAD();
FocusVNC();
}
@ -944,7 +938,7 @@ namespace XenAdmin.ConsoleView
{
if (isFullscreen)
return;
this.parentVNCView.DockUnDock();
parentVNCView.DockUnDock();
}
private void fullscreenButton_Click(object sender, EventArgs e)
@ -956,20 +950,20 @@ namespace XenAdmin.ConsoleView
private void waitForInsKey()
{
lock (this.insKeyTimer)
lock (insKeyTimer)
{
this.insKeyTimer.Change(INS_KEY_TIMEOUT, System.Threading.Timeout.Infinite);
insKeyTimer.Change(INS_KEY_TIMEOUT, Timeout.Infinite);
}
}
private void cancelWaitForInsKeyAndSendCAD()
{
lock (this.insKeyTimer)
lock (insKeyTimer)
{
// We have seen the INS key, so lets cancel the timer and send CAD
this.insKeyTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
this.vncScreen.SendCAD();
insKeyTimer.Change(Timeout.Infinite, Timeout.Infinite);
vncScreen.SendCAD();
}
}
@ -979,12 +973,12 @@ namespace XenAdmin.ConsoleView
Program.Invoke(this, delegate ()
{
lock (this.insKeyTimer)
lock (insKeyTimer)
{
// We have not seen the INS key, so lets toggleFullscreen and cancel the timer
this.toggleFullscreen();
this.insKeyTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
toggleFullscreen();
insKeyTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
});
}
@ -1046,7 +1040,7 @@ namespace XenAdmin.ConsoleView
source.Connection.BeforeConnectionEnd -= Connection_BeforeConnectionEnd;
fullscreenForm.DetachVncScreen(vncScreen);
vncScreen.Parent = this.contentPanel;
vncScreen.Parent = contentPanel;
vncScreen.DisplayFocusRectangle = true;
FocusVNC();
vncScreen.CaptureKeyboardAndMouse();
@ -1103,7 +1097,7 @@ namespace XenAdmin.ConsoleView
if (vncScreen.UseVNC)
toggleConsoleButton.Text = CanEnableRDP() ? enableRDP : UseRDP;
toggleConsoleButton.Enabled = true;
EnableRDPIfCapable();
tip.SetToolTip(toggleConsoleButton, null);
if (!vncScreen.UserWantsToSwitchProtocol && Properties.Settings.Default.AutoSwitchToRDP)
{
@ -1129,10 +1123,10 @@ namespace XenAdmin.ConsoleView
try
{
log.DebugFormat("VNC detected for VM '{0}'", source == null ? "unknown/null" : source.name_label);
this.toggleToXVNCorRDP = XVNC;
this.toggleConsoleButton.Text = vncScreen.UseSource ? UseXVNC : UseVNC;
this.toggleConsoleButton.Enabled = true;
tip.SetToolTip(this.toggleConsoleButton, null);
toggleToXVNCorRDP = XVNC;
toggleConsoleButton.Text = vncScreen.UseSource ? UseXVNC : UseVNC;
toggleConsoleButton.Enabled = true;
tip.SetToolTip(toggleConsoleButton, null);
}
catch (InvalidOperationException exn)
{
@ -1174,13 +1168,13 @@ namespace XenAdmin.ConsoleView
{
Session session = source.Connection.DuplicateSession();
Dictionary<string, string> _arguments = new Dictionary<string, string>();
XenAPI.VM.call_plugin(session, source.opaque_ref, "guest-agent-operation", "request-rdp-on", _arguments);
VM.call_plugin(session, source.opaque_ref, "guest-agent-operation", "request-rdp-on", _arguments);
tryToConnectRDP = true;
}
}
// disable toggleConsoleButton; it will be re-enabled in TryToConnectRDP() when rdp port polling is complete (CA-102755)
if (vncScreen.rdpIP == null)
if (vncScreen.RdpIp == null)
toggleConsoleButton.Enabled = false;
ThreadPool.QueueUserWorkItem(TryToConnectRDP);
}
@ -1228,13 +1222,13 @@ namespace XenAdmin.ConsoleView
private void UpdateTooltipOfToggleButton()
{
if (RDPEnabled || RDPControlEnabled)
tip.SetToolTip(this.toggleConsoleButton, null);
tip.SetToolTip(toggleConsoleButton, null);
}
private void TryToConnectRDP(object x)
{
bool hasToReconnect = vncScreen.rdpIP == null;
vncScreen.rdpIP = vncScreen.PollPort(XSVNCScreen.RDP_PORT, true);
bool hasToReconnect = vncScreen.RdpIp == null;
vncScreen.RdpIp = vncScreen.PollPort(XSVNCScreen.RDP_PORT, true);
Program.Invoke(this, (MethodInvoker)(() =>
{
if (hasToReconnect)
@ -1275,13 +1269,13 @@ namespace XenAdmin.ConsoleView
internal void SendCAD()
{
if (this.vncScreen != null)
this.vncScreen.SendCAD();
if (vncScreen != null)
vncScreen.SendCAD();
}
internal void focus_vnc()
{
if (this.vncScreen != null)
if (vncScreen != null)
FocusVNC();
}
@ -1417,7 +1411,7 @@ namespace XenAdmin.ConsoleView
private void LifeCycleMenuStrip_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
if (e.CloseReason != ToolStripDropDownCloseReason.AppClicked || !pictureBox1.ClientRectangle.Contains(this.PointToClient(MousePosition)))
if (e.CloseReason != ToolStripDropDownCloseReason.AppClicked || !pictureBox1.ClientRectangle.Contains(PointToClient(MousePosition)))
{
droppedDown = false;
pictureBox1.Image = Images.StaticImages._001_LifeCycle_h32bit_24;

View File

@ -178,7 +178,7 @@ namespace XenAdmin.ConsoleView
void Default_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "EnableRDPPolling")
Program.Invoke(this, startPolling);
Program.Invoke(this, StartPolling);
}
private void UnregisterEventListeners()
@ -210,7 +210,7 @@ namespace XenAdmin.ConsoleView
cachedNetworks = newNetworks;
Program.Invoke(this, startPolling);
Program.Invoke(this, StartPolling);
}
}
}
@ -288,84 +288,77 @@ namespace XenAdmin.ConsoleView
public MethodInvoker OnDetectRDP = null;
public MethodInvoker OnDetectVNC = null;
public String rdpIP = null;
public String vncIP = null;
public string RdpIp;
public string VncIp;
private void PollRDPPort(Object Sender)
private void PollRDPPort(object sender)
{
if (hasRDP)
{
if (connectionPoller != null)
connectionPoller.Change(Timeout.Infinite, Timeout.Infinite);
if (OnDetectRDP != null)
Program.Invoke(this, OnDetectRDP);
}
else
{
rdpIP = null;
String openIP = PollPort(RDP_PORT, false);
RdpIp = null;
var openIp = PollPort(RDP_PORT, false);
if (openIP != null)
{
rdpIP = openIP;
if (connectionPoller != null)
connectionPoller.Change(Timeout.Infinite, Timeout.Infinite);
if (OnDetectRDP != null)
Program.Invoke(this, OnDetectRDP);
}
if (openIp == null)
return;
RdpIp = openIp;
if (OnDetectRDP != null)
Program.Invoke(this, OnDetectRDP);
}
}
private void PollVNCPort(Object Sender)
private void PollVNCPort(object sender)
{
vncIP = null;
String openIP = PollPort(VNC_PORT, true);
VncIp = null;
var openIp = PollPort(VNC_PORT, true);
if (openIP != null)
{
vncIP = openIP;
if (connectionPoller != null)
connectionPoller.Change(Timeout.Infinite, Timeout.Infinite);
if (OnDetectVNC != null)
Program.Invoke(this, OnDetectVNC);
}
if (openIp == null)
return;
VncIp = openIp;
connectionPoller?.Change(Timeout.Infinite, Timeout.Infinite);
if (OnDetectVNC != null)
Program.Invoke(this, OnDetectVNC);
}
/// <summary>
/// scan each ip address (from the guest agent) for an open port
/// </summary>
public String PollPort(int port, bool vnc)
public string PollPort(int port, bool vnc)
{
try
{
if (Source == null)
return null;
VM vm = Source;
var vm = Source;
XenRef<VM_guest_metrics> guestMetricsRef = vm.guest_metrics;
var guestMetricsRef = vm.guest_metrics;
if (guestMetricsRef == null || Helper.IsNullOrEmptyOpaqueRef(guestMetricsRef.opaque_ref))
return null;
VM_guest_metrics metrics = vm.Connection.Resolve(guestMetricsRef);
if (metrics == null)
return null;
Dictionary<string, string> networks = metrics.networks;
var metrics = vm.Connection.Resolve(guestMetricsRef);
var networks = metrics?.networks;
if (networks == null)
return null;
List<string> ipAddresses = new List<string>();
List<string> ipv6Addresses = new List<string>();
List<string> ipAddressesForNetworksWithoutPifs = new List<string>();
List<string> ipv6AddressesForNetworksWithoutPifs = new List<string>();
var ipAddresses = new List<string>();
var ipv6Addresses = new List<string>();
var ipAddressesForNetworksWithoutPifs = new List<string>();
var ipv6AddressesForNetworksWithoutPifs = new List<string>();
foreach (VIF vif in vm.Connection.ResolveAll(vm.VIFs))
foreach (var vif in vm.Connection.ResolveAll(vm.VIFs))
{
XenAPI.Network network = vif.Connection.Resolve(vif.network);
Host host = vm.Connection.Resolve(vm.resident_on);
PIF pif = Helpers.FindPIF(network, host);
foreach (var networkInfo in networks.Where(n => n.Key.StartsWith(String.Format("{0}/ip", vif.device))))
var network = vif.Connection.Resolve(vif.network);
var host = vm.Connection.Resolve(vm.resident_on);
var pif = Helpers.FindPIF(network, host);
foreach (var networkInfo in networks.Where(n => n.Key.StartsWith($"{vif.device}/ip")))
{
if (networkInfo.Key.EndsWith("ip") || networkInfo.Key.Contains("ipv4")) // IPv4 address
{
@ -379,12 +372,10 @@ namespace XenAdmin.ConsoleView
if (networkInfo.Key.Contains("ipv6")) // IPv6 address, enclose in square brackets
{
if (pif == null)
ipv6AddressesForNetworksWithoutPifs.Add(String.Format("[{0}]", networkInfo.Value));
ipv6AddressesForNetworksWithoutPifs.Add($"[{networkInfo.Value}]");
else if (pif.LinkStatus() == PIF.LinkState.Connected)
ipv6Addresses.Add(String.Format("[{0}]", networkInfo.Value));
ipv6Addresses.Add($"[{networkInfo.Value}]");
}
else
continue;
}
}
}
@ -396,12 +387,12 @@ namespace XenAdmin.ConsoleView
ipAddresses.AddRange(ipv6AddressesForNetworksWithoutPifs);
foreach (String ipAddress in ipAddresses)
foreach (var ipAddress in ipAddresses)
{
try
{
Log.DebugFormat("Poll port {0}:{1}", ipAddress, port);
Stream s = connectGuest(ipAddress, port, vm.Connection);
var s = connectGuest(ipAddress, port, vm.Connection);
if (vnc)
{
Log.DebugFormat("Connected. Set Pending Vnc connection {0}:{1}", ipAddress, port);
@ -429,22 +420,25 @@ namespace XenAdmin.ConsoleView
}
catch (Failure exn)
{
if (exn.ErrorDescription[0] == Failure.HANDLE_INVALID)
switch (exn.ErrorDescription[0])
{
// HANDLE_INVALID is fine -- the guest metrics are not there yet.
}
else if (exn.ErrorDescription[0] == Failure.SESSION_INVALID)
{
// SESSION_INVALID is fine -- these will expire from time to time.
// We need to invalidate the session though.
lock (activeSessionLock)
case Failure.HANDLE_INVALID:
// HANDLE_INVALID is fine -- the guest metrics are not there yet.
break;
case Failure.SESSION_INVALID:
{
activeSession = null;
// SESSION_INVALID is fine -- these will expire from time to time.
// We need to invalidate the session though.
lock (activeSessionLock)
{
activeSession = null;
}
break;
}
}
else
{
Log.Warn("Exception while polling VM for port " + port + ".", exn);
default:
Log.Warn("Exception while polling VM for port " + port + ".", exn);
break;
}
}
catch (Exception e)
@ -519,7 +513,7 @@ namespace XenAdmin.ConsoleView
Program.AssertOnEventThread();
//When switch to RDP from VNC, if RDP IP is empty, do not try to switch.
if (String.IsNullOrEmpty(rdpIP) && !UseVNC && RemoteConsole != null)
if (String.IsNullOrEmpty(RdpIp) && !UseVNC && RemoteConsole != null)
return;
bool wasFocused = false;
@ -539,7 +533,7 @@ namespace XenAdmin.ConsoleView
// Reset
haveTriedLoginWithoutPassword = false;
if (UseVNC || String.IsNullOrEmpty(rdpIP))
if (UseVNC || String.IsNullOrEmpty(RdpIp))
{
this.AutoScroll = false;
this.AutoScrollMinSize = new Size(0, 0);
@ -590,7 +584,7 @@ namespace XenAdmin.ConsoleView
internal bool MustConnectRemoteDesktop()
{
return (UseVNC || string.IsNullOrEmpty(rdpIP)) &&
return (UseVNC || string.IsNullOrEmpty(RdpIp)) &&
Source.HasGPUPassthrough() && Source.power_state == vm_power_state.Running;
}
@ -605,7 +599,7 @@ namespace XenAdmin.ConsoleView
if (vncClient != null)
ThreadPool.QueueUserWorkItem(new WaitCallback(Connect), new KeyValuePair<VNCGraphicsClient, Exception>(vncClient, null));
else if (rdpClient != null)
rdpClient.Connect(rdpIP);
rdpClient.Connect(RdpIp);
}
void ConnectionSuccess(object sender, EventArgs e)
@ -710,7 +704,7 @@ namespace XenAdmin.ConsoleView
sourceIsPV = !value.IsHVM();
startPolling();
StartPolling();
lock (hostedConsolesLock)
{
@ -751,7 +745,7 @@ namespace XenAdmin.ConsoleView
return UseVNC && UseSource;
}
private void startPolling()
private void StartPolling()
{
//Disable the button first, but only if in text/default console (to allow user to return to the text console - ref. CA-70314)
if (InDefaultConsole())
@ -759,26 +753,19 @@ namespace XenAdmin.ConsoleView
parentVNCTabView.DisableToggleVNCButton();
}
if (!parentVNCTabView.IsRDPControlEnabled())
{
if (InDefaultConsole())
{
parentVNCTabView.DisableToggleVNCButton();
}
if (parentVNCTabView.IsRDPControlEnabled())
return;
//Start the polling again
if (Source != null && !Source.IsControlDomainZero(out _))
{
if (!Source.IsHVM())
{
connectionPoller = new Timer(PollVNCPort, null, RETRY_SLEEP_TIME, RDP_POLL_INTERVAL);
}
else if (hasRDP)
{
connectionPoller = new Timer(PollRDPPort, null, RETRY_SLEEP_TIME, RDP_POLL_INTERVAL);
}
}
if (InDefaultConsole())
{
parentVNCTabView.DisableToggleVNCButton();
}
if (Source == null || Source.IsControlDomainZero(out _))
return;
//Start the polling again
connectionPoller = !Source.IsHVM() ? new Timer(PollVNCPort, null, RETRY_SLEEP_TIME, RDP_POLL_INTERVAL) : new Timer(PollRDPPort, null, RETRY_SLEEP_TIME, RDP_POLL_INTERVAL);
}
private void VM_PropertyChanged(object sender, PropertyChangedEventArgs e)
@ -820,7 +807,7 @@ namespace XenAdmin.ConsoleView
else if (e.PropertyName == "domid")
{
// Reboot / start / shutdown
Program.Invoke(this, startPolling);
Program.Invoke(this, StartPolling);
}
if (e.PropertyName == "power_state" || e.PropertyName == "VGPUs")
@ -964,7 +951,7 @@ namespace XenAdmin.ConsoleView
}
else
{
if (vncIP == null)
if (VncIp == null)
{
Log.DebugFormat("vncIP is null. Abort VNC connection attempt");
OnVncConnectionAttemptCancelled();
@ -1006,9 +993,9 @@ namespace XenAdmin.ConsoleView
}
if (s == null)
{
Log.DebugFormat("Connecting to vncIP={0}, port={1}", this.vncIP, VNC_PORT);
s = connectGuest(this.vncIP, VNC_PORT, sourceVM.Connection);
Log.DebugFormat("Connected to vncIP={0}, port={1}", this.vncIP, VNC_PORT);
Log.DebugFormat("Connecting to vncIP={0}, port={1}", this.VncIp, VNC_PORT);
s = connectGuest(this.VncIp, VNC_PORT, sourceVM.Connection);
Log.DebugFormat("Connected to vncIP={0}, port={1}", this.VncIp, VNC_PORT);
}
InvokeConnection(v, s, null);

View File

@ -348,7 +348,8 @@ namespace XenAPI
var metrics = Connection.Resolve(this.guest_metrics);
if (metrics == null)
return false;
// feature-ts is the feature flag indicating the toolstack
// can enable RDP remotely (by writing to control/ts)
return 0 != IntKey(metrics.other, "feature-ts", 0);
}
@ -357,7 +358,7 @@ namespace XenAPI
var vmMetrics = Connection.Resolve(this.guest_metrics);
if (vmMetrics == null)
return false;
// data/ts indicates the VM has RDP enabled
return 0 != IntKey(vmMetrics.other, "data-ts", 0);
}
@ -366,10 +367,25 @@ namespace XenAPI
var metrics = Connection.Resolve(this.guest_metrics);
if (metrics == null)
return false;
// feature-ts2 is the feature flag indicating that data/ts is valid
return 0 != IntKey(metrics.other, "feature-ts2", 0);
}
public bool CanUseRDP()
{
var guestMetrics = Connection.Resolve(guest_metrics);
if (guestMetrics == null)
return false;
return IntKey(guestMetrics.other, "feature-ts2", 0) != 0 &&
IntKey(guestMetrics.other, "feature-ts", 0) != 0 &&
IntKey(guestMetrics.other, "data-ts", 0) != 0 &&
// CA-322672: Can't connect using RDP if there are no networks.
// The network object contains the IP info written by the xenvif
// driver (which needs a 1st reboot to swap out the emulated network adapter)
guestMetrics.networks.Count > 0;
}
/// <summary>Returns true if
/// 1) the guest is HVM and
/// 2a) the allow-gpu-passthrough restriction is absent or