From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> The QEMU monitor command 'add_client' can be used to connect to a VNC or SPICE graphics display. This allows for implementaton of the virDomainOpenGraphics API * src/qemu/qemu_driver.c: Implement virDomainOpenGraphics * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h, src/qemu/qemu_monitor_json.c, src/qemu/qemu_monitor_json.h, src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h: Add binding for 'add_client' command --- src/qemu/qemu_driver.c | 71 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 33 +++++++++++++++++++ src/qemu/qemu_monitor.h | 6 +++ src/qemu/qemu_monitor_json.c | 27 ++++++++++++++++ src/qemu/qemu_monitor_json.h | 5 +++ src/qemu/qemu_monitor_text.c | 32 +++++++++++++++++++ src/qemu/qemu_monitor_text.h | 5 +++ 7 files changed, 179 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 84ef4dd..fe509b7 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -10653,6 +10653,76 @@ qemuDomainBlockPull(virDomainPtr dom, const char *path, unsigned long bandwidth, return ret; } +static int +qemuDomainOpenGraphics(virDomainPtr dom, + unsigned int idx, + int fd, + unsigned int flags) +{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm = NULL; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + int ret = -1; + qemuDomainObjPrivatePtr priv; + const char *protocol; + + virCheckFlags(VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH, -1); + + qemuDriverLock(driver); + virUUIDFormat(dom->uuid, uuidstr); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + if (!vm) { + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (idx >= vm->def->ngraphics) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("No graphics backend with index %d"), idx); + goto cleanup; + } + switch (vm->def->graphics[idx]->type) { + case VIR_DOMAIN_GRAPHICS_TYPE_VNC: + protocol = "vnc"; + break; + case VIR_DOMAIN_GRAPHICS_TYPE_SPICE: + protocol = "spice"; + break; + default: + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Can only open VNC or SPICE graphics backends, not %s"), + virDomainGraphicsTypeToString(vm->def->graphics[idx]->type)); + goto cleanup; + } + + if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0) + goto cleanup; + qemuDomainObjEnterMonitorWithDriver(driver, vm); + ret = qemuMonitorOpenGraphics(priv->mon, protocol, fd, "graphicsfd", + flags & VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (qemuDomainObjEndJob(driver, vm) == 0) { + vm = NULL; + goto cleanup; + } + +cleanup: + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + + static virDriver qemuDriver = { .no = VIR_DRV_QEMU, .name = "QEMU", @@ -10783,6 +10853,7 @@ static virDriver qemuDriver = { .qemuDomainMonitorCommand = qemuDomainMonitorCommand, /* 0.8.3 */ .qemuDomainAttach = qemuDomainAttach, /* 0.9.4 */ .domainOpenConsole = qemuDomainOpenConsole, /* 0.8.6 */ + .domainOpenGraphics = qemuDomainOpenGraphics, /* 0.9.7 */ .domainInjectNMI = qemuDomainInjectNMI, /* 0.9.2 */ .domainMigrateBegin3 = qemuDomainMigrateBegin3, /* 0.9.2 */ .domainMigratePrepare3 = qemuDomainMigratePrepare3, /* 0.9.2 */ diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 182e63d..f7cea2e 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2591,3 +2591,36 @@ int qemuMonitorVMStatusToPausedReason(const char *status) } return VIR_DOMAIN_PAUSED_UNKNOWN; } + + +int qemuMonitorOpenGraphics(qemuMonitorPtr mon, + const char *protocol, + int fd, + const char *fdname, + bool skipauth) +{ + VIR_DEBUG("mon=%p protocol=%s fd=%d fdname=%s skipauth=%d", + mon, protocol, fd, NULLSTR(fdname), skipauth); + int ret; + + if (!mon) { + qemuReportError(VIR_ERR_INVALID_ARG, "%s", + _("monitor must not be NULL")); + return -1; + } + + if (qemuMonitorSendFileHandle(mon, fdname, fd) < 0) + return -1; + + if (mon->json) + ret = qemuMonitorJSONOpenGraphics(mon, protocol, fdname, skipauth); + else + ret = qemuMonitorTextOpenGraphics(mon, protocol, fdname, skipauth); + + if (ret < 0) { + if (qemuMonitorCloseFileHandle(mon, fdname) < 0) + VIR_WARN("failed to close device handle '%s'", fdname); + } + + return ret; +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 90e7b45..883e0aa 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -515,6 +515,12 @@ int qemuMonitorBlockJob(qemuMonitorPtr mon, virDomainBlockJobInfoPtr info, int mode); +int qemuMonitorOpenGraphics(qemuMonitorPtr mon, + const char *protocol, + int fd, + const char *fdname, + bool skipauth); + /** * When running two dd process and using <> redirection, we need a * shell that will not truncate files. These two strings serve that diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 46f98ee..ced6b72 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -3245,3 +3245,30 @@ int qemuMonitorJSONBlockJob(qemuMonitorPtr mon, virJSONValueFree(reply); return ret; } + +int qemuMonitorJSONOpenGraphics(qemuMonitorPtr mon, + const char *protocol, + const char *fdname, + bool skipauth) +{ + int ret; + virJSONValuePtr cmd, reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("add_client", + "s:protocol", protocol, + "s:fdname", fdname, + "b:skipauth", skipauth, + NULL); + + if (!cmd) + return -1; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index a638b41..f10d7d2 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -250,4 +250,9 @@ int qemuMonitorJSONSetLink(qemuMonitorPtr mon, const char *name, enum virDomainNetInterfaceLinkState state); +int qemuMonitorJSONOpenGraphics(qemuMonitorPtr mon, + const char *protocol, + const char *fdname, + bool skipauth); + #endif /* QEMU_MONITOR_JSON_H */ diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 4774df9..03b6b44 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -3394,3 +3394,35 @@ cleanup: VIR_FREE(reply); return ret; } + + +int qemuMonitorTextOpenGraphics(qemuMonitorPtr mon, + const char *protocol, + const char *fdname, + bool skipauth) +{ + char *cmd = NULL; + char *reply = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "add_client %s %s %d", protocol, fdname, skipauth ? 0 : 1) < 0){ + virReportOOMError(); + goto cleanup; + } + + if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) { + qemuReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("adding graphics client failed")); + goto cleanup; + } + + if (STRNEQ(reply, "")) + goto cleanup; + + ret = 0; + +cleanup: + VIR_FREE(reply); + VIR_FREE(cmd); + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index cc2a252..f32fce0 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -243,4 +243,9 @@ int qemuMonitorTextSetLink(qemuMonitorPtr mon, const char *name, enum virDomainNetInterfaceLinkState state); +int qemuMonitorTextOpenGraphics(qemuMonitorPtr mon, + const char *protocol, + const char *fdname, + bool skipauth); + #endif /* QEMU_MONITOR_TEXT_H */ -- 1.7.6.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list