[libvirt] [PATCHv2 1/6] event: dynamically manage server-side RPC domain events

Eric Blake eblake at redhat.com
Wed Jan 29 17:49:21 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   | 294 +++++++++++++++++++++++++++++++++++-------------------
 2 files changed, 194 insertions(+), 103 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 5baf0b6..be0af3d 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -192,13 +192,15 @@ remoteRelayDomainEventLifecycle(virConnectPtr conn,
                                 int detail,
                                 void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_lifecycle_msg data;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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));
@@ -206,7 +208,7 @@ remoteRelayDomainEventLifecycle(virConnectPtr conn,
     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);

@@ -218,19 +220,21 @@ remoteRelayDomainEventReboot(virConnectPtr conn,
                              virDomainPtr dom,
                              void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_reboot_msg data;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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);

@@ -244,20 +248,22 @@ remoteRelayDomainEventRTCChange(virConnectPtr conn,
                                 long long offset,
                                 void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_rtc_change_msg data;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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);

@@ -271,20 +277,22 @@ remoteRelayDomainEventWatchdog(virConnectPtr conn,
                                int action,
                                void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_watchdog_msg data;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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);

@@ -300,13 +308,16 @@ remoteRelayDomainEventIOError(virConnectPtr conn,
                               int action,
                               void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_io_error_msg data;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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));
@@ -316,7 +327,7 @@ remoteRelayDomainEventIOError(virConnectPtr conn,
     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);

@@ -337,14 +348,16 @@ remoteRelayDomainEventIOErrorReason(virConnectPtr conn,
                                     const char *reason,
                                     void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_io_error_reason_msg data;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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));
@@ -356,7 +369,7 @@ remoteRelayDomainEventIOErrorReason(virConnectPtr conn,

     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);

@@ -380,17 +393,19 @@ remoteRelayDomainEventGraphics(virConnectPtr conn,
                                virDomainEventGraphicsSubjectPtr subject,
                                void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_graphics_msg data;
     size_t i;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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++) {
@@ -420,7 +435,7 @@ remoteRelayDomainEventGraphics(virConnectPtr conn,
     }
     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);

@@ -450,14 +465,15 @@ remoteRelayDomainEventBlockJob(virConnectPtr conn,
                                int status,
                                void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_block_job_msg data;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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));
@@ -467,7 +483,7 @@ remoteRelayDomainEventBlockJob(virConnectPtr conn,
     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);

@@ -483,19 +499,21 @@ remoteRelayDomainEventControlError(virConnectPtr conn,
                                    virDomainPtr dom,
                                    void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_control_error_msg data;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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);

@@ -512,15 +530,17 @@ remoteRelayDomainEventDiskChange(virConnectPtr conn,
                                  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 || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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));
@@ -542,7 +562,7 @@ remoteRelayDomainEventDiskChange(virConnectPtr conn,

     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);

@@ -562,14 +582,15 @@ remoteRelayDomainEventTrayChange(virConnectPtr conn,
                                  int reason,
                                  void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_tray_change_msg data;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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));
@@ -580,7 +601,7 @@ remoteRelayDomainEventTrayChange(virConnectPtr conn,

     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);

@@ -593,19 +614,21 @@ remoteRelayDomainEventPMWakeup(virConnectPtr conn,
                                int reason ATTRIBUTE_UNUSED,
                                void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_pmwakeup_msg data;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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);

@@ -618,19 +641,21 @@ remoteRelayDomainEventPMSuspend(virConnectPtr conn,
                                 int reason ATTRIBUTE_UNUSED,
                                 void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_pmsuspend_msg data;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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);

@@ -643,20 +668,22 @@ remoteRelayDomainEventBalloonChange(virConnectPtr conn,
                                     unsigned long long actual,
                                     void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_balloon_change_msg data;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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);

@@ -670,19 +697,21 @@ remoteRelayDomainEventPMSuspendDisk(virConnectPtr conn,
                                     int reason ATTRIBUTE_UNUSED,
                                     void *opaque)
 {
-    virNetServerClientPtr client = opaque;
+    daemonClientEventCallbackPtr callback = opaque;
     remote_domain_event_pmsuspend_disk_msg data;

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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);

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

-    if (!client || !remoteRelayDomainEventCheckACL(client, conn, dom))
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
         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));
@@ -712,7 +742,7 @@ remoteRelayDomainEventDeviceRemoved(virConnectPtr conn,

     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);
@@ -797,14 +827,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;
@@ -843,7 +878,6 @@ void *remoteClientInitHook(virNetServerClientPtr client,
                            void *opaque ATTRIBUTE_UNUSED)
 {
     struct daemonClientPrivate *priv;
-    size_t i;

     if (VIR_ALLOC(priv) < 0)
         return NULL;
@@ -854,9 +888,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;
 }
@@ -3220,13 +3251,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);

@@ -3237,23 +3270,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);
@@ -3262,12 +3313,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);

@@ -3278,16 +3331,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;

@@ -3409,13 +3471,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);

@@ -3432,23 +3496,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);
@@ -3458,13 +3540,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);

@@ -3481,16 +3564,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.5.3




More information about the libvir-list mailing list