[libvirt] [PATCH 1/5] event: dynamically manage server-side RPC domain events

Eric Blake eblake at redhat.com
Wed Jan 15 23:23:02 UTC 2014


This patch continues the earlier conversion made for network
events, with a goal of introducing server-side event filtering
in a later patch.  Actual behavior is unchanged without
further RPC changes.

* daemon/libvirtd.h (daemonClientPrivate): Alter the tracking of
domain events.
* daemon/remote.c (remoteClientInitHook, remoteClientFreeFunc)
(remoteRelayDomainEvent*)
(remoteDispatchConnectDomainEventRegister)
(remoteDispatchConnectDomainEventRegisterAny): Track domain
callbacks dynamically.
---
 daemon/libvirtd.h |   3 +-
 daemon/remote.c   | 436 +++++++++++++++++++++++++++++++++---------------------
 2 files changed, 266 insertions(+), 173 deletions(-)

diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h
index a260ea1..c4f1f27 100644
--- a/daemon/libvirtd.h
+++ b/daemon/libvirtd.h
@@ -51,7 +51,8 @@ struct daemonClientPrivate {
     /* Hold while accessing any data except conn */
     virMutex lock;

-    int domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LAST];
+    daemonClientEventCallbackPtr *domainEventCallbacks;
+    size_t ndomainEventCallbacks;
     daemonClientEventCallbackPtr *networkEventCallbacks;
     size_t nnetworkEventCallbacks;

diff --git a/daemon/remote.c b/daemon/remote.c
index d2aafbe..f0b9922 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -127,19 +127,21 @@ remoteEventCallbackFree(void *opaque)
     VIR_FREE(opaque);
 }

-static int remoteRelayDomainEventLifecycle(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                           virDomainPtr dom,
-                                           int event,
-                                           int detail,
-                                           void *opaque)
+static int
+remoteRelayDomainEventLifecycle(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                virDomainPtr dom,
+                                int event,
+                                int detail,
+                                void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_lifecycle_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain lifecycle event %d %d", event, detail);
+    VIR_DEBUG("Relaying domain lifecycle event %d %d, callback %d",
+              event, detail, callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
@@ -147,30 +149,32 @@ static int remoteRelayDomainEventLifecycle(virConnectPtr conn ATTRIBUTE_UNUSED,
     data.event = event;
     data.detail = detail;

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE,
                                   (xdrproc_t)xdr_remote_domain_event_lifecycle_msg, &data);

     return 0;
 }

-static int remoteRelayDomainEventReboot(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                        virDomainPtr dom,
-                                        void *opaque)
+static int
+remoteRelayDomainEventReboot(virConnectPtr conn ATTRIBUTE_UNUSED,
+                             virDomainPtr dom,
+                             void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_reboot_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain reboot event %s %d", dom->name, dom->id);
+    VIR_DEBUG("Relaying domain reboot event %s %d, callback %d",
+              dom->name, dom->id, callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
     make_nonnull_domain(&data.dom, dom);

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_REBOOT,
                                   (xdrproc_t)xdr_remote_domain_event_reboot_msg, &data);

@@ -178,25 +182,27 @@ static int remoteRelayDomainEventReboot(virConnectPtr conn ATTRIBUTE_UNUSED,
 }


-static int remoteRelayDomainEventRTCChange(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                           virDomainPtr dom,
-                                           long long offset,
-                                           void *opaque)
+static int
+remoteRelayDomainEventRTCChange(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                virDomainPtr dom,
+                                long long offset,
+                                void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_rtc_change_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain rtc change event %s %d %lld", dom->name, dom->id, offset);
+    VIR_DEBUG("Relaying domain rtc change event %s %d %lld, callback %d",
+              dom->name, dom->id, offset, callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
     make_nonnull_domain(&data.dom, dom);
     data.offset = offset;

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
                                   (xdrproc_t)xdr_remote_domain_event_rtc_change_msg, &data);

@@ -204,25 +210,27 @@ static int remoteRelayDomainEventRTCChange(virConnectPtr conn ATTRIBUTE_UNUSED,
 }


-static int remoteRelayDomainEventWatchdog(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                          virDomainPtr dom,
-                                          int action,
-                                          void *opaque)
+static int
+remoteRelayDomainEventWatchdog(virConnectPtr conn ATTRIBUTE_UNUSED,
+                               virDomainPtr dom,
+                               int action,
+                               void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_watchdog_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain watchdog event %s %d %d", dom->name, dom->id, action);
+    VIR_DEBUG("Relaying domain watchdog event %s %d %d, callback %d",
+              dom->name, dom->id, action, callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
     make_nonnull_domain(&data.dom, dom);
     data.action = action;

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_WATCHDOG,
                                   (xdrproc_t)xdr_remote_domain_event_watchdog_msg, &data);

@@ -230,20 +238,23 @@ static int remoteRelayDomainEventWatchdog(virConnectPtr conn ATTRIBUTE_UNUSED,
 }


-static int remoteRelayDomainEventIOError(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                         virDomainPtr dom,
-                                         const char *srcPath,
-                                         const char *devAlias,
-                                         int action,
-                                         void *opaque)
+static int
+remoteRelayDomainEventIOError(virConnectPtr conn ATTRIBUTE_UNUSED,
+                              virDomainPtr dom,
+                              const char *srcPath,
+                              const char *devAlias,
+                              int action,
+                              void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_io_error_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain io error %s %d %s %s %d", dom->name, dom->id, srcPath, devAlias, action);
+    VIR_DEBUG("Relaying domain io error %s %d %s %s %d, callback %d",
+              dom->name, dom->id, srcPath, devAlias, action,
+              callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
@@ -253,7 +264,7 @@ static int remoteRelayDomainEventIOError(virConnectPtr conn ATTRIBUTE_UNUSED,
     make_nonnull_domain(&data.dom, dom);
     data.action = action;

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_IO_ERROR,
                                   (xdrproc_t)xdr_remote_domain_event_io_error_msg, &data);

@@ -265,22 +276,24 @@ error:
 }


-static int remoteRelayDomainEventIOErrorReason(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                               virDomainPtr dom,
-                                               const char *srcPath,
-                                               const char *devAlias,
-                                               int action,
-                                               const char *reason,
-                                               void *opaque)
+static int
+remoteRelayDomainEventIOErrorReason(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                    virDomainPtr dom,
+                                    const char *srcPath,
+                                    const char *devAlias,
+                                    int action,
+                                    const char *reason,
+                                    void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_io_error_reason_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain io error %s %d %s %s %d %s",
-              dom->name, dom->id, srcPath, devAlias, action, reason);
+    VIR_DEBUG("Relaying domain io error %s %d %s %s %d %s, callback %d",
+              dom->name, dom->id, srcPath, devAlias, action, reason,
+              callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
@@ -292,7 +305,7 @@ static int remoteRelayDomainEventIOErrorReason(virConnectPtr conn ATTRIBUTE_UNUS

     make_nonnull_domain(&data.dom, dom);

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON,
                                   (xdrproc_t)xdr_remote_domain_event_io_error_reason_msg, &data);

@@ -306,26 +319,28 @@ error:
 }


-static int remoteRelayDomainEventGraphics(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                          virDomainPtr dom,
-                                          int phase,
-                                          virDomainEventGraphicsAddressPtr local,
-                                          virDomainEventGraphicsAddressPtr remote,
-                                          const char *authScheme,
-                                          virDomainEventGraphicsSubjectPtr subject,
-                                          void *opaque)
+static int
+remoteRelayDomainEventGraphics(virConnectPtr conn ATTRIBUTE_UNUSED,
+                               virDomainPtr dom,
+                               int phase,
+                               virDomainEventGraphicsAddressPtr local,
+                               virDomainEventGraphicsAddressPtr remote,
+                               const char *authScheme,
+                               virDomainEventGraphicsSubjectPtr subject,
+                               void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_graphics_msg data;
     size_t i;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain graphics event %s %d %d - %d %s %s  - %d %s %s - %s", dom->name, dom->id, phase,
+    VIR_DEBUG("Relaying domain graphics event %s %d %d - %d %s %s  - %d %s %s - %s, callback %d",
+              dom->name, dom->id, phase,
               local->family, local->service, local->node,
               remote->family, remote->service, remote->node,
-              authScheme);
+              authScheme, callback->callbackID);

     VIR_DEBUG("Subject %d", subject->nidentity);
     for (i = 0; i < subject->nidentity; i++) {
@@ -355,7 +370,7 @@ static int remoteRelayDomainEventGraphics(virConnectPtr conn ATTRIBUTE_UNUSED,
     }
     make_nonnull_domain(&data.dom, dom);

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_GRAPHICS,
                                   (xdrproc_t)xdr_remote_domain_event_graphics_msg, &data);

@@ -377,21 +392,22 @@ error:
     return -1;
 }

-static int remoteRelayDomainEventBlockJob(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                          virDomainPtr dom,
-                                          const char *path,
-                                          int type,
-                                          int status,
-                                          void *opaque)
+static int
+remoteRelayDomainEventBlockJob(virConnectPtr conn ATTRIBUTE_UNUSED,
+                               virDomainPtr dom,
+                               const char *path,
+                               int type,
+                               int status,
+                               void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_block_job_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain block job event %s %d %s %i, %i",
-              dom->name, dom->id, path, type, status);
+    VIR_DEBUG("Relaying domain block job event %s %d %s %i, %i, callback %d",
+              dom->name, dom->id, path, type, status, callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
@@ -401,7 +417,7 @@ static int remoteRelayDomainEventBlockJob(virConnectPtr conn ATTRIBUTE_UNUSED,
     data.status = status;
     make_nonnull_domain(&data.dom, dom);

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB,
                                   (xdrproc_t)xdr_remote_domain_event_block_job_msg, &data);

@@ -412,23 +428,25 @@ error:
 }


-static int remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                              virDomainPtr dom,
-                                              void *opaque)
+static int
+remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                   virDomainPtr dom,
+                                   void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_control_error_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain control error %s %d", dom->name, dom->id);
+    VIR_DEBUG("Relaying domain control error %s %d, callback %d",
+              dom->name, dom->id, callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
     make_nonnull_domain(&data.dom, dom);

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR,
                                   (xdrproc_t)xdr_remote_domain_event_control_error_msg, &data);

@@ -436,23 +454,25 @@ static int remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSE
 }


-static int remoteRelayDomainEventDiskChange(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                            virDomainPtr dom,
-                                            const char *oldSrcPath,
-                                            const char *newSrcPath,
-                                            const char *devAlias,
-                                            int reason,
-                                            void *opaque)
+static int
+remoteRelayDomainEventDiskChange(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                 virDomainPtr dom,
+                                 const char *oldSrcPath,
+                                 const char *newSrcPath,
+                                 const char *devAlias,
+                                 int reason,
+                                 void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_disk_change_msg data;
     char **oldSrcPath_p = NULL, **newSrcPath_p = NULL;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain %s %d disk change %s %s %s %d",
-              dom->name, dom->id, oldSrcPath, newSrcPath, devAlias, reason);
+    VIR_DEBUG("Relaying domain %s %d disk change %s %s %s %d, callback %d",
+              dom->name, dom->id, oldSrcPath, newSrcPath, devAlias, reason,
+              callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
@@ -474,7 +494,7 @@ static int remoteRelayDomainEventDiskChange(virConnectPtr conn ATTRIBUTE_UNUSED,

     make_nonnull_domain(&data.dom, dom);

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE,
                                   (xdrproc_t)xdr_remote_domain_event_disk_change_msg, &data);

@@ -487,19 +507,21 @@ error:
 }


-static int remoteRelayDomainEventTrayChange(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                            virDomainPtr dom,
-                                            const char *devAlias,
-                                            int reason,
-                                            void *opaque) {
-    virNetServerClientPtr client = opaque;
+static int
+remoteRelayDomainEventTrayChange(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                 virDomainPtr dom,
+                                 const char *devAlias,
+                                 int reason,
+                                 void *opaque)
+{
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_tray_change_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain %s %d tray change devAlias: %s reason: %d",
-              dom->name, dom->id, devAlias, reason);
+    VIR_DEBUG("Relaying domain %s %d tray change devAlias: %s reason: %d, callback %d",
+              dom->name, dom->id, devAlias, reason, callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
@@ -510,53 +532,59 @@ static int remoteRelayDomainEventTrayChange(virConnectPtr conn ATTRIBUTE_UNUSED,

     make_nonnull_domain(&data.dom, dom);

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_TRAY_CHANGE,
                                   (xdrproc_t)xdr_remote_domain_event_tray_change_msg, &data);

     return 0;
 }

-static int remoteRelayDomainEventPMWakeup(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                          virDomainPtr dom,
-                                          int reason ATTRIBUTE_UNUSED,
-                                          void *opaque) {
-    virNetServerClientPtr client = opaque;
+static int
+remoteRelayDomainEventPMWakeup(virConnectPtr conn ATTRIBUTE_UNUSED,
+                               virDomainPtr dom,
+                               int reason ATTRIBUTE_UNUSED,
+                               void *opaque)
+{
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_pmwakeup_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain %s %d system pmwakeup", dom->name, dom->id);
+    VIR_DEBUG("Relaying domain %s %d system pmwakeup, callback %d",
+              dom->name, dom->id, callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
     make_nonnull_domain(&data.dom, dom);

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_PMWAKEUP,
                                   (xdrproc_t)xdr_remote_domain_event_pmwakeup_msg, &data);

     return 0;
 }

-static int remoteRelayDomainEventPMSuspend(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                           virDomainPtr dom,
-                                           int reason ATTRIBUTE_UNUSED,
-                                           void *opaque) {
-    virNetServerClientPtr client = opaque;
+static int
+remoteRelayDomainEventPMSuspend(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                virDomainPtr dom,
+                                int reason ATTRIBUTE_UNUSED,
+                                void *opaque)
+{
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_pmsuspend_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain %s %d system pmsuspend", dom->name, dom->id);
+    VIR_DEBUG("Relaying domain %s %d system pmsuspend, callback %d",
+              dom->name, dom->id, callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
     make_nonnull_domain(&data.dom, dom);

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND,
                                   (xdrproc_t)xdr_remote_domain_event_pmsuspend_msg, &data);

@@ -569,20 +597,21 @@ remoteRelayDomainEventBalloonChange(virConnectPtr conn ATTRIBUTE_UNUSED,
                                     unsigned long long actual,
                                     void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_balloon_change_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain balloon change event %s %d %lld", dom->name, dom->id, actual);
+    VIR_DEBUG("Relaying domain balloon change event %s %d %lld, callback %d",
+              dom->name, dom->id, actual, callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
     make_nonnull_domain(&data.dom, dom);
     data.actual = actual;

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE,
                                   (xdrproc_t)xdr_remote_domain_event_balloon_change_msg, &data);

@@ -590,23 +619,26 @@ remoteRelayDomainEventBalloonChange(virConnectPtr conn ATTRIBUTE_UNUSED,
 }


-static int remoteRelayDomainEventPMSuspendDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
-                                               virDomainPtr dom,
-                                               int reason ATTRIBUTE_UNUSED,
-                                               void *opaque) {
-    virNetServerClientPtr client = opaque;
+static int
+remoteRelayDomainEventPMSuspendDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                    virDomainPtr dom,
+                                    int reason ATTRIBUTE_UNUSED,
+                                    void *opaque)
+{
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_pmsuspend_disk_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain %s %d system pmsuspend-disk", dom->name, dom->id);
+    VIR_DEBUG("Relaying domain %s %d system pmsuspend-disk, callback %d",
+              dom->name, dom->id, callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
     make_nonnull_domain(&data.dom, dom);

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND_DISK,
                                   (xdrproc_t)xdr_remote_domain_event_pmsuspend_disk_msg, &data);

@@ -619,14 +651,14 @@ remoteRelayDomainEventDeviceRemoved(virConnectPtr conn ATTRIBUTE_UNUSED,
                                     const char *devAlias,
                                     void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_device_removed_msg data;

-    if (!client)
+    if (callback->callbackID < 0)
         return -1;

-    VIR_DEBUG("Relaying domain device removed event %s %d %s",
-              dom->name, dom->id, devAlias);
+    VIR_DEBUG("Relaying domain device removed event %s %d %s, callback %d",
+              dom->name, dom->id, devAlias, callback->callbackID);

     /* build return data */
     memset(&data, 0, sizeof(data));
@@ -636,7 +668,7 @@ remoteRelayDomainEventDeviceRemoved(virConnectPtr conn ATTRIBUTE_UNUSED,

     make_nonnull_domain(&data.dom, dom);

-    remoteDispatchObjectEventSend(client, remoteProgram,
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                   REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED,
                                   (xdrproc_t)xdr_remote_domain_event_device_removed_msg,
                                   &data);
@@ -720,14 +752,19 @@ void remoteClientFreeFunc(void *data)

         virIdentitySetCurrent(sysident);

-        for (i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i++) {
-            if (priv->domainEventCallbackID[i] != -1) {
-                VIR_DEBUG("Deregistering to relay remote events %zu", i);
-                virConnectDomainEventDeregisterAny(priv->conn,
-                                                   priv->domainEventCallbackID[i]);
+        for (i = 0; i < priv->ndomainEventCallbacks; i++) {
+            int callbackID = priv->domainEventCallbacks[i]->callbackID;
+            if (callbackID < 0) {
+                VIR_WARN("unexpected incomplete domain callback %zu", i);
+                continue;
             }
-            priv->domainEventCallbackID[i] = -1;
+            VIR_DEBUG("Deregistering remote domain event relay %d",
+                      callbackID);
+            priv->domainEventCallbacks[i]->callbackID = -1;
+            if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
+                VIR_WARN("unexpected domain event deregister failure");
         }
+        VIR_FREE(priv->domainEventCallbacks);

         for (i = 0; i < priv->nnetworkEventCallbacks; i++) {
             int callbackID = priv->networkEventCallbacks[i]->callbackID;
@@ -766,7 +803,6 @@ void *remoteClientInitHook(virNetServerClientPtr client,
                            void *opaque ATTRIBUTE_UNUSED)
 {
     struct daemonClientPrivate *priv;
-    size_t i;

     if (VIR_ALLOC(priv) < 0)
         return NULL;
@@ -777,9 +813,6 @@ void *remoteClientInitHook(virNetServerClientPtr client,
         return NULL;
     }

-    for (i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i++)
-        priv->domainEventCallbackID[i] = -1;
-
     virNetServerClientSetCloseHook(client, remoteClientCloseFunc);
     return priv;
 }
@@ -3143,13 +3176,15 @@ cleanup:
  ***************************/
 static int
 remoteDispatchConnectDomainEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
-                                         virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                         virNetServerClientPtr client,
                                          virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                          virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                          remote_connect_domain_event_register_ret *ret ATTRIBUTE_UNUSED)
 {
     int callbackID;
     int rv = -1;
+    daemonClientEventCallbackPtr callback = NULL;
+    daemonClientEventCallbackPtr ref;
     struct daemonClientPrivate *priv =
         virNetServerClientGetPrivateData(client);

@@ -3160,23 +3195,41 @@ remoteDispatchConnectDomainEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED

     virMutexLock(&priv->lock);

-    if (priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] != -1) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, _("domain event %d already registered"), VIR_DOMAIN_EVENT_ID_LIFECYCLE);
+    /* If we call register first, we could append a complete callback
+     * to our array, but on OOM append failure, we'd have to then hope
+     * deregister works to undo our register.  So instead we append an
+     * incomplete callback to our array, then register, then fix up
+     * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
+     * success, we use 'ref' to save a copy of the pointer.  */
+    if (VIR_ALLOC(callback) < 0)
+        goto cleanup;
+    callback->client = client;
+    callback->eventID = VIR_DOMAIN_EVENT_ID_LIFECYCLE;
+    callback->callbackID = -1;
+    ref = callback;
+    if (VIR_APPEND_ELEMENT(priv->domainEventCallbacks,
+                           priv->ndomainEventCallbacks,
+                           callback) < 0)
         goto cleanup;
-    }

     if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
                                                        NULL,
                                                        VIR_DOMAIN_EVENT_ID_LIFECYCLE,
                                                        VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
-                                                       client, NULL)) < 0)
+                                                       ref,
+                                                       remoteEventCallbackFree)) < 0) {
+        VIR_SHRINK_N(priv->domainEventCallbacks,
+                     priv->ndomainEventCallbacks, 1);
+        callback = ref;
         goto cleanup;
+    }

-    priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = callbackID;
+    ref->callbackID = callbackID;

     rv = 0;

 cleanup:
+    VIR_FREE(callback);
     if (rv < 0)
         virNetMessageSaveError(rerr);
     virMutexUnlock(&priv->lock);
@@ -3185,12 +3238,14 @@ cleanup:

 static int
 remoteDispatchConnectDomainEventDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
-                                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                           virNetServerClientPtr client,
                                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                            virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                            remote_connect_domain_event_deregister_ret *ret ATTRIBUTE_UNUSED)
 {
+    int callbackID = -1;
     int rv = -1;
+    size_t i;
     struct daemonClientPrivate *priv =
         virNetServerClientGetPrivateData(client);

@@ -3201,16 +3256,25 @@ remoteDispatchConnectDomainEventDeregister(virNetServerPtr server ATTRIBUTE_UNUS

     virMutexLock(&priv->lock);

-    if (priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, _("domain event %d not registered"), VIR_DOMAIN_EVENT_ID_LIFECYCLE);
+    for (i = 0; i < priv->ndomainEventCallbacks; i++) {
+        if (priv->domainEventCallbacks[i]->eventID == VIR_DOMAIN_EVENT_ID_LIFECYCLE) {
+            callbackID = priv->domainEventCallbacks[i]->callbackID;
+            break;
+        }
+    }
+
+    if (callbackID < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("domain event %d not registered"),
+                       VIR_DOMAIN_EVENT_ID_LIFECYCLE);
         goto cleanup;
     }

-    if (virConnectDomainEventDeregisterAny(priv->conn,
-                                           priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE]) < 0)
+    if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
         goto cleanup;

-    priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = -1;
+    VIR_DELETE_ELEMENT(priv->domainEventCallbacks, i,
+                       priv->ndomainEventCallbacks);

     rv = 0;

@@ -3332,13 +3396,15 @@ cleanup:

 static int
 remoteDispatchConnectDomainEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
-                                            virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                            virNetServerClientPtr client,
                                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                             virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                             remote_connect_domain_event_register_any_args *args)
 {
     int callbackID;
     int rv = -1;
+    daemonClientEventCallbackPtr callback = NULL;
+    daemonClientEventCallbackPtr ref;
     struct daemonClientPrivate *priv =
         virNetServerClientGetPrivateData(client);

@@ -3355,23 +3421,41 @@ remoteDispatchConnectDomainEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNU
         goto cleanup;
     }

-    if (priv->domainEventCallbackID[args->eventID] != -1)  {
-        virReportError(VIR_ERR_INTERNAL_ERROR, _("domain event %d already registered"), args->eventID);
+    /* If we call register first, we could append a complete callback
+     * to our array, but on OOM append failure, we'd have to then hope
+     * deregister works to undo our register.  So instead we append an
+     * incomplete callback to our array, then register, then fix up
+     * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
+     * success, we use 'ref' to save a copy of the pointer.  */
+    if (VIR_ALLOC(callback) < 0)
+        goto cleanup;
+    callback->client = client;
+    callback->eventID = args->eventID;
+    callback->callbackID = -1;
+    ref = callback;
+    if (VIR_APPEND_ELEMENT(priv->domainEventCallbacks,
+                           priv->ndomainEventCallbacks,
+                           callback) < 0)
         goto cleanup;
-    }

     if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
                                                        NULL,
                                                        args->eventID,
                                                        domainEventCallbacks[args->eventID],
-                                                       client, NULL)) < 0)
+                                                       ref,
+                                                       remoteEventCallbackFree)) < 0) {
+        VIR_SHRINK_N(priv->domainEventCallbacks,
+                     priv->ndomainEventCallbacks, 1);
+        callback = ref;
         goto cleanup;
+    }

-    priv->domainEventCallbackID[args->eventID] = callbackID;
+    ref->callbackID = callbackID;

     rv = 0;

 cleanup:
+    VIR_FREE(callback);
     if (rv < 0)
         virNetMessageSaveError(rerr);
     virMutexUnlock(&priv->lock);
@@ -3381,13 +3465,14 @@ cleanup:

 static int
 remoteDispatchConnectDomainEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
-                                              virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                              virNetServerClientPtr client,
                                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                               virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                               remote_connect_domain_event_deregister_any_args *args)
 {
     int callbackID = -1;
     int rv = -1;
+    size_t i;
     struct daemonClientPrivate *priv =
         virNetServerClientGetPrivateData(client);

@@ -3404,16 +3489,23 @@ remoteDispatchConnectDomainEventDeregisterAny(virNetServerPtr server ATTRIBUTE_U
         goto cleanup;
     }

-    callbackID = priv->domainEventCallbackID[args->eventID];
+    for (i = 0; i < priv->ndomainEventCallbacks; i++) {
+        if (priv->domainEventCallbacks[i]->eventID == args->eventID) {
+            callbackID = priv->domainEventCallbacks[i]->callbackID;
+            break;
+        }
+    }
     if (callbackID < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, _("domain event %d not registered"), args->eventID);
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("domain event %d not registered"), args->eventID);
         goto cleanup;
     }

     if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
         goto cleanup;

-    priv->domainEventCallbackID[args->eventID] = -1;
+    VIR_DELETE_ELEMENT(priv->domainEventCallbacks, i,
+                       priv->ndomainEventCallbacks);

     rv = 0;

-- 
1.8.4.2




More information about the libvir-list mailing list