Re: [libvirt] Re: [PATCH 07/12] Domain Events - remote driver

2008-10-23 Thread Daniel P. Berrange
On Tue, Oct 21, 2008 at 03:16:20PM -0400, Ben Guthro wrote:
> [PATCH 07/12] Domain Events - remote driver
> Deliver local callbacks in response to remote events
> 
>  remote_internal.c |  276 
> +-
>  1 file changed, 271 insertions(+), 5 deletions(-)

ACK to this.


Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org   -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] Re: [PATCH 07/12] Domain Events - remote driver

2008-10-21 Thread Ben Guthro
[PATCH 07/12] Domain Events - remote driver
Deliver local callbacks in response to remote events

 remote_internal.c |  276 +-
 1 file changed, 271 insertions(+), 5 deletions(-)
diff --git a/src/remote_internal.c b/src/remote_internal.c
index 35b7b4b..8875674 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, virEventHandleType 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 

Re: [libvirt] Re: [PATCH 07/12] Domain Events - remote driver

2008-10-20 Thread Daniel P. Berrange
On Mon, Oct 20, 2008 at 11:43:24AM -0400, Ben Guthro wrote:
> OK - it looks like my EventImpl was passing along the wrong bits.
>
> I'll look into the "token" scheme suggested in an earlier email, and 
> get this ready for re-submission.
> 
> Would you prefer a new patch series, as before - or another patch that
> modifies the prior series?

Best to just re-post the whole series with changes incorporated, rather 
than trying to add more patches ontop of patches.

Regards,
Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org   -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] Re: [PATCH 07/12] Domain Events - remote driver

2008-10-20 Thread Ben Guthro
OK - it looks like my EventImpl was passing along the wrong bits.

I'll look into the "token" scheme suggested in an earlier email, and get this 
ready for re-submission.

Would you prefer a new patch series, as before - or another patch that modifies 
the prior series?




Daniel P. Berrange wrote on 10/20/2008 10:59 AM:
> On Mon, Oct 20, 2008 at 10:48:38AM -0400, Ben Guthro wrote:
>>> Just discovered one tiny problem here - need to check 'event' to see
>>> if the POLLHUP or POLLERR flags are set, and unregister the callback.
>>> Otherwise if you kill the server, the client will just spin on POLLHUP
>>> or ERR  forever. Something like this ought todo the trick
>>>
>>> if (event & (POLLERR | POLLHUP)) {
>>>  virEventRemoveHandle(fd);
>>>  return;
>>> }
>>>
>> I've been looking over the rest of your changes.
>> Generally, I agree all these suggestions are good ones...except for the code 
>> above
>>
>> With this code in, I run the following test
>> 1. start libvirtd
>> 2. begin to monitor events with event-test
>> 3. virsh create foo.xml
>>
>> At this point, the event-test app encounters a HUP, or ERR, and stops
>> monitoring for events - it will only ever get the "Started" event
> 
> That's a little odd - I'm not sure why 'event-test' would be getting
> a HUP/ERR when 'virsh' starts a domain.
> 
> 'event-test' should only get a HUP/ERR if it looses its socket connection
> to the libvirtd server. Once you've lost the connection like this, the 
> entire virConnectPtr is non-operative, and the client app needs to 
> create a new virConnectPtr to re-connect. So removing the FD from the
> event loop shouldn't result in us loosing any events - we're already
> doomed there.to 
> 
>> I handle this in the event-test poll loop via
>>
>> if ( pfd.revents & POLLHUP ) {
>> DEBUG0("Reset by peer");
>> return -1;
>> }
> 
> The integration into the event loop though is only something the app
> will have general control off - eg, in the example libvirt-glib code
> I posted its totally opaque to the app.
> 
>> Is it not a reasonable restriction to require the client app to handle a 
>> Hangup?
> 
> Once the socket is dead, all subsequent libvirt call made on that 
> virConnectPtr object will throw errors, which the app should see. 
> Though if they're only ever waiting for events, and not making any
> other calls, they'd not see it. Perhaps we could do with an explicit
> callback for connection disconnect.
> 
> 
> Daniel

--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] Re: [PATCH 07/12] Domain Events - remote driver

2008-10-20 Thread Daniel P. Berrange
On Mon, Oct 20, 2008 at 10:48:38AM -0400, Ben Guthro wrote:
> 
> > Just discovered one tiny problem here - need to check 'event' to see
> > if the POLLHUP or POLLERR flags are set, and unregister the callback.
> > Otherwise if you kill the server, the client will just spin on POLLHUP
> > or ERR  forever. Something like this ought todo the trick
> > 
> > if (event & (POLLERR | POLLHUP)) {
> >  virEventRemoveHandle(fd);
> >  return;
> > }
> > 
> 
> I've been looking over the rest of your changes.
> Generally, I agree all these suggestions are good ones...except for the code 
> above
> 
> With this code in, I run the following test
> 1. start libvirtd
> 2. begin to monitor events with event-test
> 3. virsh create foo.xml
> 
> At this point, the event-test app encounters a HUP, or ERR, and stops
> monitoring for events - it will only ever get the "Started" event

That's a little odd - I'm not sure why 'event-test' would be getting
a HUP/ERR when 'virsh' starts a domain.

'event-test' should only get a HUP/ERR if it looses its socket connection
to the libvirtd server. Once you've lost the connection like this, the 
entire virConnectPtr is non-operative, and the client app needs to 
create a new virConnectPtr to re-connect. So removing the FD from the
event loop shouldn't result in us loosing any events - we're already
doomed there.to 

> I handle this in the event-test poll loop via
> 
> if ( pfd.revents & POLLHUP ) {
> DEBUG0("Reset by peer");
> return -1;
> }

The integration into the event loop though is only something the app
will have general control off - eg, in the example libvirt-glib code
I posted its totally opaque to the app.

> Is it not a reasonable restriction to require the client app to handle a 
> Hangup?

Once the socket is dead, all subsequent libvirt call made on that 
virConnectPtr object will throw errors, which the app should see. 
Though if they're only ever waiting for events, and not making any
other calls, they'd not see it. Perhaps we could do with an explicit
callback for connection disconnect.


Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org   -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] Re: [PATCH 07/12] Domain Events - remote driver

2008-10-20 Thread Ben Guthro

> Just discovered one tiny problem here - need to check 'event' to see
> if the POLLHUP or POLLERR flags are set, and unregister the callback.
> Otherwise if you kill the server, the client will just spin on POLLHUP
> or ERR  forever. Something like this ought todo the trick
> 
> if (event & (POLLERR | POLLHUP)) {
>  virEventRemoveHandle(fd);
>  return;
> }
> 

I've been looking over the rest of your changes.
Generally, I agree all these suggestions are good ones...except for the code 
above

With this code in, I run the following test
1. start libvirtd
2. begin to monitor events with event-test
3. virsh create foo.xml

At this point, the event-test app encounters a HUP, or ERR, and stops 
monitoring for events - it will only ever get the "Started" event

I handle this in the event-test poll loop via

if ( pfd.revents & POLLHUP ) {
DEBUG0("Reset by peer");
return -1;
}


Is it not a reasonable restriction to require the client app to handle a Hangup?


--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] Re: [PATCH 07/12] Domain Events - remote driver

2008-10-20 Thread Daniel P. Berrange
On Fri, Oct 17, 2008 at 12:02:13PM -0400, Ben Guthro wrote:
> Deliver local callbacks in response to remote events
> 
>  remote_internal.c |  255 
> --
>  1 file changed, 248 insertions(+), 7 deletions(-)

> diff --git a/src/remote_internal.c b/src/remote_internal.c
> index 35b7b4b..13537f7 100644
> --- a/src/remote_internal.c
> +++ b/src/remote_internal.c
> @@ -34,6 +34,7 @@
> +/** remoteDomainEventFired:
> + *
> + * The callback for monitoring the remote socket
> + * for event data
> + */
> +void remoteDomainEventFired(int fd ATTRIBUTE_UNUSED,
> + int event ATTRIBUTE_UNUSED,
> + void *opaque)
> +{
> +char buffer[REMOTE_MESSAGE_MAX];
> +char buffer2[4];
> +struct remote_message_header hdr;
> +XDR xdr;
> +int len;
> +
> +virConnectPtrconn = opaque;
> +struct private_data *priv = conn->privateData;
> +
> +DEBUG("%s : Event fired", __FUNCTION__);
> +
> +/* Read and deserialise length word. */
> +if (really_read (conn, priv, 0, buffer2, sizeof buffer2) == -1)
> +return;


Just discovered one tiny problem here - need to check 'event' to see
if the POLLHUP or POLLERR flags are set, and unregister the callback.
Otherwise if you kill the server, the client will just spin on POLLHUP
or ERR  forever. Something like this ought todo the trick

if (event & (POLLERR | POLLHUP)) {
 virEventRemoveHandle(fd);
 return;
}

before we try to read any data.

Regards,
Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org   -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] Re: [PATCH 07/12] Domain Events - remote driver

2008-10-19 Thread Daniel P. Berrange
On Fri, Oct 17, 2008 at 12:02:13PM -0400, Ben Guthro wrote:
> Deliver local callbacks in response to remote events
> 
>  remote_internal.c |  255 
> --
>  1 file changed, 248 insertions(+), 7 deletions(-)

> @@ -680,6 +689,26 @@ doRemoteOpen (virConnectPtr conn,
>(xdrproc_t) xdr_void, (char *) NULL) == -1)
>  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,
> +  POLLIN | POLLERR | POLLHUP,
> +  remoteDomainEventFired,
> +  conn) < 0) {
> +DEBUG0("virEventAddHandle failed: No addHandleImpl defined. 
> continuing without events.");
> +}
> +
> +DEBUG0("Adding Timeout for remote event queue flushing");
> +if ( (priv->eventFlushTimer = virEventAddTimeout(0,
> + 
> remoteDomainEventQueueFlush,
> + conn)) < 0) {

Small bug here - this creates an active timer event, which will fire
immediately & forever. Simply change the '0' to a '-1' to register
a timeout that's initially disabled, and then use virEventUpdateTimeout
to toggle it on/off only when required.

> +
> +static int remoteDomainEventRegister (virConnectPtr conn,
> +   void *callback,
> +   void *opaque)
> +{
> +struct private_data *priv = conn->privateData;
> +
> +/* dispatch an rpc - so the server sde can track
> +   how many callbacks are regstered */
> +remote_domain_events_register_args args;
> +args.callback = (unsigned long)callback;
> +args.user_data = (unsigned long)opaque;

This relates back to my comment on the remote_protocl.x file - i feel
we should probably maintain a generic token, rather than pointing the
actual pointers over the wire as ints.

>  /*--*/
>  
> @@ -4367,6 +,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 +4496,19 @@ 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);

Need to call virEventUpdateTimeout() to enable the timer here.

> +/**
> + * remoteDomainReadEvent
> + *
> + * Read the event data off the wire
> + */
> +static int remoteDomainReadEvent(virConnectPtr conn, XDR *xdr,
> + virDomainPtr *dom, int *event,
> + virConnectDomainEventCallback *cb,
> + void **opaque)
> +{
> +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;
> +*cb = (virConnectDomainEventCallback)ret.callback;
> +*opaque = (void *)ret.user_data;
> +
> +return 0;
> +}
> +
> +static void remoteDomainProcessEvent(virConnectPtr conn, XDR *xdr)
> +{
> +virDomainPtr dom;
> +int event;
> +virConnectDomainEventCallback cb;
> +void *opaque;
> +if(!remoteDomainReadEvent(conn, xdr, &dom, &event, &cb, &opaque)) {
> +DEBUG0("Calling domain event callback (no queue)");
> +if(cb)
> +cb(conn,dom,event,opaque);

Needs to call virDomainFree(dom) to release the object.

> +}
> +}
> +
> +static void remoteDomainQueueEvent(virConnectPtr conn, XDR *xdr)
> +{
> +virDomainPtr dom;
> +int event;
> +virConnectDomainEventCallback cb;
> +void *opaque;
> +struct private_data *priv = conn->privateData;
> +
> +if(!remoteDomainReadEvent(conn, xdr, &dom

[libvirt] Re: [PATCH 07/12] Domain Events - remote driver

2008-10-17 Thread Ben Guthro
Deliver local callbacks in response to remote events

 remote_internal.c |  255 --
 1 file changed, 248 insertions(+), 7 deletions(-)
diff --git a/src/remote_internal.c b/src/remote_internal.c
index 35b7b4b..13537f7 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,10 @@ struct private_data {
 unsigned int saslDecodedLength;
 unsigned int saslDecodedOffset;
 #endif
+
+virDomainEventQueuePtr domainEvents; /* The queue of events generated
+  * during a call / response rpc */
+int eventFlushTimer; /* Timer for flushing domainEvents queue */
 };
 
 #define GET_PRIVATE(conn,retcode)   \
@@ -156,7 +162,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 +689,26 @@ doRemoteOpen (virConnectPtr conn,
   (xdrproc_t) xdr_void, (char *) NULL) == -1)
 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,
+  POLLIN | POLLERR | POLLHUP,
+  remoteDomainEventFired,
+  conn) < 0) {
+DEBUG0("virEventAddHandle failed: No addHandleImpl defined. continuing without events.");
+}
+
+DEBUG0("Adding Timeout for remote event queue flushing");
+if ( (priv->eventFlushTimer = virEventAddTimeout(0,
+ remoteDomainEventQueueFlush,
+ conn)) < 0) {
+DEBUG0("virEventAddTimeout failed: No addTimeoutImpl defined. continuing without events.");
+}
 /* Successful. */
 retcode = VIR_DRV_OPEN_SUCCESS;
 
@@ -1101,6 +1130,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 +1166,9 @@ doRemoteClose (virConnectPtr conn, struct private_data *priv)
 /* Free private data. */
 priv->magic = DEAD;
 
+/* Free queued events */
+virDomainEventQueueFree(priv->domainEvents);
+
 return 0;
 }
 
@@ -4288,6 +4325,46 @@ remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open,
 return 0;
 }
 #endif /* HAVE_POLKIT */
+/*--*/
+
+static int remoteDomainEventRegister (virConnectPtr conn,
+   void *callback,
+   void *opaque)
+{
+struct private_data *priv = conn->privateData;
+
+/* dispatch an rpc - so the server sde can track
+   how many callbacks are regstered */
+remote_domain_events_register_args args;
+args.callback = (unsigned long)callback;
+args.user_data = (unsigned long)opaque;
+
+if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_EVENTS_REGISTER,
+  (xdrproc_t) xdr_remote_domain_events_register_args, (char *) &args,
+  (xdrproc_t) xdr_void, (char *) NULL) == -1)
+return -1;
+
+
+return 0;
+}
+
+static int remoteDomainEventDeregister (virConnectPtr conn,
+ void *callback)
+{
+struct private_data *priv = conn->privateData;
+
+/* dispatch an rpc - so the server sde can track
+how many callbacks are regstered */
+remote_domain_events_deregister_args args;
+args.callback = (unsigned long)callback;
+
+if (call (conn, priv,