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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list