diff --git a/AUTHORS b/AUTHORS index b7c065f5a9..8cfa431249 100644 --- a/AUTHORS +++ b/AUTHORS @@ -52,6 +52,7 @@ Patches have also been contributed by: Nguyen Anh Quynh James Morris Chris Wrigh + Ben Guthro [....send patches to get your name here....] diff --git a/ChangeLog b/ChangeLog index f71715c49e..50f12fe8dd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +Thu Oct 23 15:11:03 CEST 2008 Daniel Veillard + + * include/libvirt/libvirt.h include/libvirt/libvirt.h.in + src/libvirt.c src/libvirt_sym.version: new libvirt event entry + points, big patch provided by Ben Guthro + * Makefile.am configure.in src/driver.h src/event.c src/event.h + src/internal.h src/libvirt.c src/libvirt_sym.version src/lxc_driver.c + src/openvz_driver.c src/qemu_conf.h src/qemu_driver.c + src/remote_internal.c src/storage_backend_fs.c src/test.c + qemud/event.c qemud/event.h qemud/mdns.c qemud/qemud.c + qemud/qemud.h qemud/remote.c qemud/remote_dispatch_localvars.h + qemud/remote_dispatch_proc_switch.h qemud/remote_dispatch_prototypes.h + qemud/remote_protocol.c qemud/remote_protocol.h + qemud/remote_protocol.x proxy/Makefile.am python/generator.py: + Not much is left untouched by the patch adding the events support + * docs/libvirt-api.xml docs/libvirt-refs.xml + docs/html/libvirt-libvirt.html: regenerated the docs + * examples/domain-events/events-c/Makefile.am + examples/domain-events/events-c/event-test.c: a test example + * AUTHORS: added Ben Guthro + Thu Oct 23 13:41:49 CEST 2008 Daniel Veillard * docs/apps.html docs/apps.html.in: update monitoring apps section diff --git a/Makefile.am b/Makefile.am index 073063d2b8..d40a151f50 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,7 +4,7 @@ LCOV = lcov GENHTML = genhtml SUBDIRS = gnulib/lib include src qemud proxy docs gnulib/tests \ - python tests po + python tests po examples/domain-events/events-c ACLOCAL_AMFLAGS = -I m4 -I gnulib/m4 diff --git a/configure.in b/configure.in index d2af4def03..2d7fb1468f 100644 --- a/configure.in +++ b/configure.in @@ -1067,7 +1067,8 @@ AC_OUTPUT(Makefile src/Makefile include/Makefile docs/Makefile \ tests/sexpr2xmldata/Makefile \ tests/xmconfigdata/Makefile \ tests/xencapsdata/Makefile \ - tests/virshdata/Makefile tests/confdata/Makefile) + tests/virshdata/Makefile tests/confdata/Makefile \ + examples/domain-events/events-c/Makefile) AC_MSG_NOTICE([]) AC_MSG_NOTICE([Configuration summary]) diff --git a/docs/devhelp/libvirt-libvirt.html b/docs/devhelp/libvirt-libvirt.html index 8cf657568d..592127a437 100644 --- a/docs/devhelp/libvirt-libvirt.html +++ b/docs/devhelp/libvirt-libvirt.html @@ -58,8 +58,9 @@ typedef struct _virConnect virConnect; typedef struct _virVcpuInfo virVcpuInfo; typedef struct _virDomainInfo virDomainInfo; typedef enum virStoragePoolDeleteFlags; +typedef enum virEventHandleType; typedef struct _virStoragePool virStoragePool; -typedef virStoragePool * virStoragePoolPtr; +typedef enum virDomainEventType; typedef struct _virDomainInterfaceStats virDomainInterfaceStatsStruct; typedef struct _virStoragePoolInfo virStoragePoolInfo; typedef enum virDomainState; @@ -69,6 +70,7 @@ typedef virConnectAuth * virStorageVolInfo; typedef enum virSchedParameterType; typedef virConnectCredential * virConnectCredentialPtr; +typedef virStoragePool * virStoragePoolPtr; typedef virNodeInfo * virNodeInfoPtr; typedef virNetwork * virNetworkPtr; typedef virDomainInfo * virDomainInfoPtr; @@ -95,14 +97,17 @@ typedef virStoragePoolInfo typedef enum virDomainCreateFlags; char * virStoragePoolGetXMLDesc (virStoragePoolPtr pool,
unsigned int flags); const char * virStorageVolGetKey (virStorageVolPtr vol); +typedef void virEventUpdateTimeoutFunc (int timer,
int timeout); int virConnectClose (virConnectPtr conn); virDomainPtr virDomainDefineXML (virConnectPtr conn,
const char * xml); int virDomainShutdown (virDomainPtr domain); int virConnectListStoragePools (virConnectPtr conn,
char ** const names,
int maxnames); int virGetVersion (unsigned long * libVer,
const char * type,
unsigned long * typeVer); int virNodeGetCellsFreeMemory (virConnectPtr conn,
unsigned long long * freeMems,
int startCell,
int maxCells); +int virInitialize (void); int virStoragePoolSetAutostart (virStoragePoolPtr pool,
int autostart); virStorageVolPtr virStorageVolCreateXML (virStoragePoolPtr pool,
const char * xmldesc,
unsigned int flags); +int virConnectDomainEventDeregister (virConnectPtr conn,
virConnectDomainEventCallback cb); int virDomainGetSchedulerParameters (virDomainPtr domain,
virSchedParameterPtr params,
int * nparams); virDomainPtr virDomainLookupByUUIDString (virConnectPtr conn,
const char * uuidstr); int virConnectNumOfDefinedNetworks (virConnectPtr conn); @@ -118,17 +123,18 @@ int virDomainSetAutostart (virStorageVolPtr virStorageVolLookupByName (virStoragePoolPtr pool,
const char * name); virDomainPtr virDomainCreateLinux (virConnectPtr conn,
const char * xmlDesc,
unsigned int flags); int virDomainSetMaxMemory (virDomainPtr domain,
unsigned long memory); -int virInitialize (void); +void virEventRegisterImpl (virEventAddHandleFunc addHandle,
virEventUpdateHandleFunc updateHandle,
virEventRemoveHandleFunc removeHandle,
virEventAddTimeoutFunc addTimeout,
virEventUpdateTimeoutFunc updateTimeout,
virEventRemoveTimeoutFunc removeTimeout); virDomainPtr virDomainMigrate (virDomainPtr domain,
virConnectPtr dconn,
unsigned long flags,
const char * dname,
const char * uri,
unsigned long bandwidth); int virDomainSuspend (virDomainPtr domain); int virNetworkCreate (virNetworkPtr network); +typedef void virEventUpdateHandleFunc (int fd,
int event); int virDomainDestroy (virDomainPtr domain); int virConnectNumOfNetworks (virConnectPtr conn); virStoragePoolPtr virStoragePoolLookupByUUIDString (virConnectPtr conn,
const char * uuidstr); char * virDomainGetXMLDesc (virDomainPtr domain,
int flags); int virStoragePoolGetUUID (virStoragePoolPtr pool,
unsigned char * uuid); int virStorageVolGetInfo (virStorageVolPtr vol,
virStorageVolInfoPtr info); -const char * virNetworkGetName (virNetworkPtr network); +int virDomainGetInfo (virDomainPtr domain,
virDomainInfoPtr info); int virNetworkDestroy (virNetworkPtr network); virStoragePoolPtr virStoragePoolLookupByName (virConnectPtr conn,
const char * name); int virNetworkGetAutostart (virNetworkPtr network,
int * autostart); @@ -150,16 +156,17 @@ int virStoragePoolFree (virDomainBlockStats (virDomainPtr dom,
const char * path,
virDomainBlockStatsPtr stats,
size_t size); virConnectPtr virConnectOpenAuth (const char * name,
virConnectAuthPtr auth,
int flags); int virStoragePoolDelete (virStoragePoolPtr pool,
unsigned int flags); -int virDomainResume (virDomainPtr domain); +typedef int virEventRemoveHandleFunc (int fd); const char * virStorageVolGetName (virStorageVolPtr vol); int virStoragePoolGetAutostart (virStoragePoolPtr pool,
int * autostart); int virDomainGetAutostart (virDomainPtr domain,
int * autostart); int virStoragePoolListVolumes (virStoragePoolPtr pool,
char ** const names,
int maxnames); char * virConnectGetHostname (virConnectPtr conn); +typedef int virEventRemoveTimeoutFunc (int timer); const char * virDomainGetName (virDomainPtr domain); char * virNetworkGetXMLDesc (virNetworkPtr network,
int flags); int virConnectNumOfStoragePools (virConnectPtr conn); -int virDomainGetInfo (virDomainPtr domain,
virDomainInfoPtr info); +const char * virNetworkGetName (virNetworkPtr network); int virConnectListDefinedDomains (virConnectPtr conn,
char ** const names,
int maxnames); char * virConnectGetCapabilities (virConnectPtr conn); virDomainPtr virDomainLookupByName (virConnectPtr conn,
const char * name); @@ -168,7 +175,9 @@ int virDomainPinVcpu (virDomainRestore (virConnectPtr conn,
const char * from); char * virStorageVolGetPath (virStorageVolPtr vol); virNetworkPtr virNetworkLookupByUUIDString (virConnectPtr conn,
const char * uuidstr); +typedef int virConnectDomainEventCallback (virConnectPtr conn,
virDomainPtr dom,
int event,
void * opaque); virDomainPtr virDomainLookupByID (virConnectPtr conn,
int id); +int virStorageVolDelete (virStorageVolPtr vol,
unsigned int flags); int virStorageVolFree (virStorageVolPtr vol); int virDomainMemoryPeek (virDomainPtr dom,
unsigned long long start,
size_t size,
void * buffer,
unsigned int flags); virNetworkPtr virNetworkLookupByUUID (virConnectPtr conn,
const unsigned char * uuid); @@ -178,6 +187,7 @@ int virDomainGetUUID (virDomainGetVcpus (virDomainPtr domain,
virVcpuInfoPtr info,
int maxinfo,
unsigned char * cpumaps,
int maplen); virStoragePoolPtr virStoragePoolCreateXML (virConnectPtr conn,
const char * xmlDesc,
unsigned int flags); int virStoragePoolGetInfo (virStoragePoolPtr pool,
virStoragePoolInfoPtr info); +int virDomainResume (virDomainPtr domain); int virStoragePoolRefresh (virStoragePoolPtr pool,
unsigned int flags); int virConnectNumOfDefinedDomains (virConnectPtr conn); virStorageVolPtr virStorageVolLookupByKey (virConnectPtr conn,
const char * key); @@ -186,6 +196,7 @@ int virDomainReboot (virNetworkGetUUIDString (virNetworkPtr network,
char * buf); virNetworkPtr virNetworkLookupByName (virConnectPtr conn,
const char * name); int virDomainGetMaxVcpus (virDomainPtr domain); +typedef void virEventHandleCallback (int fd,
int events,
void * opaque); char * virDomainGetSchedulerType (virDomainPtr domain,
int * nparams); int virDomainDetachDevice (virDomainPtr domain,
const char * xml); int virStoragePoolNumOfVolumes (virStoragePoolPtr pool); @@ -197,9 +208,10 @@ char * virConnectGetURI (virConnectPtr virConnectOpenReadOnly (const char * name); int virNetworkFree (virNetworkPtr network); virStoragePoolPtr virStoragePoolLookupByUUID (virConnectPtr conn,
const unsigned char * uuid); -int virStorageVolDelete (virStorageVolPtr vol,
unsigned int flags); +typedef int virEventAddHandleFunc (int fd,
int event,
virEventHandleCallback cb,
void * opaque); int virNetworkUndefine (virNetworkPtr network); int virConnectListDefinedStoragePools (virConnectPtr conn,
char ** const names,
int maxnames); +typedef void virEventTimeoutCallback (int timer,
void * opaque); virConnectPtr virNetworkGetConnect (virNetworkPtr net); unsigned long long virNodeGetFreeMemory (virConnectPtr conn); virConnectPtr virStorageVolGetConnect (virStorageVolPtr vol); @@ -215,8 +227,10 @@ int virConnectNumOfDefinedStorageP virConnectPtr virConnectOpen (const char * name); virDomainPtr virDomainCreateXML (virConnectPtr conn,
const char * xmlDesc,
unsigned int flags); int virDomainSetVcpus (virDomainPtr domain,
unsigned int nvcpus); +int virConnectDomainEventRegister (virConnectPtr conn,
virConnectDomainEventCallback cb,
void * opaque); unsigned int virDomainGetID (virDomainPtr domain); int virDomainBlockPeek (virDomainPtr dom,
const char * path,
unsigned long long offset,
size_t size,
void * buffer,
unsigned int flags); +typedef int virEventAddTimeoutFunc (int timeout,
virEventTimeoutCallback cb,
void * opaque); int virDomainInterfaceStats (virDomainPtr dom,
const char * path,
virDomainInterfaceStatsPtr stats,
size_t size); int virConnectListNetworks (virConnectPtr conn,
char ** const names,
int maxnames); @@ -353,6 +367,19 @@ The content of this structure is not made public by the API. VIR_DOMAIN_NONE = 0 };

+ +


+

Structure virDomainInfo

struct _virDomainInfo {
@@ -419,6 +446,15 @@ The content of this structure is not made public by the API.
     VIR_DOMAIN_XML_INACTIVE = 2 /*  dump inactive domain information */
 };
 

+

+
+

Structure virNetwork

struct _virNetwork {
@@ -577,6 +613,42 @@ The content of this structure is not made public by the API.
         

Function type virConnectAuthCallbackPtr

int	virConnectAuthCallbackPtr	(virConnectCredentialPtr cred, 
unsigned int ncred,
void * cbdata)

cred:
ncred:
cbdata:
Returns:
+
+

Function type virConnectDomainEventCallback

int	virConnectDomainEventCallback	(virConnectPtr conn, 
virDomainPtr dom,
int event,
void * opaque)
+

A callback function to be registered, and called when a domain event occurs

+
conn:virConnect connection
dom:The domain on which the event occured
event:The specfic virDomainEventType which occured
opaque:opaque user data
Returns:
+
+

Function type virEventAddHandleFunc

int	virEventAddHandleFunc		(int fd, 
int event,
virEventHandleCallback cb,
void * opaque)
+

Part of the EventImpl, this callback Adds a file handle callback to listen for specific events

+
fd:file descriptor to listen on
event:bitset of events on which to fire the callback
cb:the callback to be called
opaque:user data to pass to the callback
Returns:
+
+

Function type virEventAddTimeoutFunc

int	virEventAddTimeoutFunc		(int timeout, 
virEventTimeoutCallback cb,
void * opaque)
+

Part of the EventImpl, this user-defined callback handles adding an event timeout.

+
timeout:The timeout to monitor
cb:the callback to call when timeout has expired
opaque:user data to pass to the callback
Returns:a timer value
+
+ +
+
+
+
+
+
+
+
+
+

Variable virConnectAuthPtrDefault

virConnectAuthPtr virConnectAuthPtrDefault;
 

@@ -585,6 +657,14 @@ The content of this structure is not made public by the API.

virConnectClose ()

int	virConnectClose			(virConnectPtr conn)

This function closes the connection to the Hypervisor. This should not be called if further interaction with the Hypervisor are needed especially if there is running domain which need further monitoring by the application.

conn:pointer to the hypervisor connection
Returns:0 in case of success or -1 in case of error.
+
+

virConnectDomainEventDeregister ()

int	virConnectDomainEventDeregister	(virConnectPtr conn, 
virConnectDomainEventCallback cb)
+

Removes a Domain Event Callback. De-registering for a domain callback will disable delivery of this event type

+
conn:pointer to the connection
cb:callback to the function handling domain events
Returns:0 on success, -1 on failure
+
+

virConnectDomainEventRegister ()

int	virConnectDomainEventRegister	(virConnectPtr conn, 
virConnectDomainEventCallback cb,
void * opaque)
+

Adds a Domain Event Callback. Registering for a domain callback will enable delivery of the events

+
conn:pointer to the connection
cb:callback to the function handling domain events
opaque:opaque data to pass on to the callback
Returns:0 on success, -1 on failure

virConnectFindStoragePoolSources ()

char *	virConnectFindStoragePoolSources	(virConnectPtr conn, 
const char * type,
const char * srcSpec,
unsigned int flags)

Talks to a storage backend and attempts to auto-discover the set of available storage pool sources. e.g. For iSCSI this would be a set of iSCSI targets. For NFS this would be a list of exported paths. The srcSpec (optional for some storage pool types, e.g. local ones) is an instance of the storage pool's source element specifying where to look for the pools. srcSpec is not required for some types (e.g., those querying local storage resources only)

@@ -853,6 +933,10 @@ The content of this structure is not made public by the API.

virDomainUndefine ()

int	virDomainUndefine		(virDomainPtr domain)

Undefine a domain but does not stop it if it is running

domain:pointer to a defined domain
Returns:0 in case of success, -1 in case of error
+
+

virEventRegisterImpl ()

void	virEventRegisterImpl		(virEventAddHandleFunc addHandle, 
virEventUpdateHandleFunc updateHandle,
virEventRemoveHandleFunc removeHandle,
virEventAddTimeoutFunc addTimeout,
virEventUpdateTimeoutFunc updateTimeout,
virEventRemoveTimeoutFunc removeTimeout)
+

+

addHandle:
updateHandle:
removeHandle:
addTimeout:
updateTimeout:
removeTimeout:

virGetVersion ()

int	virGetVersion			(unsigned long * libVer, 
const char * type,
unsigned long * typeVer)

Provides two information back, @libVer is the version of the library while @typeVer will be the version of the hypervisor type @type against which the library was compiled. If @type is NULL, "Xen" is assumed, if @type is unknown or not available, an error code will be returned and @typeVer will be 0.

diff --git a/docs/html/libvirt-libvirt.html b/docs/html/libvirt-libvirt.html index edaec1590a..2b2a1ec17c 100644 --- a/docs/html/libvirt-libvirt.html +++ b/docs/html/libvirt-libvirt.html @@ -26,6 +26,7 @@ typedef struct _virDomain virDomain typedef virDomainBlockStatsStruct * virDomainBlockStatsPtr typedef struct _virDomainBlockStats virDomainBlockStatsStruct typedef enum virDomainCreateFlags +typedef enum virDomainEventType typedef struct _virDomainInfo virDomainInfo typedef virDomainInfo * virDomainInfoPtr typedef virDomainInterfaceStatsStruct * virDomainInterfaceStatsPtr @@ -35,6 +36,7 @@ typedef enum virDomainMigrateFlags typedef virDomain * virDomainPtr typedef enum virDomainState typedef enum virDomainXMLFlags +typedef enum virEventHandleType typedef struct _virNetwork virNetwork typedef virNetwork * virNetworkPtr typedef struct _virNodeInfo virNodeInfo @@ -62,6 +64,11 @@ typedef enum virVcpuState int virConnectAuthCallbackPtr (virConnectCredentialPtr cred,
unsigned int ncred,
void * cbdata) int virConnectClose (virConnectPtr conn) +typedef virConnectDomainEventCallback +int virConnectDomainEventCallback (virConnectPtr conn,
virDomainPtr dom,
int event,
void * opaque) + +int virConnectDomainEventDeregister (virConnectPtr conn,
virConnectDomainEventCallback cb) +int virConnectDomainEventRegister (virConnectPtr conn,
virConnectDomainEventCallback cb,
void * opaque) char * virConnectFindStoragePoolSources (virConnectPtr conn,
const char * type,
const char * srcSpec,
unsigned int flags) char * virConnectGetCapabilities (virConnectPtr conn) char * virConnectGetHostname (virConnectPtr conn) @@ -129,6 +136,31 @@ int virDomainSetVcpus (virDomainShutdown (virDomainPtr domain) int virDomainSuspend (virDomainPtr domain) int virDomainUndefine (virDomainPtr domain) +typedef virEventAddHandleFunc +int virEventAddHandleFunc (int fd,
int event,
virEventHandleCallback cb,
void * opaque) + +typedef virEventAddTimeoutFunc +int virEventAddTimeoutFunc (int timeout,
virEventTimeoutCallback cb,
void * opaque) + +typedef virEventHandleCallback +void virEventHandleCallback (int fd,
int events,
void * opaque) + +void virEventRegisterImpl (virEventAddHandleFunc addHandle,
virEventUpdateHandleFunc updateHandle,
virEventRemoveHandleFunc removeHandle,
virEventAddTimeoutFunc addTimeout,
virEventUpdateTimeoutFunc updateTimeout,
virEventRemoveTimeoutFunc removeTimeout) +typedef virEventRemoveHandleFunc +int virEventRemoveHandleFunc (int fd) + +typedef virEventRemoveTimeoutFunc +int virEventRemoveTimeoutFunc (int timer) + +typedef virEventTimeoutCallback +void virEventTimeoutCallback (int timer,
void * opaque) + +typedef virEventUpdateHandleFunc +void virEventUpdateHandleFunc (int fd,
int event) + +typedef virEventUpdateTimeoutFunc +void virEventUpdateTimeoutFunc (int timer,
int timeout) + int virGetVersion (unsigned long * libVer,
const char * type,
unsigned long * typeVer) int virInitialize (void) int virNetworkCreate (virNetworkPtr network) @@ -207,6 +239,8 @@ char * virStorageVolGetXMLDesc (

virDomainCreateFlags

enum virDomainCreateFlags {
 
VIR_DOMAIN_NONE = 0
}
+

virDomainEventType

virDomainInfo

virDomainXMLFlags

enum virDomainXMLFlags {
 
VIR_DOMAIN_XML_SECURE = 1 : dump security sensitive information too
VIR_DOMAIN_XML_INACTIVE = 2 : dump inactive domain information
}
+

virEventHandleType

virNetwork

Functions

virConnectAuthCallbackPtr

typedef int	(*virConnectAuthCallbackPtr)	(virConnectCredentialPtr cred, 
unsigned int ncred,
void * cbdata)

cred:
ncred:
cbdata:
Returns:

virConnectClose

int	virConnectClose			(virConnectPtr conn)
-

This function closes the connection to the Hypervisor. This should not be called if further interaction with the Hypervisor are needed especially if there is running domain which need further monitoring by the application.

conn:pointer to the hypervisor connection
Returns:0 in case of success or -1 in case of error.

virConnectFindStoragePoolSources

char *	virConnectFindStoragePoolSources	(virConnectPtr conn, 
const char * type,
const char * srcSpec,
unsigned int flags)
+

This function closes the connection to the Hypervisor. This should not be called if further interaction with the Hypervisor are needed especially if there is running domain which need further monitoring by the application.

conn:pointer to the hypervisor connection
Returns:0 in case of success or -1 in case of error.

virConnectDomainEventCallback

typedef int	(*virConnectDomainEventCallback)	(virConnectPtr conn, 
virDomainPtr dom,
int event,
void * opaque) +

A callback function to be registered, and called when a domain event occurs

conn:virConnect connection
dom:The domain on which the event occured
event:The specfic virDomainEventType which occured
opaque:opaque user data
Returns:

virConnectDomainEventDeregister

int	virConnectDomainEventDeregister	(virConnectPtr conn, 
virConnectDomainEventCallback cb)
+

Removes a Domain Event Callback. De-registering for a domain callback will disable delivery of this event type

conn:pointer to the connection
cb:callback to the function handling domain events
Returns:0 on success, -1 on failure

virConnectDomainEventRegister

int	virConnectDomainEventRegister	(virConnectPtr conn, 
virConnectDomainEventCallback cb,
void * opaque)
+

Adds a Domain Event Callback. Registering for a domain callback will enable delivery of the events

conn:pointer to the connection
cb:callback to the function handling domain events
opaque:opaque data to pass on to the callback
Returns:0 on success, -1 on failure

virConnectFindStoragePoolSources

char *	virConnectFindStoragePoolSources	(virConnectPtr conn, 
const char * type,
const char * srcSpec,
unsigned int flags)

Talks to a storage backend and attempts to auto-discover the set of available storage pool sources. e.g. For iSCSI this would be a set of iSCSI targets. For NFS this would be a list of exported paths. The srcSpec (optional for some storage pool types, e.g. local ones) is an instance of the storage pool's source element specifying where to look for the pools. srcSpec is not required for some types (e.g., those querying local storage resources only)

conn:pointer to hypervisor connection
type:type of storage pool sources to discover
srcSpec:XML document specifying discovery source
flags:flags for discovery (unused, pass 0)
Returns:an xml document consisting of a SourceList element containing a source document appropriate to the given pool type for each discovered source.

virConnectGetCapabilities

char *	virConnectGetCapabilities	(virConnectPtr conn)

Provides capabilities of the hypervisor / driver.

conn:pointer to the hypervisor connection
Returns:NULL in case of error, or an XML string defining the capabilities. The client must free the returned string after use.

virConnectGetHostname

char *	virConnectGetHostname		(virConnectPtr conn)

This returns the system hostname on which the hypervisor is running (the result of the gethostname(2) system call). If we are connected to a remote system, then this returns the hostname of the remote system.

conn:pointer to a hypervisor connection
Returns:the hostname which must be freed by the caller, or NULL if there was an error.

virConnectGetMaxVcpus

int	virConnectGetMaxVcpus		(virConnectPtr conn, 
const char * type)
@@ -328,7 +367,16 @@ char * virStorageVolGetXMLDesc (

Dynamically change the number of virtual CPUs used by the domain. Note that this call may fail if the underlying virtualization hypervisor does not support it or if growing the number is arbitrary limited. This function requires privileged access to the hypervisor.

domain:pointer to domain object, or NULL for Domain0
nvcpus:the new number of virtual CPUs for this domain
Returns:0 in case of success, -1 in case of failure.

virDomainShutdown

int	virDomainShutdown		(virDomainPtr domain)

Shutdown a domain, the domain object is still usable there after but the domain OS is being stopped. Note that the guest OS may ignore the request. TODO: should we add an option for reboot, knowing it may not be doable in the general case ?

domain:a domain object
Returns:0 in case of success and -1 in case of failure.

virDomainSuspend

int	virDomainSuspend		(virDomainPtr domain)

Suspends an active domain, the process is frozen without further access to CPU resources and I/O but the memory used by the domain at the hypervisor level will stay allocated. Use virDomainResume() to reactivate the domain. This function may requires privileged access.

domain:a domain object
Returns:0 in case of success and -1 in case of failure.

virDomainUndefine

int	virDomainUndefine		(virDomainPtr domain)
-

Undefine a domain but does not stop it if it is running

domain:pointer to a defined domain
Returns:0 in case of success, -1 in case of error

virGetVersion

int	virGetVersion			(unsigned long * libVer, 
const char * type,
unsigned long * typeVer)
+

Undefine a domain but does not stop it if it is running

domain:pointer to a defined domain
Returns:0 in case of success, -1 in case of error

virEventAddHandleFunc

typedef int	(*virEventAddHandleFunc	)	(int fd, 
int event,
virEventHandleCallback cb,
void * opaque) +

Part of the EventImpl, this callback Adds a file handle callback to listen for specific events

fd:file descriptor to listen on
event:bitset of events on which to fire the callback
cb:the callback to be called
opaque:user data to pass to the callback
Returns:

virEventAddTimeoutFunc

typedef int	(*virEventAddTimeoutFunc	)	(int timeout, 
virEventTimeoutCallback cb,
void * opaque) +

Part of the EventImpl, this user-defined callback handles adding an event timeout.

timeout:The timeout to monitor
cb:the callback to call when timeout has expired
opaque:user data to pass to the callback
Returns:a timer value

virEventHandleCallback

typedef void	(*virEventHandleCallback	)	(int fd, 
int events,
void * opaque) +

callback for receiving file handle events

fd:file handle on which the event occurred
events:bitset of events from virEventHandleType constants
opaque:user data registered with handle

virEventRegisterImpl

void	virEventRegisterImpl		(virEventAddHandleFunc addHandle, 
virEventUpdateHandleFunc updateHandle,
virEventRemoveHandleFunc removeHandle,
virEventAddTimeoutFunc addTimeout,
virEventUpdateTimeoutFunc updateTimeout,
virEventRemoveTimeoutFunc removeTimeout)
+

addHandle:
updateHandle:
removeHandle:
addTimeout:
updateTimeout:
removeTimeout:

virEventRemoveHandleFunc

typedef int	(*virEventRemoveHandleFunc)	(int fd)
+

Part of the EventImpl, this user-provided callback is notified when an fd is no longer being listened on

fd:file descriptor to stop listening on
Returns:

virEventRemoveTimeoutFunc

typedef int	(*virEventRemoveTimeoutFunc)	(int timer)
+

Part of the EventImpl, this user-defined callback removes a timer

timer:the timer to remove
Returns:0 on success, -1 on failure

virEventTimeoutCallback

typedef void	(*virEventTimeoutCallback	)	(int timer, 
void * opaque) +

callback for receiving timer events

timer:timer id emitting the event
opaque:user data registered with handle

virEventUpdateHandleFunc

typedef void	(*virEventUpdateHandleFunc)	(int fd, 
int event) +

Part of the EventImpl, this user-provided callback is notified when events to listen on change

fd:file descriptor to modify
event:new events to listen on

virEventUpdateTimeoutFunc

typedef void	(*virEventUpdateTimeoutFunc)	(int timer, 
int timeout) +

Part of the EventImpl, this user-defined callback updates an event timeout.

timer:the timer to modify
timeout:the new timeout value

virGetVersion

int	virGetVersion			(unsigned long * libVer, 
const char * type,
unsigned long * typeVer)

Provides two information back, @libVer is the version of the library while @typeVer will be the version of the hypervisor type @type against which the library was compiled. If @type is NULL, "Xen" is assumed, if @type is unknown or not available, an error code will be returned and @typeVer will be 0.

libVer:return value for the library version (OUT)
type:the type of connection/driver looked at
typeVer:return value for the version of the hypervisor (OUT)
Returns:-1 in case of failure, 0 otherwise, and values for @libVer and @typeVer have the format major * 1,000,000 + minor * 1,000 + release.

virInitialize

int	virInitialize			(void)

Initialize the library. It's better to call this routine at startup in multithreaded applications to avoid potential race when initializing the library.

Returns:0 in case of success, -1 in case of error

virNetworkCreate

int	virNetworkCreate		(virNetworkPtr network)

Create and start a defined network. If the call succeed the network moves from the defined to the running networks pools.

network:pointer to a defined network
Returns:0 in case of success, -1 in case of error

virNetworkCreateXML

virNetworkPtr	virNetworkCreateXML	(virConnectPtr conn, 
const char * xmlDesc)
diff --git a/docs/libvirt-api.xml b/docs/libvirt-api.xml index d45049076c..de33b9b7ce 100644 --- a/docs/libvirt-api.xml +++ b/docs/libvirt-api.xml @@ -18,48 +18,60 @@ + + + - + + + + - + + - + + - + + - + + + - + + - + @@ -69,8 +81,9 @@ + - + @@ -80,6 +93,7 @@ + @@ -117,14 +131,17 @@ + + + @@ -140,17 +157,18 @@ - + + - + @@ -172,16 +190,17 @@ - + + - + @@ -190,7 +209,9 @@ + + @@ -200,6 +221,7 @@ + @@ -208,6 +230,7 @@ + @@ -219,9 +242,10 @@ - + + @@ -237,8 +261,10 @@ + + @@ -403,6 +429,14 @@ + + + + + + + + @@ -469,6 +503,10 @@ + + + + @@ -544,6 +582,7 @@ + @@ -595,6 +634,7 @@ see note above'/> + a virNetworkPtr is pointer to a virNetwork private structure, this is the type used to reference a virtual network in the API. @@ -690,6 +730,27 @@ see note above'/> + + A callback function to be registered, and called when a domain event occurs + + + + + + + + Removes a Domain Event Callback. De-registering for a domain callback will disable delivery of this event type + + + + + + Adds a Domain Event Callback. Registering for a domain callback will enable delivery of the events + + + + + Talks to a storage backend and attempts to auto-discover the set of available storage pool sources. e.g. For iSCSI this would be a set of iSCSI targets. For NFS this would be a list of exported paths. The srcSpec (optional for some storage pool types, e.g. local ones) is an instance of the storage pool's source element specifying where to look for the pools. srcSpec is not required for some types (e.g., those querying local storage resources only) @@ -1117,6 +1178,66 @@ see note above'/> + + Part of the EventImpl, this callback Adds a file handle callback to listen for specific events + + + + + + + + Part of the EventImpl, this user-defined callback handles adding an event timeout. + + + + + + + callback for receiving file handle events + + + + + + + + + + + + + + + + + Part of the EventImpl, this user-provided callback is notified when an fd is no longer being listened on + + + + + Part of the EventImpl, this user-defined callback removes a timer + + + + + callback for receiving timer events + + + + + + Part of the EventImpl, this user-provided callback is notified when events to listen on change + + + + + + Part of the EventImpl, this user-defined callback updates an event timeout. + + + + Provide a pointer to the last error caught at the library level Simpler but may not be suitable for multithreaded accesses, in which case use virCopyLastError() diff --git a/docs/libvirt-refs.xml b/docs/libvirt-refs.xml index 710c0b2b81..7f987702a7 100644 --- a/docs/libvirt-refs.xml +++ b/docs/libvirt-refs.xml @@ -17,6 +17,14 @@ + + + + + + + + @@ -84,6 +92,10 @@ + + + + @@ -155,6 +167,9 @@ + + + @@ -195,6 +210,7 @@ + @@ -245,6 +261,16 @@ + + + + + + + + + + @@ -350,6 +376,14 @@ + + + + + + + + @@ -417,6 +451,10 @@ + + + + @@ -492,6 +530,9 @@ + + + @@ -532,6 +573,7 @@ + @@ -582,6 +624,16 @@ + + + + + + + + + + @@ -801,12 +853,19 @@ + + + + + + + @@ -861,6 +920,7 @@ + @@ -910,6 +970,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -975,9 +1059,15 @@ + + + + + + @@ -999,6 +1089,14 @@ + + + + + + + + @@ -1014,6 +1112,10 @@ + + + + @@ -1057,6 +1159,9 @@ + + + @@ -1095,6 +1200,7 @@ + @@ -1139,6 +1245,16 @@ + + + + + + + + + + @@ -1335,6 +1451,10 @@ + + + + @@ -1393,6 +1513,8 @@ + + @@ -1428,6 +1550,9 @@ + + + @@ -1455,6 +1580,10 @@ + + + + @@ -1478,6 +1607,18 @@ + + + + + + + + + + + + @@ -1666,6 +1807,14 @@ + + + + + + + + @@ -1716,12 +1865,18 @@ + + + + + + @@ -1991,6 +2146,9 @@ + + + @@ -2254,6 +2412,7 @@ + @@ -2286,6 +2445,10 @@ + + + + @@ -2354,6 +2517,7 @@ + @@ -2363,16 +2527,29 @@ + + + + + + + + + + + + + @@ -2456,6 +2633,7 @@ + @@ -2541,6 +2719,7 @@ + @@ -2645,8 +2824,14 @@ + + + + + + @@ -2688,6 +2873,10 @@ + + + + @@ -2712,6 +2901,11 @@ + + + + + @@ -2750,6 +2944,9 @@ + + + @@ -2860,6 +3057,12 @@ + + + + + + @@ -2882,6 +3085,22 @@ + + + + + + + + + + + + + + + + @@ -2898,6 +3117,9 @@ + + + @@ -2964,6 +3186,10 @@ + + + + @@ -2985,6 +3211,9 @@ + + + @@ -3094,6 +3323,7 @@ + @@ -3102,32 +3332,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3214,14 +3418,22 @@ + + + + + + + + @@ -3236,6 +3448,7 @@ + @@ -3491,6 +3704,8 @@ + + @@ -3615,6 +3830,16 @@ + + + + + + + + + + @@ -3635,6 +3860,9 @@ + + + @@ -3654,8 +3882,6 @@ - - @@ -3787,9 +4013,16 @@ + + + + + + + @@ -3842,6 +4075,8 @@ + + @@ -3910,6 +4145,8 @@ + + @@ -3943,6 +4180,10 @@ + + + + @@ -3965,10 +4206,17 @@ + + + + + + + @@ -3998,6 +4246,10 @@ + + + + @@ -4059,8 +4311,6 @@ - - @@ -4094,10 +4344,13 @@ + + + @@ -4241,6 +4494,8 @@ + + @@ -4292,6 +4547,10 @@ + + + + @@ -4310,6 +4569,11 @@ + + + + + @@ -4340,6 +4604,12 @@ + + + + + + @@ -4499,8 +4769,6 @@ - - @@ -4626,8 +4894,12 @@ + + + + @@ -4702,6 +4974,7 @@ + @@ -4817,6 +5090,8 @@ + + @@ -4921,6 +5196,16 @@ + + + + + + + + + + @@ -4946,6 +5231,7 @@ + @@ -4960,8 +5246,6 @@ - - @@ -5010,6 +5294,9 @@ + + + @@ -5077,12 +5364,26 @@ + + + + + + + + + + + + + + @@ -5090,6 +5391,8 @@ + + @@ -5101,6 +5404,8 @@ + + @@ -5131,6 +5436,9 @@ + + + @@ -5163,6 +5471,9 @@ + + + @@ -5222,6 +5533,9 @@ + + + @@ -5304,8 +5618,6 @@ - - @@ -5326,10 +5638,14 @@ + + + + @@ -5353,6 +5669,7 @@ + @@ -5362,6 +5679,8 @@ + + @@ -5427,6 +5746,8 @@ + + @@ -5468,12 +5789,13 @@ - - - - - - + + + + + + + diff --git a/examples/domain-events/events-c/Makefile.am b/examples/domain-events/events-c/Makefile.am new file mode 100644 index 0000000000..60b15898c6 --- /dev/null +++ b/examples/domain-events/events-c/Makefile.am @@ -0,0 +1,5 @@ +INCLUDES = -I@top_srcdir@/include +noinst_PROGRAMS = event-test +event_test_CFLAGS = $(WARN_CFLAGS) +event_test_SOURCES = event-test.c +event_test_LDADD = @top_builddir@/src/libvirt.la diff --git a/examples/domain-events/events-c/event-test.c b/examples/domain-events/events-c/event-test.c new file mode 100644 index 0000000000..4c748c841a --- /dev/null +++ b/examples/domain-events/events-c/event-test.c @@ -0,0 +1,261 @@ +#include +#include +#include +#include +#include +#include + +#define DEBUG0(fmt) printf("%s:%d :: " fmt "\n", \ + __FUNCTION__, __LINE__) +#define DEBUG(fmt, ...) printf("%s:%d: " fmt "\n", \ + __FUNCTION__, __LINE__, __VA_ARGS__) +#define STREQ(a,b) (strcmp((a),(b)) == 0) + +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__((__unused__)) +#endif + +/* handle globals */ +int h_fd = 0; +virEventHandleType h_event = 0; +virEventHandleCallback h_cb = NULL; +void *h_opaque = NULL; + +/* timeout globals */ +#define TIMEOUT_MS 1000 +int t_active = 0; +int t_timeout = -1; +virEventTimeoutCallback t_cb = NULL; +void *t_opaque = NULL; + + +/* Prototypes */ +const char *eventToString(int event); +int myDomainEventCallback1 (virConnectPtr conn, virDomainPtr dom, + int event, void *opaque); +int myDomainEventCallback2 (virConnectPtr conn, virDomainPtr dom, + int event, void *opaque); +int myEventAddHandleFunc (int fd, int event, + virEventHandleCallback cb, void *opaque); +void myEventUpdateHandleFunc(int fd, int event); +int myEventRemoveHandleFunc(int fd); + +int myEventAddTimeoutFunc(int timeout, virEventTimeoutCallback cb, + void *opaque); +void myEventUpdateTimeoutFunc(int timer, int timout); +int myEventRemoveTimeoutFunc(int timer); + +int myEventHandleTypeToPollEvent(virEventHandleType events); +virEventHandleType myPollEventToEventHandleType(int events); + +void usage(const char *pname); + +/* Callback functions */ + +const char *eventToString(int event) { + const char *ret = NULL; + switch(event) { + case VIR_DOMAIN_EVENT_ADDED: + ret ="Added"; + break; + case VIR_DOMAIN_EVENT_REMOVED: + ret ="Removed"; + break; + case VIR_DOMAIN_EVENT_STARTED: + ret ="Started"; + break; + case VIR_DOMAIN_EVENT_SUSPENDED: + ret ="Suspended"; + break; + case VIR_DOMAIN_EVENT_RESUMED: + ret ="Resumed"; + break; + case VIR_DOMAIN_EVENT_STOPPED: + ret ="Stopped"; + break; + case VIR_DOMAIN_EVENT_SAVED: + ret ="Saved"; + break; + case VIR_DOMAIN_EVENT_RESTORED: + ret ="Restored"; + break; + default: + ret ="Unknown Event"; + } + return ret; +} + +int myDomainEventCallback1 (virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + int event, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) %s\n", __FUNCTION__, virDomainGetName(dom), + virDomainGetID(dom), eventToString(event)); + return 0; +} + +int myDomainEventCallback2 (virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + int event, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) %s\n", __FUNCTION__, virDomainGetName(dom), + virDomainGetID(dom), eventToString(event)); + return 0; +} + + +/* EventImpl Functions */ +int myEventHandleTypeToPollEvent(virEventHandleType events) +{ + int ret = 0; + if(events & VIR_EVENT_HANDLE_READABLE) + ret |= POLLIN; + if(events & VIR_EVENT_HANDLE_WRITABLE) + ret |= POLLOUT; + if(events & VIR_EVENT_HANDLE_ERROR) + ret |= POLLERR; + if(events & VIR_EVENT_HANDLE_HANGUP) + ret |= POLLHUP; + return ret; +} + +virEventHandleType myPollEventToEventHandleType(int events) +{ + virEventHandleType ret = 0; + if(events & POLLIN) + ret |= VIR_EVENT_HANDLE_READABLE; + if(events & POLLOUT) + ret |= VIR_EVENT_HANDLE_WRITABLE; + if(events & POLLERR) + ret |= VIR_EVENT_HANDLE_ERROR; + if(events & POLLHUP) + ret |= VIR_EVENT_HANDLE_HANGUP; + return ret; +} + +int myEventAddHandleFunc(int fd, int event, + virEventHandleCallback cb, void *opaque) +{ + DEBUG("Add handle %d %d %p %p", fd, event, cb, opaque); + h_fd = fd; + h_event = myEventHandleTypeToPollEvent(event); + h_cb = cb; + h_opaque = opaque; + return 0; +} + +void myEventUpdateHandleFunc(int fd, int event) +{ + DEBUG("Updated Handle %d %d", fd, event); + h_event = myEventHandleTypeToPollEvent(event); + return; +} + +int myEventRemoveHandleFunc(int fd) +{ + DEBUG("Removed Handle %d", fd); + h_fd = 0; + return 0; +} + +int myEventAddTimeoutFunc(int timeout, virEventTimeoutCallback cb, + void *opaque) +{ + DEBUG("Adding Timeout %d %p %p", timeout, cb, opaque); + t_active = 1; + t_timeout = timeout; + t_cb = cb; + t_opaque = opaque; + return 0; +} + +void myEventUpdateTimeoutFunc(int timer ATTRIBUTE_UNUSED, int timeout) +{ + /*DEBUG("Timeout updated %d %d", timer, timeout);*/ + t_timeout = timeout; +} + +int myEventRemoveTimeoutFunc(int timer) +{ + DEBUG("Timeout removed %d", timer); + t_active = 0; + return 0; +} + +/* main test functions */ + +void usage(const char *pname) +{ + printf("%s uri\n", pname); +} + +int main(int argc, char **argv) +{ + int run=1; + int sts; + + if(argc > 1 && STREQ(argv[1],"--help")) { + usage(argv[0]); + return -1; + } + virEventRegisterImpl( myEventAddHandleFunc, + myEventUpdateHandleFunc, + myEventRemoveHandleFunc, + myEventAddTimeoutFunc, + myEventUpdateTimeoutFunc, + myEventRemoveTimeoutFunc); + + virConnectPtr dconn = NULL; + dconn = virConnectOpen (argv[1] ? argv[1] : "qemu:///system"); + if (!dconn) { + printf("error opening\n"); + return -1; + } + + DEBUG0("Registering domain event cbs"); + + /* Add 2 callbacks to prove this works with more than just one */ + virConnectDomainEventRegister(dconn, myDomainEventCallback1, NULL); + virConnectDomainEventRegister(dconn, myDomainEventCallback2, NULL); + + while(run) { + struct pollfd pfd = { .fd = h_fd, + .events = h_event, + .revents = 0}; + + sts = poll(&pfd, 1, TIMEOUT_MS); + + /* We are assuming timeout of 0 here - so execute every time */ + if(t_cb && t_active) + t_cb(t_timeout,t_opaque); + + if (sts == 0) { + /* DEBUG0("Poll timeout"); */ + continue; + } + if (sts < 0 ) { + DEBUG0("Poll failed"); + continue; + } + if ( pfd.revents & POLLHUP ) { + DEBUG0("Reset by peer"); + return -1; + } + + if(h_cb) { + h_cb(h_fd, + myPollEventToEventHandleType(pfd.revents & h_event), + h_opaque); + } + + } + + if( dconn && virConnectClose(dconn)<0 ) { + printf("error closing\n"); + } + printf("done\n"); + return 0; +} + diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h index 35b80d033c..806bd6327d 100644 --- a/include/libvirt/libvirt.h +++ b/include/libvirt/libvirt.h @@ -993,6 +993,159 @@ char * virStorageVolGetPath (virStorageVolPtr vol); virDomainPtr virDomainCreateLinux (virConnectPtr conn, const char *xmlDesc, unsigned int flags); + +/* + * Domain Event Notification + */ + +/** + * virDomainEventType: + * + * a virDomainEventType is emitted during domain lifecycle events + */ +typedef enum { + VIR_DOMAIN_EVENT_ADDED, + VIR_DOMAIN_EVENT_REMOVED, + VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_RESUMED, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_SAVED, + VIR_DOMAIN_EVENT_RESTORED, +} virDomainEventType; + +/** + * virConnectDomainEventCallback: + * @conn: virConnect connection + * @dom: The domain on which the event occured + * @event: The specfic virDomainEventType which occured + * @opaque: opaque user data + * + * A callback function to be registered, and called when a domain event occurs + */ +typedef int (*virConnectDomainEventCallback)(virConnectPtr conn, + virDomainPtr dom, + int event, + void *opaque); + +int virConnectDomainEventRegister(virConnectPtr conn, + virConnectDomainEventCallback cb, + void *opaque); + +int virConnectDomainEventDeregister(virConnectPtr conn, + virConnectDomainEventCallback cb); + +/* + * Events Implementation + */ + +/** + * virEventHandleType: + * + * a virEventHandleType is used similar to POLLxxx FD events, but is specific + * to libvirt. A client app must translate to, and from POLL events when using + * this construct. + */ +typedef enum { + VIR_EVENT_HANDLE_READABLE = (1 << 0), + VIR_EVENT_HANDLE_WRITABLE = (1 << 1), + VIR_EVENT_HANDLE_ERROR = (1 << 2), + VIR_EVENT_HANDLE_HANGUP = (1 << 3), +} virEventHandleType; + +/** + * virEventHandleCallback: + * + * @fd: file handle on which the event occurred + * @events: bitset of events from virEventHandleType constants + * @opaque: user data registered with handle + * + * callback for receiving file handle events + */ +typedef void (*virEventHandleCallback)(int fd, int events, void *opaque); + +/** + * virEventAddHandleFunc: + * @fd: file descriptor to listen on + * @event: bitset of events on which to fire the callback + * @cb: the callback to be called + * @opaque: user data to pass to the callback + * + * Part of the EventImpl, this callback Adds a file handle callback to + * listen for specific events + */ +typedef int (*virEventAddHandleFunc)(int fd, int event, + virEventHandleCallback cb, void *opaque); + +/** + * virEventUpdateHandleFunc: + * @fd: file descriptor to modify + * @event: new events to listen on + * + * Part of the EventImpl, this user-provided callback is notified when + * events to listen on change + */ +typedef void (*virEventUpdateHandleFunc)(int fd, int event); + +/** + * virEventRemoveHandleFunc: + * @fd: file descriptor to stop listening on + * + * Part of the EventImpl, this user-provided callback is notified when + * an fd is no longer being listened on + */ +typedef int (*virEventRemoveHandleFunc)(int fd); + +/** + * virEventTimeoutCallback: + * + * @timer: timer id emitting the event + * @opaque: user data registered with handle + * + * callback for receiving timer events + */ +typedef void (*virEventTimeoutCallback)(int timer, void *opaque); + +/** + * virEventAddTimeoutFunc: + * @timeout: The timeout to monitor + * @cb: the callback to call when timeout has expired + * @opaque: user data to pass to the callback + * + * Part of the EventImpl, this user-defined callback handles adding an + * event timeout. + * + * Returns a timer value + */ +typedef int (*virEventAddTimeoutFunc)(int timeout, virEventTimeoutCallback cb, + void *opaque); + +/** + * virEventUpdateTimeoutFunc: + * @timer: the timer to modify + * @timeout: the new timeout value + * + * Part of the EventImpl, this user-defined callback updates an + * event timeout. + */ +typedef void (*virEventUpdateTimeoutFunc)(int timer, int timeout); + +/** + * virEventRemoveTimeoutFunc: + * @timer: the timer to remove + * + * Part of the EventImpl, this user-defined callback removes a timer + * + * Returns 0 on success, -1 on failure + */ +typedef int (*virEventRemoveTimeoutFunc)(int timer); + +void virEventRegisterImpl(virEventAddHandleFunc addHandle, + virEventUpdateHandleFunc updateHandle, + virEventRemoveHandleFunc removeHandle, + virEventAddTimeoutFunc addTimeout, + virEventUpdateTimeoutFunc updateTimeout, + virEventRemoveTimeoutFunc removeTimeout); #ifdef __cplusplus } #endif diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 3624367480..97aea7dfbf 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -993,6 +993,159 @@ char * virStorageVolGetPath (virStorageVolPtr vol); virDomainPtr virDomainCreateLinux (virConnectPtr conn, const char *xmlDesc, unsigned int flags); + +/* + * Domain Event Notification + */ + +/** + * virDomainEventType: + * + * a virDomainEventType is emitted during domain lifecycle events + */ +typedef enum { + VIR_DOMAIN_EVENT_ADDED, + VIR_DOMAIN_EVENT_REMOVED, + VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_RESUMED, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_SAVED, + VIR_DOMAIN_EVENT_RESTORED, +} virDomainEventType; + +/** + * virConnectDomainEventCallback: + * @conn: virConnect connection + * @dom: The domain on which the event occured + * @event: The specfic virDomainEventType which occured + * @opaque: opaque user data + * + * A callback function to be registered, and called when a domain event occurs + */ +typedef int (*virConnectDomainEventCallback)(virConnectPtr conn, + virDomainPtr dom, + int event, + void *opaque); + +int virConnectDomainEventRegister(virConnectPtr conn, + virConnectDomainEventCallback cb, + void *opaque); + +int virConnectDomainEventDeregister(virConnectPtr conn, + virConnectDomainEventCallback cb); + +/* + * Events Implementation + */ + +/** + * virEventHandleType: + * + * a virEventHandleType is used similar to POLLxxx FD events, but is specific + * to libvirt. A client app must translate to, and from POLL events when using + * this construct. + */ +typedef enum { + VIR_EVENT_HANDLE_READABLE = (1 << 0), + VIR_EVENT_HANDLE_WRITABLE = (1 << 1), + VIR_EVENT_HANDLE_ERROR = (1 << 2), + VIR_EVENT_HANDLE_HANGUP = (1 << 3), +} virEventHandleType; + +/** + * virEventHandleCallback: + * + * @fd: file handle on which the event occurred + * @events: bitset of events from virEventHandleType constants + * @opaque: user data registered with handle + * + * callback for receiving file handle events + */ +typedef void (*virEventHandleCallback)(int fd, int events, void *opaque); + +/** + * virEventAddHandleFunc: + * @fd: file descriptor to listen on + * @event: bitset of events on which to fire the callback + * @cb: the callback to be called + * @opaque: user data to pass to the callback + * + * Part of the EventImpl, this callback Adds a file handle callback to + * listen for specific events + */ +typedef int (*virEventAddHandleFunc)(int fd, int event, + virEventHandleCallback cb, void *opaque); + +/** + * virEventUpdateHandleFunc: + * @fd: file descriptor to modify + * @event: new events to listen on + * + * Part of the EventImpl, this user-provided callback is notified when + * events to listen on change + */ +typedef void (*virEventUpdateHandleFunc)(int fd, int event); + +/** + * virEventRemoveHandleFunc: + * @fd: file descriptor to stop listening on + * + * Part of the EventImpl, this user-provided callback is notified when + * an fd is no longer being listened on + */ +typedef int (*virEventRemoveHandleFunc)(int fd); + +/** + * virEventTimeoutCallback: + * + * @timer: timer id emitting the event + * @opaque: user data registered with handle + * + * callback for receiving timer events + */ +typedef void (*virEventTimeoutCallback)(int timer, void *opaque); + +/** + * virEventAddTimeoutFunc: + * @timeout: The timeout to monitor + * @cb: the callback to call when timeout has expired + * @opaque: user data to pass to the callback + * + * Part of the EventImpl, this user-defined callback handles adding an + * event timeout. + * + * Returns a timer value + */ +typedef int (*virEventAddTimeoutFunc)(int timeout, virEventTimeoutCallback cb, + void *opaque); + +/** + * virEventUpdateTimeoutFunc: + * @timer: the timer to modify + * @timeout: the new timeout value + * + * Part of the EventImpl, this user-defined callback updates an + * event timeout. + */ +typedef void (*virEventUpdateTimeoutFunc)(int timer, int timeout); + +/** + * virEventRemoveTimeoutFunc: + * @timer: the timer to remove + * + * Part of the EventImpl, this user-defined callback removes a timer + * + * Returns 0 on success, -1 on failure + */ +typedef int (*virEventRemoveTimeoutFunc)(int timer); + +void virEventRegisterImpl(virEventAddHandleFunc addHandle, + virEventUpdateHandleFunc updateHandle, + virEventRemoveHandleFunc removeHandle, + virEventAddTimeoutFunc addTimeout, + virEventUpdateTimeoutFunc updateTimeout, + virEventRemoveTimeoutFunc removeTimeout); #ifdef __cplusplus } #endif diff --git a/proxy/Makefile.am b/proxy/Makefile.am index 5902cab876..75ba6b4705 100644 --- a/proxy/Makefile.am +++ b/proxy/Makefile.am @@ -17,6 +17,7 @@ libvirt_proxy_SOURCES = libvirt_proxy.c @top_srcdir@/src/xend_internal.c \ @top_srcdir@/src/memory.c \ @top_srcdir@/src/domain_conf.c \ @top_srcdir@/src/util.c \ + @top_srcdir@/src/event.c \ @top_srcdir@/src/uuid.c libvirt_proxy_LDFLAGS = $(WARN_CFLAGS) libvirt_proxy_DEPENDENCIES = diff --git a/python/generator.py b/python/generator.py index c706b19ff2..ca83eafe2b 100755 --- a/python/generator.py +++ b/python/generator.py @@ -332,6 +332,9 @@ skip_function = ( 'virCopyLastError', # Python API is called virGetLastError instead 'virConnectOpenAuth', # Python C code is manually written 'virDefaultErrorFunc', # Python virErrorFuncHandler impl calls this from C + 'virConnectDomainEventRegister', # TODO: generate python bindings for these below XXX + 'virConnectDomainEventDeregister', + 'virEventRegisterImpl', ) diff --git a/qemud/event.c b/qemud/event.c index bb1f381d1f..1e2a5f584f 100644 --- a/qemud/event.c +++ b/qemud/event.c @@ -74,13 +74,13 @@ static struct virEventLoop eventLoop; /* Unique ID for the next timer to be registered */ static int nextTimer = 0; - /* * Register a callback for monitoring file handle events. * NB, it *must* be safe to call this from within a callback * For this reason we only ever append to existing list. */ -int virEventAddHandleImpl(int fd, int events, virEventHandleCallback cb, void *opaque) { +int virEventAddHandleImpl(int fd, int events, virEventHandleCallback cb, + void *opaque) { EVENT_DEBUG("Add handle %d %d %p %p", fd, events, cb, opaque); if (eventLoop.handlesCount == eventLoop.handlesAlloc) { EVENT_DEBUG("Used %d handle slots, adding %d more", @@ -92,7 +92,8 @@ int virEventAddHandleImpl(int fd, int events, virEventHandleCallback cb, void *o } eventLoop.handles[eventLoop.handlesCount].fd = fd; - eventLoop.handles[eventLoop.handlesCount].events = events; + eventLoop.handles[eventLoop.handlesCount].events = + virEventHandleTypeToPollEvent(events); eventLoop.handles[eventLoop.handlesCount].cb = cb; eventLoop.handles[eventLoop.handlesCount].opaque = opaque; eventLoop.handles[eventLoop.handlesCount].deleted = 0; @@ -106,7 +107,8 @@ void virEventUpdateHandleImpl(int fd, int events) { int i; for (i = 0 ; i < eventLoop.handlesCount ; i++) { if (eventLoop.handles[i].fd == fd) { - eventLoop.handles[i].events = events; + eventLoop.handles[i].events = + virEventHandleTypeToPollEvent(events); break; } } @@ -342,6 +344,7 @@ static int virEventDispatchTimeouts(void) { */ static int virEventDispatchHandles(struct pollfd *fds) { int i; + virEventHandleType hEvents; /* Save this now - it may be changed during dispatch */ int nhandles = eventLoop.handlesCount; @@ -352,8 +355,10 @@ static int virEventDispatchHandles(struct pollfd *fds) { } if (fds[i].revents) { - EVENT_DEBUG("Dispatch %d %d %p", fds[i].fd, fds[i].revents, eventLoop.handles[i].opaque); - (eventLoop.handles[i].cb)(fds[i].fd, fds[i].revents, + hEvents = virPollEventToEventHandleType(fds[i].revents); + EVENT_DEBUG("Dispatch %d %d %p", fds[i].fd, fds[i].revents, + eventLoop.handles[i].opaque); + (eventLoop.handles[i].cb)(fds[i].fd, hEvents, eventLoop.handles[i].opaque); } } @@ -482,3 +487,33 @@ int virEventRunOnce(void) { return 0; } + +int +__virEventHandleTypeToPollEvent(virEventHandleType events) +{ + int ret = 0; + if(events & VIR_EVENT_HANDLE_READABLE) + ret |= POLLIN; + if(events & VIR_EVENT_HANDLE_WRITABLE) + ret |= POLLOUT; + if(events & VIR_EVENT_HANDLE_ERROR) + ret |= POLLERR; + if(events & VIR_EVENT_HANDLE_HANGUP) + ret |= POLLHUP; + return ret; +} + +virEventHandleType +__virPollEventToEventHandleType(int events) +{ + virEventHandleType ret = 0; + if(events & POLLIN) + ret |= VIR_EVENT_HANDLE_READABLE; + if(events & POLLOUT) + ret |= VIR_EVENT_HANDLE_WRITABLE; + if(events & POLLERR) + ret |= VIR_EVENT_HANDLE_ERROR; + if(events & POLLHUP) + ret |= VIR_EVENT_HANDLE_HANGUP; + return ret; +} diff --git a/qemud/event.h b/qemud/event.h index adf7b6d04c..1729c33924 100644 --- a/qemud/event.h +++ b/qemud/event.h @@ -36,7 +36,8 @@ * * returns -1 if the file handle cannot be registered, 0 upon success */ -int virEventAddHandleImpl(int fd, int events, virEventHandleCallback cb, void *opaque); +int virEventAddHandleImpl(int fd, int events, virEventHandleCallback cb, + void *opaque); /** * virEventUpdateHandleImpl: change event set for a monitored file handle diff --git a/qemud/mdns.c b/qemud/mdns.c index 914794608e..06eb9f0d24 100644 --- a/qemud/mdns.c +++ b/qemud/mdns.c @@ -231,14 +231,16 @@ static void libvirtd_mdns_client_callback(AvahiClient *c, AvahiClientState state static void libvirtd_mdns_watch_dispatch(int fd, int events, void *opaque) { AvahiWatch *w = (AvahiWatch*)opaque; - AVAHI_DEBUG("Dispatch watch FD %d Event %d", fd, events); - w->revents = events; - w->callback(w, fd, events, w->userdata); + int fd_events = virEventHandleTypeToPollEvent(events); + AVAHI_DEBUG("Dispatch watch FD %d Event %d", fd, fd_events); + w->revents = fd_events; + w->callback(w, fd, fd_events, w->userdata); } static AvahiWatch *libvirtd_mdns_watch_new(const AvahiPoll *api ATTRIBUTE_UNUSED, int fd, AvahiWatchEvent event, AvahiWatchCallback cb, void *userdata) { AvahiWatch *w; + virEventHandleType hEvents; if (VIR_ALLOC(w) < 0) return NULL; @@ -248,7 +250,9 @@ static AvahiWatch *libvirtd_mdns_watch_new(const AvahiPoll *api ATTRIBUTE_UNUSED w->userdata = userdata; AVAHI_DEBUG("New handle %p FD %d Event %d", w, w->fd, event); - if (virEventAddHandleImpl(fd, event, libvirtd_mdns_watch_dispatch, w) < 0) { + hEvents = virPollEventToEventHandleType(event); + if (virEventAddHandleImpl(fd, hEvents, + libvirtd_mdns_watch_dispatch, w) < 0) { VIR_FREE(w); return NULL; } diff --git a/qemud/qemud.c b/qemud/qemud.c index 9da27d215a..b98e55ae5f 100644 --- a/qemud/qemud.c +++ b/qemud/qemud.c @@ -230,9 +230,10 @@ remoteInitializeGnuTLS (void) return 0; } -static void qemudDispatchSignalEvent(int fd ATTRIBUTE_UNUSED, - int events ATTRIBUTE_UNUSED, - void *opaque) { +static void +qemudDispatchSignalEvent(int fd ATTRIBUTE_UNUSED, + int events ATTRIBUTE_UNUSED, + void *opaque) { struct qemud_server *server = (struct qemud_server *)opaque; siginfo_t siginfo; int ret; @@ -521,10 +522,13 @@ static int qemudListenUnix(struct qemud_server *server, } if (virEventAddHandleImpl(sock->fd, - POLLIN| POLLERR | POLLHUP, + VIR_EVENT_HANDLE_READABLE | + VIR_EVENT_HANDLE_ERROR | + VIR_EVENT_HANDLE_HANGUP, qemudDispatchServerEvent, server) < 0) { - qemudLog(QEMUD_ERR, "%s", _("Failed to add server event callback")); + qemudLog(QEMUD_ERR, "%s", + _("Failed to add server event callback")); goto cleanup; } @@ -650,7 +654,9 @@ remoteListenTCP (struct qemud_server *server, } if (virEventAddHandleImpl(sock->fd, - POLLIN| POLLERR | POLLHUP, + VIR_EVENT_HANDLE_READABLE | + VIR_EVENT_HANDLE_ERROR | + VIR_EVENT_HANDLE_HANGUP, qemudDispatchServerEvent, server) < 0) { qemudLog(QEMUD_ERR, "%s", _("Failed to add server event callback")); @@ -723,12 +729,12 @@ static struct qemud_server *qemudInitialize(int sigread) { server->sigread = sigread; - __virEventRegisterImpl(virEventAddHandleImpl, - virEventUpdateHandleImpl, - virEventRemoveHandleImpl, - virEventAddTimeoutImpl, - virEventUpdateTimeoutImpl, - virEventRemoveTimeoutImpl); + virEventRegisterImpl(virEventAddHandleImpl, + virEventUpdateHandleImpl, + virEventRemoveHandleImpl, + virEventAddTimeoutImpl, + virEventUpdateTimeoutImpl, + virEventRemoveTimeoutImpl); virStateInitialize(); @@ -1105,6 +1111,7 @@ static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket client->auth = sock->auth; memcpy (&client->addr, &addr, sizeof addr); client->addrlen = addrlen; + client->server = server; #if HAVE_POLKIT /* Only do policy checks for non-root - allow root user @@ -1199,6 +1206,12 @@ static void qemudDispatchClientFailure(struct qemud_server *server, struct qemud virEventRemoveHandleImpl(client->fd); + /* Deregister event delivery callback */ + if(client->conn) { + qemudDebug("Deregistering to relay remote events"); + virConnectDomainEventDeregister(client->conn, remoteRelayDomainEvent); + } + if (client->conn) virConnectClose(client->conn); @@ -1503,7 +1516,9 @@ static int qemudClientWrite(struct qemud_server *server, } -static void qemudDispatchClientWrite(struct qemud_server *server, struct qemud_client *client) { +void +qemudDispatchClientWrite(struct qemud_server *server, + struct qemud_client *client) { switch (client->mode) { case QEMUD_MODE_TX_PACKET: { if (qemudClientWrite(server, client) < 0) @@ -1552,7 +1567,8 @@ static void qemudDispatchClientWrite(struct qemud_server *server, struct qemud_c } -static void qemudDispatchClientEvent(int fd, int events, void *opaque) { +static void +qemudDispatchClientEvent(int fd, int events, void *opaque) { struct qemud_server *server = (struct qemud_server *)opaque; struct qemud_client *client = server->clients; @@ -1566,9 +1582,9 @@ static void qemudDispatchClientEvent(int fd, int events, void *opaque) { if (!client) return; - if (events == POLLOUT) + if (events == VIR_EVENT_HANDLE_WRITABLE) qemudDispatchClientWrite(server, client); - else if (events == POLLIN) + else if (events == VIR_EVENT_HANDLE_READABLE) qemudDispatchClientRead(server, client); else qemudDispatchClientFailure(server, client); @@ -1581,18 +1597,18 @@ static int qemudRegisterClientEvent(struct qemud_server *server, switch (client->mode) { case QEMUD_MODE_TLS_HANDSHAKE: if (gnutls_record_get_direction (client->tlssession) == 0) - mode = POLLIN; + mode = VIR_EVENT_HANDLE_READABLE; else - mode = POLLOUT; + mode = VIR_EVENT_HANDLE_WRITABLE; break; case QEMUD_MODE_RX_HEADER: case QEMUD_MODE_RX_PAYLOAD: - mode = POLLIN; + mode = VIR_EVENT_HANDLE_READABLE; break; case QEMUD_MODE_TX_PACKET: - mode = POLLOUT; + mode = VIR_EVENT_HANDLE_WRITABLE; break; default: @@ -1604,7 +1620,8 @@ static int qemudRegisterClientEvent(struct qemud_server *server, return -1; if (virEventAddHandleImpl(client->fd, - mode | POLLERR | POLLHUP, + mode | VIR_EVENT_HANDLE_ERROR | + VIR_EVENT_HANDLE_HANGUP, qemudDispatchClientEvent, server) < 0) return -1; @@ -1612,7 +1629,8 @@ static int qemudRegisterClientEvent(struct qemud_server *server, return 0; } -static void qemudDispatchServerEvent(int fd, int events, void *opaque) { +static void +qemudDispatchServerEvent(int fd, int events, void *opaque) { struct qemud_server *server = (struct qemud_server *)opaque; struct qemud_socket *sock = server->sockets; @@ -2215,7 +2233,7 @@ int main(int argc, char **argv) { } if (virEventAddHandleImpl(sigpipe[0], - POLLIN, + VIR_EVENT_HANDLE_READABLE, qemudDispatchSignalEvent, server) < 0) { qemudLog(QEMUD_ERR, diff --git a/qemud/qemud.h b/qemud/qemud.h index 91cb939aa8..83d65b6ee5 100644 --- a/qemud/qemud.h +++ b/qemud/qemud.h @@ -132,6 +132,9 @@ struct qemud_client { */ virConnectPtr conn; + /* back-pointer to our server */ + struct qemud_server *server; + struct qemud_client *next; }; @@ -179,8 +182,16 @@ void qemudLog(int priority, const char *fmt, ...) void remoteDispatchClientRequest (struct qemud_server *server, struct qemud_client *client); +void qemudDispatchClientWrite(struct qemud_server *server, + struct qemud_client *client); + #if HAVE_POLKIT int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid); #endif +int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + int event, + void *opaque); + #endif diff --git a/qemud/remote.c b/qemud/remote.c index 72e064efbb..a623494fcd 100644 --- a/qemud/remote.c +++ b/qemud/remote.c @@ -75,6 +75,12 @@ typedef int (*dispatch_fn) (struct qemud_server *server, char *args, char *ret); +/* Prototypes */ +static void +remoteDispatchDomainEventSend (struct qemud_client *client, + virDomainPtr dom, + virDomainEventType event); + /* This function gets called from qemud when it detects an incoming * remote protocol message. At this point, client->buffer contains * the full call message (including length word which we skip). @@ -405,6 +411,20 @@ remoteDispatchError (struct qemud_client *client, remoteDispatchSendError (client, req, VIR_ERR_RPC, msg); } +int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + int event, + void *opaque) +{ + struct qemud_client *client = opaque; + REMOTE_DEBUG("Relaying domain event %d", event); + + if(client) { + remoteDispatchDomainEventSend (client, dom, event); + qemudDispatchClientWrite(client->server,client); + } + return 0; +} /*----- Functions. -----*/ @@ -3620,6 +3640,129 @@ remoteDispatchStorageVolLookupByPath (struct qemud_server *server ATTRIBUTE_UNUS } +/************************** + * Async Events + **************************/ +static int +remoteDispatchDomainEvent (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + remote_message_header *req ATTRIBUTE_UNUSED, + void *args ATTRIBUTE_UNUSED, + remote_domain_event_ret *ret ATTRIBUTE_UNUSED) +{ + /* This call gets dispatched from a client call. + * This does not make sense, as this should not be intiated + * from the client side in generated code. + */ + return -1; +} + +/*************************** + * Register / deregister events + ***************************/ +static int +remoteDispatchDomainEventsRegister (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req ATTRIBUTE_UNUSED, + void *args ATTRIBUTE_UNUSED, + remote_domain_events_register_ret *ret ATTRIBUTE_UNUSED) +{ + CHECK_CONN(client); + + /* Register event delivery callback */ + REMOTE_DEBUG("%s","Registering to relay remote events"); + virConnectDomainEventRegister(client->conn, remoteRelayDomainEvent, client); + + if(ret) + ret->cb_registered = 1; + return 0; +} + +static int +remoteDispatchDomainEventsDeregister (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req ATTRIBUTE_UNUSED, + void *args ATTRIBUTE_UNUSED, + remote_domain_events_deregister_ret *ret ATTRIBUTE_UNUSED) +{ + CHECK_CONN(client); + + /* Deregister event delivery callback */ + REMOTE_DEBUG("%s","Deregistering to relay remote events"); + virConnectDomainEventDeregister(client->conn, remoteRelayDomainEvent); + + if(ret) + ret->cb_registered = 0; + return 0; +} + +static void +remoteDispatchDomainEventSend (struct qemud_client *client, + virDomainPtr dom, + virDomainEventType event) +{ + remote_message_header rep; + XDR xdr; + int len; + remote_domain_event_ret data; + + if(!client) { + remoteDispatchError (client, NULL, "%s", _("Invalid Client")); + return; + } + + rep.prog = REMOTE_PROGRAM; + rep.vers = REMOTE_PROTOCOL_VERSION; + rep.proc = REMOTE_PROC_DOMAIN_EVENT; + rep.direction = REMOTE_MESSAGE; + rep.serial = 1; + rep.status = REMOTE_OK; + + /* Serialise the return header and event. */ + xdrmem_create (&xdr, client->buffer, sizeof client->buffer, XDR_ENCODE); + + len = 0; /* We'll come back and write this later. */ + if (!xdr_int (&xdr, &len)) { + remoteDispatchError (client, NULL, "%s", _("xdr_int failed (1)")); + xdr_destroy (&xdr); + return; + } + + if (!xdr_remote_message_header (&xdr, &rep)) { + xdr_destroy (&xdr); + return; + } + + /* build return data */ + make_nonnull_domain (&data.dom, dom); + data.event = (int) event; + + if (!xdr_remote_domain_event_ret(&xdr, &data)) { + remoteDispatchError (client, NULL, "%s", _("serialise return struct")); + xdr_destroy (&xdr); + return; + } + + len = xdr_getpos (&xdr); + if (xdr_setpos (&xdr, 0) == 0) { + remoteDispatchError (client, NULL, "%s", _("xdr_setpos failed")); + xdr_destroy (&xdr); + return; + } + + if (!xdr_int (&xdr, &len)) { + remoteDispatchError (client, NULL, "%s", _("xdr_int failed (2)")); + xdr_destroy (&xdr); + return; + } + + xdr_destroy (&xdr); + + /* Send it. */ + client->mode = QEMUD_MODE_TX_PACKET; + client->bufferLength = len; + client->bufferOffset = 0; +} /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/qemud/remote_dispatch_localvars.h b/qemud/remote_dispatch_localvars.h index f46b493779..505fb30cab 100644 --- a/qemud/remote_dispatch_localvars.h +++ b/qemud/remote_dispatch_localvars.h @@ -6,6 +6,7 @@ remote_domain_lookup_by_uuid_args lv_remote_domain_lookup_by_uuid_args; remote_domain_lookup_by_uuid_ret lv_remote_domain_lookup_by_uuid_ret; remote_storage_pool_list_volumes_args lv_remote_storage_pool_list_volumes_args; remote_storage_pool_list_volumes_ret lv_remote_storage_pool_list_volumes_ret; +remote_domain_events_deregister_ret lv_remote_domain_events_deregister_ret; remote_domain_shutdown_args lv_remote_domain_shutdown_args; remote_list_defined_domains_args lv_remote_list_defined_domains_args; remote_list_defined_domains_ret lv_remote_list_defined_domains_ret; @@ -20,6 +21,7 @@ remote_domain_get_autostart_args lv_remote_domain_get_autostart_args; remote_domain_get_autostart_ret lv_remote_domain_get_autostart_ret; remote_domain_set_vcpus_args lv_remote_domain_set_vcpus_args; remote_get_hostname_ret lv_remote_get_hostname_ret; +remote_domain_events_register_ret lv_remote_domain_events_register_ret; remote_network_undefine_args lv_remote_network_undefine_args; remote_domain_create_args lv_remote_domain_create_args; remote_network_destroy_args lv_remote_network_destroy_args; @@ -121,6 +123,7 @@ remote_num_of_defined_storage_pools_ret lv_remote_num_of_defined_storage_pools_r remote_domain_core_dump_args lv_remote_domain_core_dump_args; remote_list_defined_storage_pools_args lv_remote_list_defined_storage_pools_args; remote_list_defined_storage_pools_ret lv_remote_list_defined_storage_pools_ret; +remote_domain_event_ret lv_remote_domain_event_ret; remote_domain_get_max_memory_args lv_remote_domain_get_max_memory_args; remote_domain_get_max_memory_ret lv_remote_domain_get_max_memory_ret; remote_num_of_domains_ret lv_remote_num_of_domains_ret; diff --git a/qemud/remote_dispatch_proc_switch.h b/qemud/remote_dispatch_proc_switch.h index 89296d7004..3cd5d786db 100644 --- a/qemud/remote_dispatch_proc_switch.h +++ b/qemud/remote_dispatch_proc_switch.h @@ -116,6 +116,24 @@ case REMOTE_PROC_DOMAIN_DUMP_XML: ret = (char *) &lv_remote_domain_dump_xml_ret; memset (&lv_remote_domain_dump_xml_ret, 0, sizeof lv_remote_domain_dump_xml_ret); break; +case REMOTE_PROC_DOMAIN_EVENT: + fn = (dispatch_fn) remoteDispatchDomainEvent; + ret_filter = (xdrproc_t) xdr_remote_domain_event_ret; + ret = (char *) &lv_remote_domain_event_ret; + memset (&lv_remote_domain_event_ret, 0, sizeof lv_remote_domain_event_ret); + break; +case REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER: + fn = (dispatch_fn) remoteDispatchDomainEventsDeregister; + ret_filter = (xdrproc_t) xdr_remote_domain_events_deregister_ret; + ret = (char *) &lv_remote_domain_events_deregister_ret; + memset (&lv_remote_domain_events_deregister_ret, 0, sizeof lv_remote_domain_events_deregister_ret); + break; +case REMOTE_PROC_DOMAIN_EVENTS_REGISTER: + fn = (dispatch_fn) remoteDispatchDomainEventsRegister; + ret_filter = (xdrproc_t) xdr_remote_domain_events_register_ret; + ret = (char *) &lv_remote_domain_events_register_ret; + memset (&lv_remote_domain_events_register_ret, 0, sizeof lv_remote_domain_events_register_ret); + break; case REMOTE_PROC_DOMAIN_GET_AUTOSTART: fn = (dispatch_fn) remoteDispatchDomainGetAutostart; args_filter = (xdrproc_t) xdr_remote_domain_get_autostart_args; diff --git a/qemud/remote_dispatch_prototypes.h b/qemud/remote_dispatch_prototypes.h index 3f4eb9fd12..4b27a9f312 100644 --- a/qemud/remote_dispatch_prototypes.h +++ b/qemud/remote_dispatch_prototypes.h @@ -18,6 +18,9 @@ static int remoteDispatchDomainDefineXml (struct qemud_server *server, struct qe static int remoteDispatchDomainDestroy (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_destroy_args *args, void *ret); static int remoteDispatchDomainDetachDevice (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_detach_device_args *args, void *ret); static int remoteDispatchDomainDumpXml (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_dump_xml_args *args, remote_domain_dump_xml_ret *ret); +static int remoteDispatchDomainEvent (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_domain_event_ret *ret); +static int remoteDispatchDomainEventsDeregister (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_domain_events_deregister_ret *ret); +static int remoteDispatchDomainEventsRegister (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_domain_events_register_ret *ret); static int remoteDispatchDomainGetAutostart (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_autostart_args *args, remote_domain_get_autostart_ret *ret); static int remoteDispatchDomainGetInfo (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_info_args *args, remote_domain_get_info_ret *ret); static int remoteDispatchDomainGetMaxMemory (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_max_memory_args *args, remote_domain_get_max_memory_ret *ret); diff --git a/qemud/remote_protocol.c b/qemud/remote_protocol.c index 33a25e103f..5ef80e546a 100644 --- a/qemud/remote_protocol.c +++ b/qemud/remote_protocol.c @@ -1942,6 +1942,35 @@ xdr_remote_storage_vol_get_path_ret (XDR *xdrs, remote_storage_vol_get_path_ret return TRUE; } +bool_t +xdr_remote_domain_events_register_ret (XDR *xdrs, remote_domain_events_register_ret *objp) +{ + + if (!xdr_int (xdrs, &objp->cb_registered)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_domain_events_deregister_ret (XDR *xdrs, remote_domain_events_deregister_ret *objp) +{ + + if (!xdr_int (xdrs, &objp->cb_registered)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_domain_event_ret (XDR *xdrs, remote_domain_event_ret *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + if (!xdr_int (xdrs, &objp->event)) + return FALSE; + return TRUE; +} + bool_t xdr_remote_procedure (XDR *xdrs, remote_procedure *objp) { diff --git a/qemud/remote_protocol.h b/qemud/remote_protocol.h index 0bf8b79da4..e43514d28e 100644 --- a/qemud/remote_protocol.h +++ b/qemud/remote_protocol.h @@ -1081,6 +1081,22 @@ struct remote_storage_vol_get_path_ret { remote_nonnull_string name; }; typedef struct remote_storage_vol_get_path_ret remote_storage_vol_get_path_ret; + +struct remote_domain_events_register_ret { + int cb_registered; +}; +typedef struct remote_domain_events_register_ret remote_domain_events_register_ret; + +struct remote_domain_events_deregister_ret { + int cb_registered; +}; +typedef struct remote_domain_events_deregister_ret remote_domain_events_deregister_ret; + +struct remote_domain_event_ret { + remote_nonnull_domain dom; + int event; +}; +typedef struct remote_domain_event_ret remote_domain_event_ret; #define REMOTE_PROGRAM 0x20008086 #define REMOTE_PROTOCOL_VERSION 1 @@ -1189,6 +1205,9 @@ enum remote_procedure { REMOTE_PROC_NODE_GET_FREE_MEMORY = 102, REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103, REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104, + REMOTE_PROC_DOMAIN_EVENTS_REGISTER = 105, + REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER = 106, + REMOTE_PROC_DOMAIN_EVENT = 107, }; typedef enum remote_procedure remote_procedure; @@ -1394,6 +1413,9 @@ extern bool_t xdr_remote_storage_vol_get_info_args (XDR *, remote_storage_vol_g extern bool_t xdr_remote_storage_vol_get_info_ret (XDR *, remote_storage_vol_get_info_ret*); extern bool_t xdr_remote_storage_vol_get_path_args (XDR *, remote_storage_vol_get_path_args*); extern bool_t xdr_remote_storage_vol_get_path_ret (XDR *, remote_storage_vol_get_path_ret*); +extern bool_t xdr_remote_domain_events_register_ret (XDR *, remote_domain_events_register_ret*); +extern bool_t xdr_remote_domain_events_deregister_ret (XDR *, remote_domain_events_deregister_ret*); +extern bool_t xdr_remote_domain_event_ret (XDR *, remote_domain_event_ret*); extern bool_t xdr_remote_procedure (XDR *, remote_procedure*); extern bool_t xdr_remote_message_direction (XDR *, remote_message_direction*); extern bool_t xdr_remote_message_status (XDR *, remote_message_status*); @@ -1575,6 +1597,9 @@ extern bool_t xdr_remote_storage_vol_get_info_args (); extern bool_t xdr_remote_storage_vol_get_info_ret (); extern bool_t xdr_remote_storage_vol_get_path_args (); extern bool_t xdr_remote_storage_vol_get_path_ret (); +extern bool_t xdr_remote_domain_events_register_ret (); +extern bool_t xdr_remote_domain_events_deregister_ret (); +extern bool_t xdr_remote_domain_event_ret (); extern bool_t xdr_remote_procedure (); extern bool_t xdr_remote_message_direction (); extern bool_t xdr_remote_message_status (); diff --git a/qemud/remote_protocol.x b/qemud/remote_protocol.x index f1bd9ff549..b7e41aadee 100644 --- a/qemud/remote_protocol.x +++ b/qemud/remote_protocol.x @@ -965,6 +965,25 @@ struct remote_storage_vol_get_path_ret { remote_nonnull_string name; }; +/** + * Events Register/Deregister: + * It would seem rpcgen does not like both args, and ret + * to be null. It will not generate the prototype otherwise. + * Pass back a redundant boolean to force prototype generation. + */ +struct remote_domain_events_register_ret { + int cb_registered; +}; + +struct remote_domain_events_deregister_ret { + int cb_registered; +}; + +struct remote_domain_event_ret { + remote_nonnull_domain dom; + int event; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -1086,7 +1105,11 @@ enum remote_procedure { REMOTE_PROC_NODE_GET_FREE_MEMORY = 102, REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103, - REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104 + REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104, + + REMOTE_PROC_DOMAIN_EVENTS_REGISTER = 105, + REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER = 106, + REMOTE_PROC_DOMAIN_EVENT = 107 }; /* Custom RPC structure. */ diff --git a/src/driver.h b/src/driver.h index 0540f80b9e..d1b541f9f4 100644 --- a/src/driver.h +++ b/src/driver.h @@ -280,6 +280,17 @@ typedef unsigned long long (*virDrvNodeGetFreeMemory) (virConnectPtr conn); +typedef int + (*virDrvDomainEventRegister) + (virConnectPtr conn, + void *callback, + void *opaque); + +typedef int + (*virDrvDomainEventDeregister) + (virConnectPtr conn, + void *callback); + /** * _virDriver: * @@ -352,6 +363,8 @@ struct _virDriver { virDrvDomainMemoryPeek domainMemoryPeek; virDrvNodeGetCellsFreeMemory nodeGetCellsFreeMemory; virDrvNodeGetFreeMemory getFreeMemory; + virDrvDomainEventRegister domainEventRegister; + virDrvDomainEventDeregister domainEventDeregister; }; typedef int diff --git a/src/event.c b/src/event.c index 49a9e61da5..ac6f886264 100644 --- a/src/event.c +++ b/src/event.c @@ -34,7 +34,8 @@ static virEventAddTimeoutFunc addTimeoutImpl = NULL; static virEventUpdateTimeoutFunc updateTimeoutImpl = NULL; static virEventRemoveTimeoutFunc removeTimeoutImpl = NULL; -int virEventAddHandle(int fd, int events, virEventHandleCallback cb, void *opaque) { +int virEventAddHandle(int fd, int events, virEventHandleCallback cb, + void *opaque) { if (!addHandleImpl) return -1; @@ -70,12 +71,22 @@ int virEventRemoveTimeout(int timer) { return removeTimeoutImpl(timer); } -void __virEventRegisterImpl(virEventAddHandleFunc addHandle, - virEventUpdateHandleFunc updateHandle, - virEventRemoveHandleFunc removeHandle, - virEventAddTimeoutFunc addTimeout, - virEventUpdateTimeoutFunc updateTimeout, - virEventRemoveTimeoutFunc removeTimeout) { +/** + * virEventRegisterImpl: + * Register an EventImpl + * @addHandle: the callback to add fd handles + * @updateHandle: the callback to update fd handles + * @removeHandle: the callback to remove fd handles + * @addTimeout: the callback to add a timeout + * @updateTimeout: the callback to update a timeout + * @removeTimeout: the callback to remove a timeout + */ +void virEventRegisterImpl(virEventAddHandleFunc addHandle, + virEventUpdateHandleFunc updateHandle, + virEventRemoveHandleFunc removeHandle, + virEventAddTimeoutFunc addTimeout, + virEventUpdateTimeoutFunc updateTimeout, + virEventRemoveTimeoutFunc removeTimeout) { addHandleImpl = addHandle; updateHandleImpl = updateHandle; removeHandleImpl = removeHandle; diff --git a/src/event.h b/src/event.h index 758573c145..f540384259 100644 --- a/src/event.h +++ b/src/event.h @@ -23,34 +23,25 @@ #ifndef __VIR_EVENT_H__ #define __VIR_EVENT_H__ - - -/** - * virEventHandleCallback: callback for receiving file handle events - * - * @fd: file handle on which the event occurred - * @events: bitset of events from POLLnnn constants - * @opaque: user data registered with handle - */ -typedef void (*virEventHandleCallback)(int fd, int events, void *opaque); - +#include "internal.h" /** * virEventAddHandle: register a callback for monitoring file handle events * * @fd: file handle to monitor for events - * @events: bitset of events to watch from POLLnnn constants + * @events: bitset of events to watch from virEventHandleType constants * @cb: callback to invoke when an event occurs * @opaque: user data to pass to callback * * returns -1 if the file handle cannot be registered, 0 upon success */ -int virEventAddHandle(int fd, int events, virEventHandleCallback cb, void *opaque); +int virEventAddHandle(int fd, int events, virEventHandleCallback cb, + void *opaque); /** * virEventUpdateHandle: change event set for a monitored file handle * * @fd: file handle to monitor for events - * @events: bitset of events to watch from POLLnnn constants + * @events: bitset of events to watch from virEventHandleType constants * * Will not fail if fd exists */ @@ -65,14 +56,6 @@ void virEventUpdateHandle(int fd, int events); */ int virEventRemoveHandle(int fd); -/** - * virEventTimeoutCallback: callback for receiving timer events - * - * @timer: timer id emitting the event - * @opaque: user data registered with handle - */ -typedef void (*virEventTimeoutCallback)(int timer, void *opaque); - /** * virEventAddTimeout: register a callback for a timer event * @@ -110,21 +93,4 @@ void virEventUpdateTimeout(int timer, int frequency); */ int virEventRemoveTimeout(int timer); -typedef int (*virEventAddHandleFunc)(int, int, virEventHandleCallback, void *); -typedef void (*virEventUpdateHandleFunc)(int, int); -typedef int (*virEventRemoveHandleFunc)(int); - -typedef int (*virEventAddTimeoutFunc)(int, virEventTimeoutCallback, void *); -typedef void (*virEventUpdateTimeoutFunc)(int, int); -typedef int (*virEventRemoveTimeoutFunc)(int); - -void __virEventRegisterImpl(virEventAddHandleFunc addHandle, - virEventUpdateHandleFunc updateHandle, - virEventRemoveHandleFunc removeHandle, - virEventAddTimeoutFunc addTimeout, - virEventUpdateTimeoutFunc updateTimeout, - virEventRemoveTimeoutFunc removeTimeout); - -#define virEventRegisterImpl(ah,rh,at,rt) __virEventRegisterImpl(ah,rh,at,rt) - #endif /* __VIR_EVENT_H__ */ diff --git a/src/internal.h b/src/internal.h index 2ae764d8f8..7ea15860ba 100644 --- a/src/internal.h +++ b/src/internal.h @@ -379,8 +379,80 @@ struct _virStringList { struct _virStringList *next; }; -char *virStringListJoin(const virStringList *list, const char *pre, +char *__virStringListJoin(const virStringList *list, const char *pre, const char *post, const char *sep); -void virStringListFree(virStringList *list); +void __virStringListFree(virStringList *list); + +/** + * Domain Event Notification + */ + +struct _virDomainEventCallback { + virConnectPtr conn; + virConnectDomainEventCallback cb; + void *opaque; +}; +typedef struct _virDomainEventCallback virDomainEventCallback; +typedef virDomainEventCallback *virDomainEventCallbackPtr; + +struct _virDomainEventCallbackList { + unsigned int count; + virDomainEventCallbackPtr *callbacks; +}; +typedef struct _virDomainEventCallbackList virDomainEventCallbackList; +typedef virDomainEventCallbackList *virDomainEventCallbackListPtr; + +void __virDomainEventCallbackListFree(virDomainEventCallbackListPtr list); +#define virDomainEventCallbackListFree(x) __virDomainEventCallbackListFree(x) + +int __virDomainEventCallbackListAdd(virConnectPtr conn, + virDomainEventCallbackListPtr cbList, + virConnectDomainEventCallback callback, + void *opaque); +#define virDomainEventCallbackListAdd(a,b,c,d) \ + __virDomainEventCallbackListAdd((a),(b),(c),(d)) + +int __virDomainEventCallbackListRemove(virConnectPtr conn, + virDomainEventCallbackListPtr cbList, + virConnectDomainEventCallback callback); +#define virDomainEventCallbackListRemove(a,b,c) \ + __virDomainEventCallbackListRemove((a),(b),(c)) + +int __virEventHandleTypeToPollEvent(virEventHandleType events); +#define virEventHandleTypeToPollEvent(x) __virEventHandleTypeToPollEvent(x) + +virEventHandleType __virPollEventToEventHandleType(int events); +#define virPollEventToEventHandleType(x) __virPollEventToEventHandleType(x) + +/** + * Dispatching domain events that come in while + * in a call / response rpc + */ +struct _virDomainEvent { + virDomainPtr dom; + virDomainEventType event; +}; +typedef struct _virDomainEvent virDomainEvent; +typedef virDomainEvent *virDomainEventPtr; + +struct _virDomainEventQueue { + unsigned int count; + virDomainEventPtr *events; +}; +typedef struct _virDomainEventQueue virDomainEventQueue; +typedef virDomainEventQueue *virDomainEventQueuePtr; + +int __virDomainEventCallbackQueuePush(virDomainEventQueuePtr evtQueue, + virDomainPtr dom, + virDomainEventType event); +#define virDomainEventCallbackQueuePush(a,b,c) \ + __virDomainEventCallbackQueuePush((a),(b),(c)) + +virDomainEventPtr +__virDomainEventCallbackQueuePop(virDomainEventQueuePtr evtQueue); +#define virDomainEventCallbackQueuePop(x) __virDomainEventCallbackQueuePop(x) + +void __virDomainEventQueueFree(virDomainEventQueuePtr queue); +#define virDomainEventQueueFree(x) __virDomainEventQueueFree(x) #endif /* __VIR_INTERNAL_H__ */ diff --git a/src/libvirt.c b/src/libvirt.c index ca2675a1df..8fd594b0f7 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #ifdef HAVE_SYS_WAIT_H @@ -5310,7 +5311,7 @@ virStorageVolGetPath(virStorageVolPtr vol) /* Not for public use. Combines the elements of a virStringList * into a single string. */ -char *virStringListJoin(const virStringList *list, const char *pre, +char *__virStringListJoin(const virStringList *list, const char *pre, const char *post, const char *sep) { size_t pre_len = strlen(pre); @@ -5337,7 +5338,7 @@ char *virStringListJoin(const virStringList *list, const char *pre, } -void virStringListFree(virStringList *list) +void __virStringListFree(virStringList *list) { while (list) { virStringList *p = list->next; @@ -5345,3 +5346,269 @@ void virStringListFree(virStringList *list) list = p; } } + +/* + * Domain Event Notification + */ + +/** + * virConnectDomainEventRegister: + * @conn: pointer to the connection + * @cb: callback to the function handling domain events + * @opaque: opaque data to pass on to the callback + * + * Adds a Domain Event Callback. + * Registering for a domain callback will enable delivery of the events + * + * Returns 0 on success, -1 on failure + */ +int +virConnectDomainEventRegister(virConnectPtr conn, + virConnectDomainEventCallback cb, + void *opaque) +{ + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + if (cb == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if ((conn->driver) && (conn->driver->domainEventRegister)) + return conn->driver->domainEventRegister (conn, cb, opaque); + return -1; +} + +/** + * virConnectDomainEventDeregister: + * @conn: pointer to the connection + * @cb: callback to the function handling domain events + * + * Removes a Domain Event Callback. + * De-registering for a domain callback will disable + * delivery of this event type + * + * Returns 0 on success, -1 on failure + */ +int +virConnectDomainEventDeregister(virConnectPtr conn, + virConnectDomainEventCallback cb) +{ + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + if (cb == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + if ((conn->driver) && (conn->driver->domainEventDeregister)) + return conn->driver->domainEventDeregister (conn, cb); + + return -1; +} + +/** + * __virDomainEventCallbackListFree: + * @list: event callback list head + * + * Free the memory in the domain event callback list + */ +void +__virDomainEventCallbackListFree(virDomainEventCallbackListPtr list) +{ + int i; + for (i=0; icount; i++) { + VIR_FREE(list->callbacks[i]); + } + VIR_FREE(list); +} +/** + * __virDomainEventCallbackListRemove: + * @conn: pointer to the connection + * @cbList: the list + * @callback: the callback to remove + * + * Internal function to remove a callback from a virDomainEventCallbackListPtr + */ +int +__virDomainEventCallbackListRemove(virConnectPtr conn, + virDomainEventCallbackListPtr cbList, + virConnectDomainEventCallback callback) +{ + int i; + for (i = 0 ; i < cbList->count ; i++) { + if(cbList->callbacks[i]->cb == callback && + cbList->callbacks[i]->conn == conn) { + virUnrefConnect(cbList->callbacks[i]->conn); + VIR_FREE(cbList->callbacks[i]); + + if (i < (cbList->count - 1)) + memmove(cbList->callbacks + i, + cbList->callbacks + i + 1, + sizeof(*(cbList->callbacks)) * + (cbList->count - (i + 1))); + + if (VIR_REALLOC_N(cbList->callbacks, + cbList->count - 1) < 0) { + ; /* Failure to reduce memory allocation isn't fatal */ + } + cbList->count--; + + return 0; + } + } + return -1; +} + +/** + * __virDomainEventCallbackListAdd: + * @conn: pointer to the connection + * @cbList: the list + * @callback: the callback to add + * @opaque: opaque data tio pass to callback + * + * Internal function to add a callback from a virDomainEventCallbackListPtr + */ +int +__virDomainEventCallbackListAdd(virConnectPtr conn, + virDomainEventCallbackListPtr cbList, + virConnectDomainEventCallback callback, + void *opaque) +{ + virDomainEventCallbackPtr event; + int n; + + /* Check incoming */ + if ( !cbList ) { + return -1; + } + + /* check if we already have this callback on our list */ + for (n=0; n < cbList->count; n++) { + if(cbList->callbacks[n]->cb == callback && + conn == cbList->callbacks[n]->conn) { + DEBUG0("WARNING: Callback already tracked"); + return -1; + } + } + /* Allocate new event */ + if (VIR_ALLOC(event) < 0) { + DEBUG0("Error allocating event"); + return -1; + } + event->conn = conn; + event->cb = callback; + event->opaque = opaque; + + /* Make space on list */ + n = cbList->count; + if (VIR_REALLOC_N(cbList->callbacks, n + 1) < 0) { + DEBUG0("Error reallocating list"); + VIR_FREE(event); + return -1; + } + + event->conn->refs++; + + cbList->callbacks[n] = event; + cbList->count++; + return 0; +} + +/** + * __virDomainEventQueueFree: + * @queue: pointer to the queue + * + * Free the memory in the queue. We process this like a list here + */ +void +__virDomainEventQueueFree(virDomainEventQueuePtr queue) +{ + int i; + for ( i=0 ; icount ; i++ ) { + VIR_FREE(queue->events[i]); + } + VIR_FREE(queue); +} + +/** + * __virDomainEventCallbackQueuePop: + * @evtQueue: the queue of events + * + * Internal function to pop off, and return the front of the queue + * NOTE: The caller is responsible for freeing the returned object + * + * Returns: virDomainEventPtr on success NULL on failure. + */ +virDomainEventPtr +__virDomainEventCallbackQueuePop(virDomainEventQueuePtr evtQueue) +{ + virDomainEventPtr ret; + + if(!evtQueue || evtQueue->count == 0 ) + return NULL; + + ret = evtQueue->events[0]; + + memmove(evtQueue->events, + evtQueue->events + 1, + sizeof(*(evtQueue->events)) * + (evtQueue->count - 1)); + + if (VIR_REALLOC_N(evtQueue->events, + evtQueue->count - 1) < 0) { + ; /* Failure to reduce memory allocation isn't fatal */ + } + evtQueue->count--; + + return ret; +} + +/** + * __virDomainEventCallbackQueuePush: + * @evtQueue: the dom event queue + * @dom: the domain to add + * @event: the event to add + * + * Internal function to push onto the back of an virDomainEventQueue + * + * Returns: 0 on success, -1 on failure + */ +int +__virDomainEventCallbackQueuePush(virDomainEventQueuePtr evtQueue, + virDomainPtr dom, + virDomainEventType event) +{ + virDomainEventPtr domEvent; + + /* Check incoming */ + if ( !evtQueue ) { + return -1; + } + + /* Allocate new event */ + if (VIR_ALLOC(domEvent) < 0) { + DEBUG0("Error allocating event"); + return -1; + } + domEvent->dom = dom; + domEvent->event = event; + + /* Make space on queue */ + if (VIR_REALLOC_N(evtQueue->events, + evtQueue->count + 1) < 0) { + DEBUG0("Error reallocating queue"); + VIR_FREE(domEvent); + return -1; + } + + evtQueue->events[evtQueue->count] = domEvent; + evtQueue->count++; + return 0; +} + diff --git a/src/libvirt_sym.version b/src/libvirt_sym.version index 3cc4505bd3..78358372ba 100644 --- a/src/libvirt_sym.version +++ b/src/libvirt_sym.version @@ -147,6 +147,10 @@ virStorageVolGetXMLDesc; virStorageVolGetPath; + virEventRegisterImpl; + virConnectDomainEventRegister; + virConnectDomainEventDeregister; + /* Symbols with __ are private only for use by the libvirtd daemon. They are not part of stable ABI @@ -167,8 +171,6 @@ __virGetStoragePool; __virGetStorageVol; - __virEventRegisterImpl; - __virStateInitialize; __virStateCleanup; __virStateReload; @@ -197,6 +199,5 @@ __virAllocN; __virReallocN; __virFree; - local: *; }; diff --git a/src/lxc_driver.c b/src/lxc_driver.c index c598d1d11c..6b34620d02 100644 --- a/src/lxc_driver.c +++ b/src/lxc_driver.c @@ -811,7 +811,7 @@ static int lxcVmStart(virConnectPtr conn, vm->state = VIR_DOMAIN_RUNNING; if (virEventAddHandle(vm->monitor, - POLLERR | POLLHUP, + VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, lxcMonitorEvent, driver) < 0) { lxcVmTerminate(conn, driver, vm, 0); @@ -1278,6 +1278,8 @@ static virDriver lxcDriver = { NULL, /* domainMemoryPeek */ NULL, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ + NULL, /* domainEventRegister */ + NULL, /* domainEventDeregister */ }; static virStateDriver lxcStateDriver = { diff --git a/src/openvz_driver.c b/src/openvz_driver.c index b82d0df1b2..2d0ddaa2b0 100644 --- a/src/openvz_driver.c +++ b/src/openvz_driver.c @@ -1012,6 +1012,8 @@ static virDriver openvzDriver = { NULL, /* domainMemoryPeek */ NULL, /* nodeGetCellsFreeMemory */ NULL, /* nodeGetFreeMemory */ + NULL, /* domainEventRegister */ + NULL, /* domainEventDeregister */ }; int openvzRegister(void) { diff --git a/src/qemu_conf.h b/src/qemu_conf.h index cfd7d35609..d06c4d7691 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -63,6 +63,9 @@ struct qemud_driver { char *vncListen; virCapsPtr caps; + + /* An array of callbacks */ + virDomainEventCallbackListPtr domainEventCallbacks; }; diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 34f743b684..e2b34e35b3 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -106,7 +106,14 @@ static int qemudSetNonBlock(int fd) { } -static void qemudDispatchVMEvent(int fd, int events, void *opaque); +static void qemudDomainEventDispatch (struct qemud_driver *driver, + virDomainObjPtr vm, + virDomainEventType evt); + +static void qemudDispatchVMEvent(int fd, + int events, + void *opaque); + static int qemudStartVMDaemon(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm, @@ -116,8 +123,8 @@ static void qemudShutdownVMDaemon(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm); - static int qemudDomainGetMaxVcpus(virDomainPtr dom); + static int qemudMonitorCommand (const struct qemud_driver *driver, const virDomainObjPtr vm, const char *cmd, @@ -160,6 +167,10 @@ qemudStartup(void) { /* Don't have a dom0 so start from 1 */ qemu_driver->nextvmid = 1; + /* Init callback list */ + if(VIR_ALLOC(qemu_driver->domainEventCallbacks) < 0) + return -1; + if (!uid) { if (asprintf(&qemu_driver->logDir, "%s/log/libvirt/qemu", LOCAL_STATE_DIR) == -1) @@ -302,6 +313,9 @@ qemudShutdown(void) { VIR_FREE(qemu_driver->autostartDir); VIR_FREE(qemu_driver->vncTLSx509certdir); + /* Free domain callback list */ + virDomainEventCallbackListFree(qemu_driver->domainEventCallbacks); + if (qemu_driver->brctl) brShutdown(qemu_driver->brctl); @@ -743,6 +757,9 @@ static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) { return -1; } +static virDomainPtr qemudDomainLookupByName(virConnectPtr conn, + const char *name); + static int qemudStartVMDaemon(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm, @@ -906,11 +923,15 @@ static int qemudStartVMDaemon(virConnectPtr conn, if (ret == 0) { if ((virEventAddHandle(vm->stdout_fd, - POLLIN | POLLERR | POLLHUP, + VIR_EVENT_HANDLE_READABLE | + VIR_EVENT_HANDLE_ERROR | + VIR_EVENT_HANDLE_HANGUP, qemudDispatchVMEvent, driver) < 0) || (virEventAddHandle(vm->stderr_fd, - POLLIN | POLLERR | POLLHUP, + VIR_EVENT_HANDLE_READABLE | + VIR_EVENT_HANDLE_ERROR | + VIR_EVENT_HANDLE_HANGUP, qemudDispatchVMEvent, driver) < 0) || (qemudWaitForMonitor(conn, driver, vm) < 0) || @@ -919,6 +940,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, qemudShutdownVMDaemon(conn, driver, vm); return -1; } + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STARTED); } return ret; @@ -1013,6 +1035,7 @@ static int qemudDispatchVMLog(struct qemud_driver *driver, virDomainObjPtr vm, i static int qemudDispatchVMFailure(struct qemud_driver *driver, virDomainObjPtr vm, int fd ATTRIBUTE_UNUSED) { qemudShutdownVMDaemon(NULL, driver, vm); + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STOPPED); if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); @@ -1020,7 +1043,8 @@ static int qemudDispatchVMFailure(struct qemud_driver *driver, virDomainObjPtr v } -static void qemudDispatchVMEvent(int fd, int events, void *opaque) { +static void +qemudDispatchVMEvent(int fd, int events, void *opaque) { struct qemud_driver *driver = (struct qemud_driver *)opaque; virDomainObjPtr vm = NULL; unsigned int i; @@ -1037,7 +1061,7 @@ static void qemudDispatchVMEvent(int fd, int events, void *opaque) { if (!vm) return; - if (events == POLLIN) + if (events == VIR_EVENT_HANDLE_READABLE) qemudDispatchVMLog(driver, vm, fd); else qemudDispatchVMFailure(driver, vm, fd); @@ -1504,6 +1528,7 @@ static int qemudDomainSuspend(virDomainPtr dom) { } vm->state = VIR_DOMAIN_PAUSED; qemudDebug("Reply %s", info); + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_SUSPENDED); VIR_FREE(info); return 0; } @@ -1532,6 +1557,7 @@ static int qemudDomainResume(virDomainPtr dom) { } vm->state = VIR_DOMAIN_RUNNING; qemudDebug("Reply %s", info); + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_RESUMED); VIR_FREE(info); return 0; } @@ -1570,10 +1596,10 @@ static int qemudDomainDestroy(virDomainPtr dom) { } qemudShutdownVMDaemon(dom->conn, driver, vm); + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STOPPED); if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); - return 0; } @@ -1904,7 +1930,7 @@ static int qemudDomainSave(virDomainPtr dom, if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); - + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_SAVED); return 0; } @@ -2211,6 +2237,7 @@ static int qemudDomainRestore(virConnectPtr conn, vm->state = VIR_DOMAIN_RUNNING; } + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_RESTORED); return 0; } @@ -3149,6 +3176,56 @@ done: } +static int +qemudDomainEventRegister (virConnectPtr conn, + void *callback, + void *opaque) +{ + struct qemud_driver *driver = (struct qemud_driver *)conn->privateData; + + return virDomainEventCallbackListAdd(conn, driver->domainEventCallbacks, + callback, opaque); +} + +static int +qemudDomainEventDeregister (virConnectPtr conn, + void *callback) +{ + struct qemud_driver *driver = (struct qemud_driver *)conn->privateData; + + return virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks, + callback); +} + +static void qemudDomainEventDispatch (struct qemud_driver *driver, + virDomainObjPtr vm, + virDomainEventType evt) +{ + int i; + virDomainEventCallbackListPtr cbList; + + cbList = driver->domainEventCallbacks; + + for(i=0 ; i < cbList->count ; i++) { + if(cbList->callbacks[i] && cbList->callbacks[i]->cb) { + virConnectPtr conn = cbList->callbacks[i]->conn; + virDomainPtr dom = virGetDomain(conn, vm->def->name, + vm->def->uuid); + if (dom) { + dom->id = virDomainIsActive(vm) ? vm->def->id : -1; + DEBUG("Dispatching callback %p %p event %d", + cbList->callbacks[i], + cbList->callbacks[i]->cb, evt); + cbList->callbacks[i]->cb(cbList->callbacks[i]->conn, + dom, evt, + cbList->callbacks[i]->opaque); + virDomainFree(dom); + } + } + } + +} + static virDriver qemuDriver = { VIR_DRV_QEMU, "QEMU", @@ -3219,6 +3296,8 @@ static virDriver qemuDriver = { NULL, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ #endif + qemudDomainEventRegister, /* domainEventRegister */ + qemudDomainEventDeregister, /* domainEventDeregister */ }; diff --git a/src/remote_internal.c b/src/remote_internal.c index 35b7b4b523..a182de3a75 100644 --- a/src/remote_internal.c +++ b/src/remote_internal.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #ifdef HAVE_SYS_WAIT_H @@ -73,6 +74,7 @@ #include "remote_protocol.h" #include "memory.h" #include "util.h" +#include "event.h" /* Per-connection private data. */ #define MAGIC 999 /* private_data->magic if OK */ @@ -97,6 +99,13 @@ struct private_data { unsigned int saslDecodedLength; unsigned int saslDecodedOffset; #endif + /* The list of domain event callbacks */ + virDomainEventCallbackListPtr callbackList; + /* The queue of domain events generated + during a call / response rpc */ + virDomainEventQueuePtr domainEvents; + /* Timer for flushing domainEvents queue */ + int eventFlushTimer; }; #define GET_PRIVATE(conn,retcode) \ @@ -156,7 +165,10 @@ static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr do static void make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr net_src); static void make_nonnull_storage_pool (remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr vol_src); static void make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src); - +void remoteDomainEventFired(int fd, int event, void *data); +static void remoteDomainProcessEvent(virConnectPtr conn, XDR *xdr); +static void remoteDomainQueueEvent(virConnectPtr conn, XDR *xdr); +void remoteDomainEventQueueFlush(int timer, void *opaque); /*----------------------------------------------------------------------*/ /* Helper functions for remoteOpen. */ @@ -680,6 +692,36 @@ doRemoteOpen (virConnectPtr conn, (xdrproc_t) xdr_void, (char *) NULL) == -1) goto failed; + if(VIR_ALLOC(priv->callbackList)<0) { + error(conn, VIR_ERR_INVALID_ARG, _("Error allocating callbacks list")); + goto failed; + } + + if(VIR_ALLOC(priv->domainEvents)<0) { + error(conn, VIR_ERR_INVALID_ARG, _("Error allocating domainEvents")); + goto failed; + } + + DEBUG0("Adding Handler for remote events"); + /* Set up a callback to listen on the socket data */ + if (virEventAddHandle(priv->sock, + VIR_EVENT_HANDLE_READABLE | + VIR_EVENT_HANDLE_ERROR | + VIR_EVENT_HANDLE_HANGUP, + remoteDomainEventFired, + conn) < 0) { + DEBUG0("virEventAddHandle failed: No addHandleImpl defined." + " continuing without events."); + } else { + + DEBUG0("Adding Timeout for remote event queue flushing"); + if ( (priv->eventFlushTimer = virEventAddTimeout(-1, + remoteDomainEventQueueFlush, + conn)) < 0) { + DEBUG0("virEventAddTimeout failed: No addTimeoutImpl defined. " + "continuing without events."); + } + } /* Successful. */ retcode = VIR_DRV_OPEN_SUCCESS; @@ -1101,6 +1143,11 @@ doRemoteClose (virConnectPtr conn, struct private_data *priv) (xdrproc_t) xdr_void, (char *) NULL) == -1) return -1; + /* Remove handle for remote events */ + virEventRemoveHandle(priv->sock); + /* Remove timout */ + virEventRemoveTimeout(priv->eventFlushTimer); + /* Close socket. */ if (priv->uses_tls && priv->session) { gnutls_bye (priv->session, GNUTLS_SHUT_RDWR); @@ -1132,6 +1179,12 @@ doRemoteClose (virConnectPtr conn, struct private_data *priv) /* Free private data. */ priv->magic = DEAD; + /* Free callback list */ + virDomainEventCallbackListFree(priv->callbackList); + + /* Free queued events */ + virDomainEventQueueFree(priv->domainEvents); + return 0; } @@ -4288,6 +4341,52 @@ remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open, return 0; } #endif /* HAVE_POLKIT */ +/*----------------------------------------------------------------------*/ + +static int remoteDomainEventRegister (virConnectPtr conn, + void *callback ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + struct private_data *priv = conn->privateData; + + if (virDomainEventCallbackListAdd(conn, priv->callbackList, + callback, opaque) < 0) { + error (conn, VIR_ERR_RPC, _("adding cb to list")); + return -1; + } + + if ( priv->callbackList->count == 1 ) { + /* Tell the server when we are the first callback deregistering */ + if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_EVENTS_REGISTER, + (xdrproc_t) xdr_void, (char *) NULL, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + return -1; + } + + return 0; +} + +static int remoteDomainEventDeregister (virConnectPtr conn, + void *callback ATTRIBUTE_UNUSED) +{ + struct private_data *priv = conn->privateData; + + if (virDomainEventCallbackListRemove(conn, priv->callbackList, + callback) < 0) { + error (conn, VIR_ERR_RPC, _("removing cb fron list")); + return -1; + } + + if ( priv->callbackList->count == 0 ) { + /* Tell the server when we are the last callback deregistering */ + if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER, + (xdrproc_t) xdr_void, (char *) NULL, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + return -1; + } + + return 0; +} /*----------------------------------------------------------------------*/ @@ -4367,6 +4466,7 @@ call (virConnectPtr conn, struct private_data *priv, really_write (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer, len-4) == -1) return -1; +retry_read: /* Read and deserialise length word. */ if (really_read (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer2, sizeof buffer2) == -1) return -1; @@ -4418,10 +4518,20 @@ call (virConnectPtr conn, struct private_data *priv, return -1; } - /* If we extend the server to actually send asynchronous messages, then - * we'll need to change this so that it can recognise an asynch - * message being received at this point. - */ + if (hdr.proc == REMOTE_PROC_DOMAIN_EVENT && + hdr.direction == REMOTE_MESSAGE) { + /* An async message has come in while we were waiting for the + * response. Process it to pull it off the wire, and try again + */ + DEBUG0("Encountered an event while waiting for a response"); + + remoteDomainQueueEvent(conn, &xdr); + virEventUpdateTimeout(priv->eventFlushTimer, 0); + + DEBUG0("Retrying read"); + xdr_destroy (&xdr); + goto retry_read; + } if (hdr.proc != proc_nr) { __virRaiseError (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE, @@ -4872,6 +4982,8 @@ static virDriver driver = { .domainMemoryPeek = remoteDomainMemoryPeek, .nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory, .getFreeMemory = remoteNodeGetFreeMemory, + .domainEventRegister = remoteDomainEventRegister, + .domainEventDeregister = remoteDomainEventDeregister, }; static virNetworkDriver network_driver = { @@ -4957,3 +5069,157 @@ remoteRegister (void) return 0; } + +/** + * remoteDomainReadEvent + * + * Read the event data off the wire + */ +static int +remoteDomainReadEvent(virConnectPtr conn, XDR *xdr, + virDomainPtr *dom, int *event) +{ + remote_domain_event_ret ret; + memset (&ret, 0, sizeof ret); + + /* unmarshall parameters, and process it*/ + if (! xdr_remote_domain_event_ret(xdr, &ret) ) { + error (conn, VIR_ERR_RPC, + _("remoteDomainProcessEvent: unmarshalling ret")); + return -1; + } + + *dom = get_nonnull_domain(conn,ret.dom); + *event = ret.event; + + return 0; +} + +static void +remoteDomainProcessEvent(virConnectPtr conn, XDR *xdr) +{ + virDomainPtr dom; + int event,i; + struct private_data *priv = conn->privateData; + + if(!remoteDomainReadEvent(conn, xdr, &dom, &event)) { + DEBUG0("Calling domain event callbacks (no queue)"); + for(i=0 ; i < priv->callbackList->count ; i++) { + if( priv->callbackList->callbacks[i] ) + priv->callbackList->callbacks[i]->cb(conn, dom, event, + priv->callbackList->callbacks[i]->opaque); + } + } +} + +static void +remoteDomainQueueEvent(virConnectPtr conn, XDR *xdr) +{ + virDomainPtr dom; + int event; + struct private_data *priv = conn->privateData; + + if(!remoteDomainReadEvent(conn, xdr, &dom, &event)) + { + if( virDomainEventCallbackQueuePush(priv->domainEvents, + dom, event) < 0 ) { + DEBUG("%s", "Error adding event to queue"); + } + } +} + +/** remoteDomainEventFired: + * + * The callback for monitoring the remote socket + * for event data + */ +void +remoteDomainEventFired(int fd ATTRIBUTE_UNUSED, + int event, + void *opaque) +{ + char buffer[REMOTE_MESSAGE_MAX]; + char buffer2[4]; + struct remote_message_header hdr; + XDR xdr; + int len; + + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + + DEBUG("%s : Event fired %d %X", __FUNCTION__, event, event); + + if (event & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) { + DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or " + "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__); + virEventRemoveHandle(fd); + return; + } + + /* Read and deserialise length word. */ + if (really_read (conn, priv, 0, buffer2, sizeof buffer2) == -1) + return; + + xdrmem_create (&xdr, buffer2, sizeof buffer2, XDR_DECODE); + if (!xdr_int (&xdr, &len)) { + error (conn, VIR_ERR_RPC, _("xdr_int (length word, reply)")); + return; + } + xdr_destroy (&xdr); + + /* Length includes length word - adjust to real length to read. */ + len -= 4; + + if (len < 0 || len > REMOTE_MESSAGE_MAX) { + error (conn, VIR_ERR_RPC, _("packet received from server too large")); + return; + } + + /* Read reply header and what follows (either a ret or an error). */ + if (really_read (conn, priv, 0, buffer, len) == -1) { + error (conn, VIR_ERR_RPC, _("error reading buffer from memory")); + return; + } + + /* Deserialise reply header. */ + xdrmem_create (&xdr, buffer, len, XDR_DECODE); + if (!xdr_remote_message_header (&xdr, &hdr)) { + error (conn, VIR_ERR_RPC, _("invalid header in event firing")); + return; + } + + if (hdr.proc == REMOTE_PROC_DOMAIN_EVENT && + hdr.direction == REMOTE_MESSAGE) { + DEBUG0("Encountered an async event"); + remoteDomainProcessEvent(conn, &xdr); + } else { + DEBUG0("invalid proc in event firing"); + error (conn, VIR_ERR_RPC, _("invalid proc in event firing")); + } +} + +void +remoteDomainEventQueueFlush(int timer ATTRIBUTE_UNUSED, void *opaque) +{ + int i; + virDomainEventPtr domEvent; + void *user_data = NULL; + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + + while( (domEvent = virDomainEventCallbackQueuePop(priv->domainEvents)) ) { + DEBUG(" Flushing %p", domEvent); + for (i=0 ; i < priv->callbackList->count ; i++) { + if( priv->callbackList->callbacks[i] ) { + user_data = priv->callbackList->callbacks[i]->opaque; + priv->callbackList->callbacks[i]->cb(domEvent->dom->conn, + domEvent->dom, + domEvent->event, + user_data); + } + } + VIR_FREE(domEvent); + } + + virEventUpdateTimeout(priv->eventFlushTimer, -1); +} diff --git a/src/storage_backend_fs.c b/src/storage_backend_fs.c index d261d71add..c3bda715fd 100644 --- a/src/storage_backend_fs.c +++ b/src/storage_backend_fs.c @@ -400,7 +400,8 @@ virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn, &state, &exitstatus) < 0) goto cleanup; - retval = virStringListJoin(state.list, SOURCES_START_TAG, SOURCES_END_TAG, "\n"); + retval = __virStringListJoin(state.list, SOURCES_START_TAG, + SOURCES_END_TAG, "\n"); if (retval == NULL) { virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("retval")); goto cleanup; @@ -410,7 +411,7 @@ virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn, xmlFreeDoc(doc); xmlXPathFreeContext(xpath_ctxt); VIR_FREE(state.host); - virStringListFree(state.list); + __virStringListFree(state.list); return retval; } diff --git a/src/test.c b/src/test.c index aab74e4ab9..34d35dbbaa 100644 --- a/src/test.c +++ b/src/test.c @@ -1552,6 +1552,8 @@ static virDriver testDriver = { NULL, /* domainMemoryPeek */ testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ + NULL, /* domainEventRegister */ + NULL, /* domainEventDeregister */ }; static virNetworkDriver testNetworkDriver = {