diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index 8639a014d6c787709c21788d796dbf5acff71e5b..a490fe53f525ded3b9c78e1a178e3eae64368785 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -1281,6 +1281,8 @@ virDomainEventStateRegister(virConnectPtr conn, void *opaque, virFreeCallback freecb) { + int callbackID; + if (virDomainEventsInitialize() < 0) return -1; @@ -1288,7 +1290,8 @@ virDomainEventStateRegister(virConnectPtr conn, NULL, NULL, virDomainEventClass, VIR_DOMAIN_EVENT_ID_LIFECYCLE, VIR_OBJECT_EVENT_CALLBACK(callback), - opaque, freecb, NULL, false); + opaque, freecb, + true, &callbackID, false); } @@ -1326,7 +1329,75 @@ virDomainEventStateRegisterID(virConnectPtr conn, NULL, NULL, virDomainEventClass, eventID, VIR_OBJECT_EVENT_CALLBACK(cb), - opaque, freecb, callbackID, false); + opaque, freecb, + false, callbackID, false); +} + + +/** + * virDomainEventStateRegisterClient: + * @conn: connection to associate with callback + * @state: object event state + * @dom: optional domain for filtering the event + * @eventID: ID of the event type to register for + * @cb: function to invoke when event fires + * @opaque: data blob to pass to @callback + * @freecb: callback to free @opaque + * @legacy: true if callback is tracked by function instead of callbackID + * @callbackID: filled with callback ID + * @remoteID: true if server supports filtering + * + * Register the function @cb with connection @conn, from @state, for + * events of type @eventID, and return the registration handle in + * @callbackID. This version is intended for use on the client side + * of RPC. + * + * Returns: the number of callbacks now registered, or -1 on error + */ +int +virDomainEventStateRegisterClient(virConnectPtr conn, + virObjectEventStatePtr state, + virDomainPtr dom, + int eventID, + virConnectDomainEventGenericCallback cb, + void *opaque, + virFreeCallback freecb, + bool legacy, + int *callbackID, + bool remoteID) +{ + if (virDomainEventsInitialize() < 0) + return -1; + + return virObjectEventStateRegisterID(conn, state, dom ? dom->uuid : NULL, + NULL, NULL, + virDomainEventClass, eventID, + VIR_OBJECT_EVENT_CALLBACK(cb), + opaque, freecb, + legacy, callbackID, remoteID); +} + + +/** + * virDomainEventStateCallbackID: + * @conn: connection associated with callback + * @state: object event state + * @cb: function registered as a callback with virDomainEventStateRegister() + * @remoteID: associated remote id of the callback + * + * Returns the callbackID of @cb, or -1 with an error issued if the + * function is not currently registered. + */ +int +virDomainEventStateCallbackID(virConnectPtr conn, + virObjectEventStatePtr state, + virConnectDomainEventCallback cb, + int *remoteID) +{ + return virObjectEventStateCallbackID(conn, state, virDomainEventClass, + VIR_DOMAIN_EVENT_ID_LIFECYCLE, + VIR_OBJECT_EVENT_CALLBACK(cb), + remoteID); } @@ -1351,7 +1422,8 @@ virDomainEventStateDeregister(virConnectPtr conn, callbackID = virObjectEventStateCallbackID(conn, state, virDomainEventClass, VIR_DOMAIN_EVENT_ID_LIFECYCLE, - VIR_OBJECT_EVENT_CALLBACK(cb)); + VIR_OBJECT_EVENT_CALLBACK(cb), + NULL); if (callbackID < 0) return -1; return virObjectEventStateDeregisterID(conn, state, callbackID); diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index b033b23fda38a05c1f47e23d10ffd3c7f5fcfd49..be577e9131a224a04744933b83dce1378f20edcb 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -192,6 +192,28 @@ virDomainEventStateRegisterID(virConnectPtr conn, int *callbackID) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(5); int +virDomainEventStateRegisterClient(virConnectPtr conn, + virObjectEventStatePtr state, + virDomainPtr dom, + int eventID, + virConnectDomainEventGenericCallback cb, + void *opaque, + virFreeCallback freecb, + bool legacy, + int *callbackID, + bool remoteID) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(5) + ATTRIBUTE_NONNULL(9); + +int +virDomainEventStateCallbackID(virConnectPtr conn, + virObjectEventStatePtr state, + virConnectDomainEventCallback callback, + int *remoteID) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) + ATTRIBUTE_NONNULL(4); + +int virDomainEventStateDeregister(virConnectPtr conn, virObjectEventStatePtr state, virConnectDomainEventCallback callback) diff --git a/src/conf/network_event.c b/src/conf/network_event.c index 4c59356664cfbfc56f3ed471be7b7ab6181b7b95..f2cfefed3499f515950603082f0b73a2a033c95c 100644 --- a/src/conf/network_event.c +++ b/src/conf/network_event.c @@ -155,7 +155,8 @@ virNetworkEventStateRegisterID(virConnectPtr conn, NULL, NULL, virNetworkEventClass, eventID, VIR_OBJECT_EVENT_CALLBACK(cb), - opaque, freecb, callbackID, false); + opaque, freecb, + false, callbackID, false); } @@ -194,7 +195,8 @@ virNetworkEventStateRegisterClient(virConnectPtr conn, NULL, NULL, virNetworkEventClass, eventID, VIR_OBJECT_EVENT_CALLBACK(cb), - opaque, freecb, callbackID, true); + opaque, freecb, + false, callbackID, true); } diff --git a/src/conf/object_event.c b/src/conf/object_event.c index aff49566145e9456b4d81479aa89381c30b7aa88..de452577e1c06071ae1d20bf7331e5ad2494aecc 100644 --- a/src/conf/object_event.c +++ b/src/conf/object_event.c @@ -334,13 +334,13 @@ virObjectEventCallbackLookup(virConnectPtr conn, if (cb->klass == klass && cb->eventID == eventID && cb->conn == conn && - cb->legacy == legacy && ((uuid && cb->uuid_filter && memcmp(cb->uuid, uuid, VIR_UUID_BUFLEN) == 0) || (!uuid && !cb->uuid_filter))) { if (remoteID) *remoteID = cb->remoteID; - if (cb->cb == callback) + if (cb->legacy == legacy && + cb->cb == callback) return cb->callbackID; } } @@ -360,6 +360,7 @@ virObjectEventCallbackLookup(virConnectPtr conn, * @callback: the callback to add * @opaque: opaque data to pass to @callback * @freecb: callback to free @opaque + * @legacy: true if callback is tracked by function instead of callbackID * @callbackID: filled with callback ID * @serverFilter: true if server supports object filtering * @@ -376,6 +377,7 @@ virObjectEventCallbackListAddID(virConnectPtr conn, virConnectObjectEventGenericCallback callback, void *opaque, virFreeCallback freecb, + bool legacy, int *callbackID, bool serverFilter) { @@ -384,9 +386,10 @@ virObjectEventCallbackListAddID(virConnectPtr conn, int remoteID = -1; VIR_DEBUG("conn=%p cblist=%p uuid=%p filter=%p filter_opaque=%p " - "klass=%p eventID=%d callback=%p opaque=%p", - conn, cbList, uuid, filter, filter_opaque, - klass, eventID, callback, opaque); + "klass=%p eventID=%d callback=%p opaque=%p " + "legacy=%d callbackID=%p serverFilter=%d", + conn, cbList, uuid, filter, filter_opaque, klass, eventID, + callback, opaque, legacy, callbackID, serverFilter); /* Check incoming */ if (!cbList) { @@ -395,8 +398,7 @@ virObjectEventCallbackListAddID(virConnectPtr conn, /* check if we already have this callback on our list */ if (virObjectEventCallbackLookup(conn, cbList, uuid, - klass, eventID, callback, - !callbackID, + klass, eventID, callback, legacy, serverFilter ? &remoteID : NULL) != -1) { virReportError(VIR_ERR_INVALID_ARG, "%s", _("event callback already tracked")); @@ -406,7 +408,7 @@ virObjectEventCallbackListAddID(virConnectPtr conn, if (VIR_ALLOC(event) < 0) goto cleanup; event->conn = virObjectRef(conn); - event->callbackID = cbList->nextID++; + *callbackID = event->callbackID = cbList->nextID++; event->cb = callback; event->klass = klass; event->eventID = eventID; @@ -423,11 +425,7 @@ virObjectEventCallbackListAddID(virConnectPtr conn, } event->filter = filter; event->filter_opaque = filter_opaque; - - if (callbackID) - *callbackID = event->callbackID; - else - event->legacy = true; + event->legacy = legacy; if (VIR_APPEND_ELEMENT(cbList->callbacks, cbList->count, event) < 0) goto cleanup; @@ -833,6 +831,7 @@ virObjectEventStateFlush(virObjectEventStatePtr state) * @cb: function to invoke when event occurs * @opaque: data blob to pass to @callback * @freecb: callback to free @opaque + * @legacy: true if callback is tracked by function instead of callbackID * @callbackID: filled with callback ID * @serverFilter: true if server supports object filtering * @@ -867,6 +866,7 @@ virObjectEventStateRegisterID(virConnectPtr conn, virConnectObjectEventGenericCallback cb, void *opaque, virFreeCallback freecb, + bool legacy, int *callbackID, bool serverFilter) { @@ -889,7 +889,7 @@ virObjectEventStateRegisterID(virConnectPtr conn, uuid, filter, filter_opaque, klass, eventID, cb, opaque, freecb, - callbackID, serverFilter); + legacy, callbackID, serverFilter); if (ret == -1 && state->callbacks->count == 0 && @@ -949,6 +949,7 @@ virObjectEventStateDeregisterID(virConnectPtr conn, * @klass: the base event class * @eventID: the event ID * @callback: function registered as a callback + * @remoteID: optional output, containing resulting remote id * * Returns the callbackID of @callback, or -1 with an error issued if the * function is not currently registered. This only finds functions @@ -960,13 +961,15 @@ virObjectEventStateCallbackID(virConnectPtr conn, virObjectEventStatePtr state, virClassPtr klass, int eventID, - virConnectObjectEventGenericCallback callback) + virConnectObjectEventGenericCallback callback, + int *remoteID) { int ret = -1; virObjectEventStateLock(state); ret = virObjectEventCallbackLookup(conn, state->callbacks, NULL, - klass, eventID, callback, true, NULL); + klass, eventID, callback, true, + remoteID); virObjectEventStateUnlock(state); if (ret < 0) diff --git a/src/conf/object_event_private.h b/src/conf/object_event_private.h index 8e265f94bcdd7ddc703aba2bc419f9bca5379b95..a19a0d3a39db1b4e45d6eb00ba6ba7d3abf3bf0d 100644 --- a/src/conf/object_event_private.h +++ b/src/conf/object_event_private.h @@ -80,17 +80,19 @@ virObjectEventStateRegisterID(virConnectPtr conn, virConnectObjectEventGenericCallback cb, void *opaque, virFreeCallback freecb, + bool legacy, int *callbackID, bool remoteFilter) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(6) - ATTRIBUTE_NONNULL(8); + ATTRIBUTE_NONNULL(8) ATTRIBUTE_NONNULL(12); int virObjectEventStateCallbackID(virConnectPtr conn, virObjectEventStatePtr state, virClassPtr klass, int eventID, - virConnectObjectEventGenericCallback callback) + virConnectObjectEventGenericCallback callback, + int *remoteID) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(5); diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 18eb454f58285ce08a42aa824011bd0024bb6a68..b0257c2c1ce631b18ccfe00f82f5dbc14feb316a 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -92,6 +92,7 @@ struct private_data { int localUses; /* Ref count for private data */ char *hostname; /* Original hostname */ bool serverKeepAlive; /* Does server support keepalive protocol? */ + bool serverEventFilter; /* Does server support modern event filtering */ virObjectEventStatePtr eventState; }; @@ -890,8 +891,26 @@ doRemoteOpen(virConnectPtr conn, goto failed; } + /* Set up events */ if (!(priv->eventState = virObjectEventStateNew())) goto failed; + { + remote_connect_supports_feature_args args = + { VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK }; + remote_connect_supports_feature_ret ret = { 0 }; + int rc; + + rc = call(conn, priv, 0, REMOTE_PROC_CONNECT_SUPPORTS_FEATURE, + (xdrproc_t)xdr_remote_connect_supports_feature_args, (char *) &args, + (xdrproc_t)xdr_remote_connect_supports_feature_ret, (char *) &ret); + + if (rc != -1 && ret.supported) { + priv->serverEventFilter = true; + } else { + VIR_INFO("Avoiding server event filtering since it is not " + "supported by the server"); + } + } /* Successful. */ retcode = VIR_DRV_OPEN_SUCCESS; @@ -4421,14 +4440,19 @@ remoteConnectDomainEventRegister(virConnectPtr conn, void *opaque, virFreeCallback freecb) { + int callbackID; int rv = -1; struct private_data *priv = conn->privateData; int count; remoteDriverLock(priv); - if ((count = virDomainEventStateRegister(conn, priv->eventState, - callback, opaque, freecb)) < 0) + if ((count = virDomainEventStateRegisterClient(conn, priv->eventState, + NULL, + VIR_DOMAIN_EVENT_ID_LIFECYCLE, + VIR_DOMAIN_EVENT_CALLBACK(callback), + opaque, freecb, true, + &callbackID, false)) < 0) goto done; if (count == 1) { @@ -5245,10 +5269,10 @@ remoteConnectDomainEventRegisterAny(virConnectPtr conn, remoteDriverLock(priv); - if ((count = virDomainEventStateRegisterID(conn, priv->eventState, - dom, eventID, - callback, opaque, freecb, - &callbackID)) < 0) + if ((count = virDomainEventStateRegisterClient(conn, priv->eventState, + dom, eventID, callback, + opaque, freecb, false, + &callbackID, false)) < 0) goto done; /* If this is the first callback for this eventID, we need to enable