event: dynamically manage server-side RPC domain events

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.
This commit is contained in:
Eric Blake 2014-01-05 17:23:55 -07:00
parent 74cf8202d2
commit 047fd2e83e
2 changed files with 194 additions and 103 deletions

View File

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

View File

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