[libvirt] [RFC PATCH] qemu: new API for tracking arbitrary monitor events

Several times in the past, qemu has implemented a new event, but libvirt has not yet caught up to reporting that event to the user applications. While it is possible to track libvirt logs to see that an unknown event was received and ignored, it would be nicer to copy what 'virsh qemu-monitor-command' does, and expose this information to the end developer as one of our unsupported qemu-specific commands. If you find yourself needing to use this API for more than just development purposes, please ask on the libvirt list for a supported counterpart event to be added in libvirt.so. While the supported virConnectDomainEventRegisterAny() API takes an id which determines the signature of the callback, this version takes a string filter and always uses the same signature. Furthermore, I chose to expose this as a new API instead of trying to add a new eventID at the top level, in part because the generic option lacks event name filtering, and in part because the normal domain event namespace should not be polluted by a qemu-only event. I also added a flags argument; unused for now, but we might decide to use it to allow a user to request event names by glob or regex instead of literal match. * include/libvirt/libvirt-qemu.h (virConnectDomainQemuMonitorEventCallback) (virConnectDomainQemuMonitorEventRegister) (virConnectDomainQemuMonitorEventDeregister): New prototypes. * src/libvirt-qemu.c (virConnectDomainQemuMonitorEventRegister) (virConnectDomainQemuMonitorEventDeregister): New functions. * src/libvirt_qemu.syms (LIBVIRT_QEMU_1.2.1): Export them. * src/driver.h (virDrvConnectDomainQemuMonitorEventRegister) (virDrvConnectDomainQemuMonitorEventDeregister): New callbacks. Signed-off-by: Eric Blake <eblake@redhat.com> --- Before I go and implement the guts of this new API, I first wanted to get approval from the list that I'm on the right track. include/libvirt/libvirt-qemu.h | 31 ++++++++++- src/driver.h | 15 +++++ src/libvirt-qemu.c | 123 +++++++++++++++++++++++++++++++++++++++++ src/libvirt_qemu.syms | 6 ++ 4 files changed, 174 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-qemu.h b/include/libvirt/libvirt-qemu.h index 3e79a8c..5403093 100644 --- a/include/libvirt/libvirt-qemu.h +++ b/include/libvirt/libvirt-qemu.h @@ -4,7 +4,7 @@ * Description: Provides the interfaces of the libvirt library to handle * qemu specific methods * - * Copyright (C) 2010, 2012 Red Hat, Inc. + * Copyright (C) 2010, 2012-2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -54,6 +54,35 @@ typedef enum { char *virDomainQemuAgentCommand(virDomainPtr domain, const char *cmd, int timeout, unsigned int flags); +/** + * virConnectDomainQemuMonitorEventCallback: + * @conn: the connection pointer + * @dom: the domain pointer + * @event: the name of the event + * @details: the JSON details of the event + * @opaque: application specified data + * + * The callback signature to use when registering for a qemu monitor + * event with virConnectDomainQemuMonitorEventRegister(). + */ +typedef void (*virConnectDomainQemuMonitorEventCallback)(virConnectPtr conn, + virDomainPtr dom, + const char *event, + const char *details, + void *opaque); + +int virConnectDomainQemuMonitorEventRegister(virConnectPtr conn, + virDomainPtr dom, + const char *event, + virConnectDomainQemuMonitorEventCallback cb, + void *opaque, + virFreeCallback freecb, + unsigned int flags); + +int virConnectDomainQemuMonitorEventDeregister(virConnectPtr conn, + int callbackID); + + # ifdef __cplusplus } # endif diff --git a/src/driver.h b/src/driver.h index b6927ea..e9bf5cb 100644 --- a/src/driver.h +++ b/src/driver.h @@ -841,6 +841,19 @@ typedef virDomainPtr unsigned int flags); typedef int +(*virDrvConnectDomainQemuMonitorEventRegister)(virConnectPtr conn, + virDomainPtr dom, + const char *event, + virConnectDomainQemuMonitorEventCallback cb, + void *opaque, + virFreeCallback freecb, + unsigned int flags); + +typedef int +(*virDrvConnectDomainQemuMonitorEventDeregister)(virConnectPtr conn, + int callbackID); + +typedef int (*virDrvDomainOpenConsole)(virDomainPtr dom, const char *dev_name, virStreamPtr st, @@ -1300,6 +1313,8 @@ struct _virDriver { virDrvDomainQemuMonitorCommand domainQemuMonitorCommand; virDrvDomainQemuAttach domainQemuAttach; virDrvDomainQemuAgentCommand domainQemuAgentCommand; + virDrvConnectDomainQemuMonitorEventRegister connectDomainQemuMonitorEventRegister; + virDrvConnectDomainQemuMonitorEventDeregister connectDomainQemuMonitorEventDeregister; virDrvDomainOpenConsole domainOpenConsole; virDrvDomainOpenChannel domainOpenChannel; virDrvDomainOpenGraphics domainOpenGraphics; diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c index db52c65..849932d 100644 --- a/src/libvirt-qemu.c +++ b/src/libvirt-qemu.c @@ -237,3 +237,126 @@ error: virDispatchError(conn); return NULL; } + + +/** + * virConnectDomainQemuMonitorEventRegister: + * @conn: pointer to the connection + * @dom: pointer to the domain, or NULL + * @event: name of the event, or NULL + * @cb: callback to the function handling monitor events + * @opaque: opaque data to pass on to the callback + * @freecb: optional function to deallocate opaque when not used anymore + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * This API is QEMU specific, so it will only work with hypervisor + * connections to the QEMU driver. + * + * Adds a callback to receive notifications of arbitrary qemu monitor events + * occurring on a domain. Many qemu monitor events also result in a libvirt + * event which can be delivered via virConnectDomainEventRegisterAny(); this + * command is primarily for testing new qemu events that have not yet been + * given a libvirt counterpart event. + * + * If @dom is NULL, then events will be monitored for any domain. If @dom + * is non-NULL, then only the specific domain will be monitored. + * + * If @event is NULL, then all monitor events will be reported. If @event is + * non-NULL, then only the specific monitor event will be reported. @flags + * is currently unused, but in the future may support a flag for passing + * @event as a glob instead of a literal name to match a category of events. + * + * The virDomainPtr object handle passed into the callback upon delivery + * of an event is only valid for the duration of execution of the callback. + * If the callback wishes to keep the domain object after the callback returns, + * it shall take a reference to it, by calling virDomainRef(). + * The reference can be released once the object is no longer required + * by calling virDomainFree(). + * + * The return value from this method is a positive integer identifier + * for the callback. To unregister a callback, this callback ID should + * be passed to the virConnectDomainQemuMonitorEventDeregister() method. + * + * Returns a callback identifier on success, -1 on failure + */ +int +virConnectDomainQemuMonitorEventRegister(virConnectPtr conn, + virDomainPtr dom, + const char *event, + virConnectDomainQemuMonitorEventCallback cb, + void *opaque, + virFreeCallback freecb, + unsigned int flags) +{ + VIR_DOMAIN_DEBUG(dom, + "conn=%p, event=%s, cb=%p, opaque=%p, freecb=%p, flags=%x", + conn, NULLSTR(event), cb, opaque, freecb, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + if (dom && + !(VIR_IS_CONNECTED_DOMAIN(dom) && dom->conn == conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(conn); + return -1; + } + virCheckNonNullArgGoto(cb, error); + + if ((conn->driver) && (conn->driver->connectDomainQemuMonitorEventRegister)) { + int ret; + ret = conn->driver->connectDomainQemuMonitorEventRegister(conn, dom, event, cb, opaque, freecb, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); +error: + virDispatchError(conn); + return -1; +} + +/** + * virConnectDomainQemuMonitorEventDeregister: + * @conn: pointer to the connection + * @callbackID: the callback identifier + * + * Removes an event callback. The callbackID parameter should be the + * value obtained from a previous virConnectDomainQemuMonitorEventRegister() + * method. + * + * Returns 0 on success, -1 on failure + */ +int +virConnectDomainQemuMonitorEventDeregister(virConnectPtr conn, + int callbackID) +{ + VIR_DEBUG("conn=%p, callbackID=%d", conn, callbackID); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + virCheckNonNegativeArgGoto(callbackID, error); + + if ((conn->driver) && (conn->driver->connectDomainQemuMonitorEventDeregister)) { + int ret; + ret = conn->driver->connectDomainQemuMonitorEventDeregister(conn, callbackID); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); +error: + virDispatchError(conn); + return -1; +} diff --git a/src/libvirt_qemu.syms b/src/libvirt_qemu.syms index f968d91..7698c5c 100644 --- a/src/libvirt_qemu.syms +++ b/src/libvirt_qemu.syms @@ -24,3 +24,9 @@ LIBVIRT_QEMU_0.10.0 { global: virDomainQemuAgentCommand; } LIBVIRT_QEMU_0.9.4; + +LIBVIRT_QEMU_1.2.1 { + global: + virConnectDomainQemuMonitorEventDeregister; + virConnectDomainQemuMonitorEventRegister; +} LIBVIRT_QEMU_0.10.0; -- 1.8.4.2

On Thu, Dec 19, 2013 at 08:15:09AM -0700, Eric Blake wrote:
diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c index db52c65..849932d 100644 --- a/src/libvirt-qemu.c +++ b/src/libvirt-qemu.c @@ -237,3 +237,126 @@ error: virDispatchError(conn); return NULL; } + + +/** + * virConnectDomainQemuMonitorEventRegister: + * @conn: pointer to the connection + * @dom: pointer to the domain, or NULL + * @event: name of the event, or NULL + * @cb: callback to the function handling monitor events + * @opaque: opaque data to pass on to the callback + * @freecb: optional function to deallocate opaque when not used anymore + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * This API is QEMU specific, so it will only work with hypervisor + * connections to the QEMU driver. + * + * Adds a callback to receive notifications of arbitrary qemu monitor events + * occurring on a domain. Many qemu monitor events also result in a libvirt + * event which can be delivered via virConnectDomainEventRegisterAny(); this + * command is primarily for testing new qemu events that have not yet been + * given a libvirt counterpart event. + * + * If @dom is NULL, then events will be monitored for any domain. If @dom + * is non-NULL, then only the specific domain will be monitored. + * + * If @event is NULL, then all monitor events will be reported. If @event is + * non-NULL, then only the specific monitor event will be reported. @flags + * is currently unused, but in the future may support a flag for passing + * @event as a glob instead of a literal name to match a category of events. + * + * The virDomainPtr object handle passed into the callback upon delivery + * of an event is only valid for the duration of execution of the callback. + * If the callback wishes to keep the domain object after the callback returns, + * it shall take a reference to it, by calling virDomainRef(). + * The reference can be released once the object is no longer required + * by calling virDomainFree(). + * + * The return value from this method is a positive integer identifier + * for the callback. To unregister a callback, this callback ID should + * be passed to the virConnectDomainQemuMonitorEventDeregister() method. + * + * Returns a callback identifier on success, -1 on failure + */ +int +virConnectDomainQemuMonitorEventRegister(virConnectPtr conn, + virDomainPtr dom, + const char *event, + virConnectDomainQemuMonitorEventCallback cb, + void *opaque, + virFreeCallback freecb, + unsigned int flags) +{ + VIR_DOMAIN_DEBUG(dom, + "conn=%p, event=%s, cb=%p, opaque=%p, freecb=%p, flags=%x", + conn, NULLSTR(event), cb, opaque, freecb, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + if (dom && + !(VIR_IS_CONNECTED_DOMAIN(dom) && dom->conn == conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(conn); + return -1; + } + virCheckNonNullArgGoto(cb, error)
I have a gut feeling that we should restrict use of this API to authenticated users only. So add a check for a read-only connection here
+ if ((conn->driver) && (conn->driver->connectDomainQemuMonitorEventRegister)) {
This is excessively bracketed isn't it
+ int ret; + ret = conn->driver->connectDomainQemuMonitorEventRegister(conn, dom, event, cb, opaque, freecb, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); +error: + virDispatchError(conn); + return -1; +} + +/** + * virConnectDomainQemuMonitorEventDeregister: + * @conn: pointer to the connection + * @callbackID: the callback identifier + * + * Removes an event callback. The callbackID parameter should be the + * value obtained from a previous virConnectDomainQemuMonitorEventRegister() + * method. + * + * Returns 0 on success, -1 on failure + */ +int +virConnectDomainQemuMonitorEventDeregister(virConnectPtr conn, + int callbackID) +{ + VIR_DEBUG("conn=%p, callbackID=%d", conn, callbackID); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + virCheckNonNegativeArgGoto(callbackID, error);
And add read-only check
+ + if ((conn->driver) && (conn->driver->connectDomainQemuMonitorEventDeregister)) {
To many brackets again
+ int ret; + ret = conn->driver->connectDomainQemuMonitorEventDeregister(conn, callbackID); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); +error: + virDispatchError(conn); + return -1; +}
Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 12/19/2013 08:23 AM, Daniel P. Berrange wrote:
On Thu, Dec 19, 2013 at 08:15:09AM -0700, Eric Blake wrote:
diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c index db52c65..849932d 100644
+ if (dom && + !(VIR_IS_CONNECTED_DOMAIN(dom) && dom->conn == conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(conn); + return -1; + } + virCheckNonNullArgGoto(cb, error)
I have a gut feeling that we should restrict use of this API to authenticated users only. So add a check for a read-only connection here
Hmm. It would match what we have for qemu-monitor-command; on the other hand, it differs from what we have for normal events (libvirt events are fine on a read-only connection). I guess an argument in favor of requiring write privileges is that qemu may expose details in its events that are better left internal to libvirt (that is, libvirt has a chance to scrub details before handing information to read-only guests, but with raw event handling, there is no scrubbing). And it's always easier to relax things later than it is to add read-write restrictions later and break existing callers that had grown used to read-only.
+ if ((conn->driver) && (conn->driver->connectDomainQemuMonitorEventRegister)) {
This is excessively bracketed isn't it
Copy-and-paste, all the way! I'll clean it up. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Thu, Dec 19, 2013 at 11:32:32AM -0700, Eric Blake wrote:
On 12/19/2013 08:23 AM, Daniel P. Berrange wrote:
On Thu, Dec 19, 2013 at 08:15:09AM -0700, Eric Blake wrote:
diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c index db52c65..849932d 100644
+ if (dom && + !(VIR_IS_CONNECTED_DOMAIN(dom) && dom->conn == conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(conn); + return -1; + } + virCheckNonNullArgGoto(cb, error)
I have a gut feeling that we should restrict use of this API to authenticated users only. So add a check for a read-only connection here
Hmm. It would match what we have for qemu-monitor-command; on the other hand, it differs from what we have for normal events (libvirt events are fine on a read-only connection). I guess an argument in favor of requiring write privileges is that qemu may expose details in its events that are better left internal to libvirt (that is, libvirt has a chance to scrub details before handing information to read-only guests, but with raw event handling, there is no scrubbing). And it's always easier to relax things later than it is to add read-write restrictions later and break existing callers that had grown used to read-only.
Yes, my concern is that there could one day be a QEMU event that includes some sensitive information in its parameters. Normal users should never need to use this API anyway, so restricting its access shouldn't really hurt people. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 19.12.2013 16:15, Eric Blake wrote:
Several times in the past, qemu has implemented a new event, but libvirt has not yet caught up to reporting that event to the user applications. While it is possible to track libvirt logs to see that an unknown event was received and ignored, it would be nicer to copy what 'virsh qemu-monitor-command' does, and expose this information to the end developer as one of our unsupported qemu-specific commands.
If you find yourself needing to use this API for more than just development purposes, please ask on the libvirt list for a supported counterpart event to be added in libvirt.so.
While the supported virConnectDomainEventRegisterAny() API takes an id which determines the signature of the callback, this version takes a string filter and always uses the same signature. Furthermore, I chose to expose this as a new API instead of trying to add a new eventID at the top level, in part because the generic option lacks event name filtering, and in part because the normal domain event namespace should not be polluted by a qemu-only event. I also added a flags argument; unused for now, but we might decide to use it to allow a user to request event names by glob or regex instead of literal match.
* include/libvirt/libvirt-qemu.h (virConnectDomainQemuMonitorEventCallback) (virConnectDomainQemuMonitorEventRegister) (virConnectDomainQemuMonitorEventDeregister): New prototypes. * src/libvirt-qemu.c (virConnectDomainQemuMonitorEventRegister) (virConnectDomainQemuMonitorEventDeregister): New functions. * src/libvirt_qemu.syms (LIBVIRT_QEMU_1.2.1): Export them. * src/driver.h (virDrvConnectDomainQemuMonitorEventRegister) (virDrvConnectDomainQemuMonitorEventDeregister): New callbacks.
Signed-off-by: Eric Blake <eblake@redhat.com> ---
Before I go and implement the guts of this new API, I first wanted to get approval from the list that I'm on the right track.
include/libvirt/libvirt-qemu.h | 31 ++++++++++- src/driver.h | 15 +++++ src/libvirt-qemu.c | 123 +++++++++++++++++++++++++++++++++++++++++ src/libvirt_qemu.syms | 6 ++ 4 files changed, 174 insertions(+), 1 deletion(-)
diff --git a/include/libvirt/libvirt-qemu.h b/include/libvirt/libvirt-qemu.h index 3e79a8c..5403093 100644 --- a/include/libvirt/libvirt-qemu.h +++ b/include/libvirt/libvirt-qemu.h @@ -4,7 +4,7 @@ * Description: Provides the interfaces of the libvirt library to handle * qemu specific methods * - * Copyright (C) 2010, 2012 Red Hat, Inc. + * Copyright (C) 2010, 2012-2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -54,6 +54,35 @@ typedef enum { char *virDomainQemuAgentCommand(virDomainPtr domain, const char *cmd, int timeout, unsigned int flags);
+/** + * virConnectDomainQemuMonitorEventCallback: + * @conn: the connection pointer + * @dom: the domain pointer + * @event: the name of the event + * @details: the JSON details of the event + * @opaque: application specified data + * + * The callback signature to use when registering for a qemu monitor + * event with virConnectDomainQemuMonitorEventRegister(). + */ +typedef void (*virConnectDomainQemuMonitorEventCallback)(virConnectPtr conn, + virDomainPtr dom, + const char *event, + const char *details, + void *opaque);
So for instance on this event: 2013-12-19 15:55:05.575+0000: 18630: debug : qemuMonitorJSONIOProcessLine:172 : QEMU_MONITOR_RECV_EVENT: mon=0x7f8c80008910 event={"timestamp": {"seconds": 1387468505, "microseconds": 574652}, "event": "SPICE_INITIALIZED", "data": {"server": {"auth": "none", "port": "5900", "family": "ipv4", "host": "127.0.0.1"}, "client": {"port": "39285", "family": "ipv4", "channel-type": 4, "connection-id": 375558326, "host": "127.0.0.1", "channel-id": 0, "tls": false}}} the callback will be invoked with: event="SPICE_INITIALIZED" details="{"server": {"auth": ....}}"? After all, I don't think we should do anything clever about it. Apps dealing with monitor/agent code (e.g. command passthru) are dealing with JSON anyway. Michal

On Thu, Dec 19, 2013 at 04:59:28PM +0100, Michal Privoznik wrote:
On 19.12.2013 16:15, Eric Blake wrote:
Several times in the past, qemu has implemented a new event, but libvirt has not yet caught up to reporting that event to the user applications. While it is possible to track libvirt logs to see that an unknown event was received and ignored, it would be nicer to copy what 'virsh qemu-monitor-command' does, and expose this information to the end developer as one of our unsupported qemu-specific commands.
If you find yourself needing to use this API for more than just development purposes, please ask on the libvirt list for a supported counterpart event to be added in libvirt.so.
While the supported virConnectDomainEventRegisterAny() API takes an id which determines the signature of the callback, this version takes a string filter and always uses the same signature. Furthermore, I chose to expose this as a new API instead of trying to add a new eventID at the top level, in part because the generic option lacks event name filtering, and in part because the normal domain event namespace should not be polluted by a qemu-only event. I also added a flags argument; unused for now, but we might decide to use it to allow a user to request event names by glob or regex instead of literal match.
* include/libvirt/libvirt-qemu.h (virConnectDomainQemuMonitorEventCallback) (virConnectDomainQemuMonitorEventRegister) (virConnectDomainQemuMonitorEventDeregister): New prototypes. * src/libvirt-qemu.c (virConnectDomainQemuMonitorEventRegister) (virConnectDomainQemuMonitorEventDeregister): New functions. * src/libvirt_qemu.syms (LIBVIRT_QEMU_1.2.1): Export them. * src/driver.h (virDrvConnectDomainQemuMonitorEventRegister) (virDrvConnectDomainQemuMonitorEventDeregister): New callbacks.
Signed-off-by: Eric Blake <eblake@redhat.com> ---
Before I go and implement the guts of this new API, I first wanted to get approval from the list that I'm on the right track.
include/libvirt/libvirt-qemu.h | 31 ++++++++++- src/driver.h | 15 +++++ src/libvirt-qemu.c | 123 +++++++++++++++++++++++++++++++++++++++++ src/libvirt_qemu.syms | 6 ++ 4 files changed, 174 insertions(+), 1 deletion(-)
diff --git a/include/libvirt/libvirt-qemu.h b/include/libvirt/libvirt-qemu.h index 3e79a8c..5403093 100644 --- a/include/libvirt/libvirt-qemu.h +++ b/include/libvirt/libvirt-qemu.h @@ -4,7 +4,7 @@ * Description: Provides the interfaces of the libvirt library to handle * qemu specific methods * - * Copyright (C) 2010, 2012 Red Hat, Inc. + * Copyright (C) 2010, 2012-2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -54,6 +54,35 @@ typedef enum { char *virDomainQemuAgentCommand(virDomainPtr domain, const char *cmd, int timeout, unsigned int flags);
+/** + * virConnectDomainQemuMonitorEventCallback: + * @conn: the connection pointer + * @dom: the domain pointer + * @event: the name of the event + * @details: the JSON details of the event + * @opaque: application specified data + * + * The callback signature to use when registering for a qemu monitor + * event with virConnectDomainQemuMonitorEventRegister(). + */ +typedef void (*virConnectDomainQemuMonitorEventCallback)(virConnectPtr conn, + virDomainPtr dom, + const char *event, + const char *details, + void *opaque);
So for instance on this event: 2013-12-19 15:55:05.575+0000: 18630: debug : qemuMonitorJSONIOProcessLine:172 : QEMU_MONITOR_RECV_EVENT: mon=0x7f8c80008910 event={"timestamp": {"seconds": 1387468505, "microseconds": 574652}, "event": "SPICE_INITIALIZED", "data": {"server": {"auth": "none", "port": "5900", "family": "ipv4", "host": "127.0.0.1"}, "client": {"port": "39285", "family": "ipv4", "channel-type": 4, "connection-id": 375558326, "host": "127.0.0.1", "channel-id": 0, "tls": false}}}
the callback will be invoked with: event="SPICE_INITIALIZED" details="{"server": {"auth": ....}}"?
After all, I don't think we should do anything clever about it. Apps dealing with monitor/agent code (e.g. command passthru) are dealing with JSON anyway.
Agreed, just sending out the JSON 'data' block as-is seems fine to me. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 12/19/2013 09:01 AM, Daniel P. Berrange wrote:
+typedef void (*virConnectDomainQemuMonitorEventCallback)(virConnectPtr conn, + virDomainPtr dom, + const char *event, + const char *details, + void *opaque);
So for instance on this event: 2013-12-19 15:55:05.575+0000: 18630: debug : qemuMonitorJSONIOProcessLine:172 : QEMU_MONITOR_RECV_EVENT: mon=0x7f8c80008910 event={"timestamp": {"seconds": 1387468505, "microseconds": 574652}, "event": "SPICE_INITIALIZED", "data": {"server": {"auth": "none", "port": "5900", "family": "ipv4", "host": "127.0.0.1"}, "client": {"port": "39285", "family": "ipv4", "channel-type": 4, "connection-id": 375558326, "host": "127.0.0.1", "channel-id": 0, "tls": false}}}
the callback will be invoked with: event="SPICE_INITIALIZED" details="{"server": {"auth": ....}}"?
Ooh, just noticed that the timestamp is not part of the event data; probably worth adding another parameter to the callback function to list the event timestamp (as knowing when qemu fired an event may indeed be important to a developer using this interface for debugging). What type would be best? Is it okay to tie our public interface to struct timespec (which in turn risks problems if a compile-time switch can move between 32- and 64-bit seconds since Epoch), or should I just open-code it to two parameters: 'long long seconds, int microseconds'?
After all, I don't think we should do anything clever about it. Apps dealing with monitor/agent code (e.g. command passthru) are dealing with JSON anyway.
Agreed, just sending out the JSON 'data' block as-is seems fine to me.
Sounds like I'm on the right track, then. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 19.12.2013 21:36, Eric Blake wrote:
On 12/19/2013 09:01 AM, Daniel P. Berrange wrote:
+typedef void (*virConnectDomainQemuMonitorEventCallback)(virConnectPtr conn, + virDomainPtr dom, + const char *event, + const char *details, + void *opaque);
So for instance on this event: 2013-12-19 15:55:05.575+0000: 18630: debug : qemuMonitorJSONIOProcessLine:172 : QEMU_MONITOR_RECV_EVENT: mon=0x7f8c80008910 event={"timestamp": {"seconds": 1387468505, "microseconds": 574652}, "event": "SPICE_INITIALIZED", "data": {"server": {"auth": "none", "port": "5900", "family": "ipv4", "host": "127.0.0.1"}, "client": {"port": "39285", "family": "ipv4", "channel-type": 4, "connection-id": 375558326, "host": "127.0.0.1", "channel-id": 0, "tls": false}}}
the callback will be invoked with: event="SPICE_INITIALIZED" details="{"server": {"auth": ....}}"?
Ooh, just noticed that the timestamp is not part of the event data; probably worth adding another parameter to the callback function to list the event timestamp (as knowing when qemu fired an event may indeed be important to a developer using this interface for debugging). What type would be best? Is it okay to tie our public interface to struct timespec (which in turn risks problems if a compile-time switch can move between 32- and 64-bit seconds since Epoch), or should I just open-code it to two parameters: 'long long seconds, int microseconds'?
Well, in qemu code base it seems like they're using struct timeval; but typecasting into int64_t both seconds and microseconds. So I'd say it's fine for us to go with ULL seconds, uint microseconds. Although I'm not that convinced that we should stick with unsigned, signed type will work too. At least for another ~25 years on my RPi :) Michal

On 12/20/2013 09:41 AM, Michal Privoznik wrote:
Ooh, just noticed that the timestamp is not part of the event data; probably worth adding another parameter to the callback function to list the event timestamp (as knowing when qemu fired an event may indeed be important to a developer using this interface for debugging). What type would be best? Is it okay to tie our public interface to struct timespec (which in turn risks problems if a compile-time switch can move between 32- and 64-bit seconds since Epoch), or should I just open-code it to two parameters: 'long long seconds, int microseconds'?
Well, in qemu code base it seems like they're using struct timeval; but typecasting into int64_t both seconds and microseconds. So I'd say it's fine for us to go with ULL seconds, uint microseconds. Although I'm not that convinced that we should stick with unsigned, signed type will work too. At least for another ~25 years on my RPi :)
I'm going signed LL for seconds (-1 if timestamp is not available), and uint for micros. Even if the host uses 32-bit time_t for seconds, it doesn't hurt us to pass the time as 64-bit; and by specifying it as explicit LL rather than time_t our header remains independent of host sizing changes. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (3)
-
Daniel P. Berrange
-
Eric Blake
-
Michal Privoznik