We want to convert over to server-side events, even for older APIs. To do that, the client side of the remote driver wants to distinguish between legacy virConnectDomainEventRegister and normal virConnectDomainEventRegisterAny, while knowing the client callbackID and the server's serverID for both types of registration. The client also needs to probe whether the server supports server-side filtering. However, for ease of review, we don't actually use the new RPCs until a later patch. * src/conf/object_event_private.h (virObjectEventStateCallbackID): Add parameter. * src/conf/object_event.c (virObjectEventCallbackListAddID) (virObjectEventStateRegisterID): Separate legacy from callbackID. (virObjectEventStateCallbackID): Pass through parameter. (virObjectEventCallbackLookup): Let legacy and global domain lifecycle events share a common remoteID. * src/conf/network_event.c (virNetworkEventStateRegisterID): Update caller. * src/conf/domain_event.c (virDomainEventStateRegister) (virDomainEventStateRegisterID, virDomainEventStateDeregister): Likewise. (virDomainEventStateRegisterClient) (virDomainEventStateCallbackID): Implement new functions. * src/conf/domain_event.h (virDomainEventStateRegisterClient) (virDomainEventStateCallbackID): New prototypes. * src/remote/remote_driver.c (private_data): Add field. (doRemoteOpen): Probe server feature. (remoteConnectDomainEventRegister) (remoteConnectDomainEventRegisterAny): Use new function. Signed-off-by: Eric Blake <eblake@xxxxxxxxxx> --- src/conf/domain_event.c | 78 +++++++++++++++++++++++++++++++++++++++-- src/conf/domain_event.h | 22 ++++++++++++ src/conf/network_event.c | 6 ++-- src/conf/object_event.c | 35 +++++++++--------- src/conf/object_event_private.h | 6 ++-- src/remote/remote_driver.c | 36 +++++++++++++++---- 6 files changed, 154 insertions(+), 29 deletions(-) diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index 8639a01..a490fe5 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 b033b23..be577e9 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 4c59356..f2cfefe 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 aff4956..de45257 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 8e265f9..a19a0d3 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 18eb454..b0257c2 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 -- 1.8.5.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list