void *opaque,
virFreeCallback freecb)
{
+ int callbackID;
+
if (virDomainEventsInitialize() < 0)
return -1;
NULL, NULL, virDomainEventClass,
VIR_DOMAIN_EVENT_ID_LIFECYCLE,
VIR_OBJECT_EVENT_CALLBACK(callback),
- opaque, freecb, NULL, false);
+ opaque, freecb,
+ true, &callbackID, false);
}
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);
}
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);
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)
NULL, NULL,
virNetworkEventClass, eventID,
VIR_OBJECT_EVENT_CALLBACK(cb),
- opaque, freecb, callbackID, false);
+ opaque, freecb,
+ false, callbackID, false);
}
NULL, NULL,
virNetworkEventClass, eventID,
VIR_OBJECT_EVENT_CALLBACK(cb),
- opaque, freecb, callbackID, true);
+ opaque, freecb,
+ false, callbackID, true);
}
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;
}
}
* @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
*
virConnectObjectEventGenericCallback callback,
void *opaque,
virFreeCallback freecb,
+ bool legacy,
int *callbackID,
bool serverFilter)
{
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) {
/* 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"));
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;
}
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;
* @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
*
virConnectObjectEventGenericCallback cb,
void *opaque,
virFreeCallback freecb,
+ bool legacy,
int *callbackID,
bool serverFilter)
{
uuid, filter, filter_opaque,
klass, eventID,
cb, opaque, freecb,
- callbackID, serverFilter);
+ legacy, callbackID, serverFilter);
if (ret == -1 &&
state->callbacks->count == 0 &&
* @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
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)
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);
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;
};
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;
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) {
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