From: Nikolay Shirokovskiy <nshirokovskiy(a)virtuozzo.com>
Add conneciton close subscription/unsubscription and event rpc.
Now remote driver firing connection close event in 2 cases.
1. connection to daemon closed, as previously
2. as a relay of connection close event from wrapped driver
As it commented out in remoteDispatchConnectCloseCallbackRegister we impose
some multi-thread requirements on drivers implementations. This is the same
approach as in for example remoteDispatchConnectDomainEventRegister.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy(a)virtuozzo.com>
---
daemon/libvirtd.h | 1 +
daemon/remote.c | 86 ++++++++++++++++++++++++++++++++++++++++++
src/remote/remote_driver.c | 53 +++++++++++++++++++++++++-
src/remote/remote_protocol.x | 24 +++++++++++-
src/remote_protocol-structs | 6 +++
5 files changed, 167 insertions(+), 3 deletions(-)
diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h
index 8c1a904..5b2d2ca 100644
--- a/daemon/libvirtd.h
+++ b/daemon/libvirtd.h
@@ -60,6 +60,7 @@ struct daemonClientPrivate {
size_t nnetworkEventCallbacks;
daemonClientEventCallbackPtr *qemuEventCallbacks;
size_t nqemuEventCallbacks;
+ bool closeRegistered;
# if WITH_SASL
virNetSASLSessionPtr sasl;
diff --git a/daemon/remote.c b/daemon/remote.c
index e9e2dca..366ecd5 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -1189,6 +1189,20 @@ remoteRelayDomainQemuMonitorEvent(virConnectPtr conn,
VIR_FREE(details_p);
}
+static
+void remoteRelayConnectionClosedEvent(virConnectPtr conn ATTRIBUTE_UNUSED, int reason,
void *opaque)
+{
+ virNetServerClientPtr client = opaque;
+
+ VIR_DEBUG("Relaying connection closed event, reason %d", reason);
+
+ remote_connect_event_connection_closed_msg msg = { reason };
+ remoteDispatchObjectEventSend(client, remoteProgram,
+ REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED,
+
(xdrproc_t)xdr_remote_connect_event_connection_closed_msg,
+ &msg);
+}
+
/*
* You must hold lock for at least the client
* We don't free stuff here, merely disconnect the client's
@@ -1251,6 +1265,12 @@ void remoteClientFreeFunc(void *data)
}
VIR_FREE(priv->qemuEventCallbacks);
+ if (priv->closeRegistered) {
+ if (virConnectUnregisterCloseCallback(priv->conn,
+ remoteRelayConnectionClosedEvent) <
0)
+ VIR_WARN("unexpected close callback event deregister
failure");
+ }
+
virConnectClose(priv->conn);
virIdentitySetCurrent(NULL);
@@ -3489,6 +3509,72 @@ remoteDispatchNodeDeviceGetParent(virNetServerPtr server
ATTRIBUTE_UNUSED,
return rv;
}
+static int
+remoteDispatchConnectCloseCallbackRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr)
+{
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ virMutexLock(&priv->lock);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not
open"));
+ goto cleanup;
+ }
+
+ /* NetClient is passed to driver but not referenced.
+ This imposes next requirements on drivers implementation.
+ Driver must serialize unregistering and event delivering operations.
+ Thus as we unregister callback before unreferencing NetClient
+ remoteRelayConnectionClosedEvent is safe to use NetClient. */
+ if (virConnectRegisterCloseCallback(priv->conn, remoteRelayConnectionClosedEvent,
client, NULL) < 0)
+ goto cleanup;
+
+ priv->closeRegistered = true;
+
+ rv = 0;
+
+ cleanup:
+ virMutexUnlock(&priv->lock);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ return rv;
+}
+
+static int
+remoteDispatchConnectCloseCallbackUnregister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr)
+{
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ virMutexLock(&priv->lock);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not
open"));
+ goto cleanup;
+ }
+
+ if (virConnectUnregisterCloseCallback(priv->conn,
remoteRelayConnectionClosedEvent) < 0)
+ goto cleanup;
+
+ priv->closeRegistered = false;
+
+ rv = 0;
+
+ cleanup:
+ virMutexUnlock(&priv->lock);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ return rv;
+}
/***************************
* Register / deregister events
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index e1138a8..b2cd1ea 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -347,6 +347,11 @@ remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog
ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque);
+static void
+remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque);
+
static virNetClientProgramEvent remoteEvents[] = {
{ REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE,
remoteDomainBuildEventLifecycle,
@@ -505,8 +510,23 @@ static virNetClientProgramEvent remoteEvents[] = {
remoteDomainBuildEventCallbackDeviceAdded,
sizeof(remote_domain_event_callback_device_added_msg),
(xdrproc_t)xdr_remote_domain_event_callback_device_added_msg },
+ { REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED,
+ remoteConnectNotifyEventConnectionClosed,
+ sizeof(remote_connect_event_connection_closed_msg),
+ (xdrproc_t)xdr_remote_connect_event_connection_closed_msg },
};
+static void
+remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_connect_event_connection_closed_msg *msg = evdata;
+
+ virConnectCloseCallbackCall(priv->closeCallback, msg->reason);
+}
static void
remoteDomainBuildQemuMonitorEvent(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
@@ -8034,17 +8054,46 @@ remoteConnectRegisterCloseCallback(virConnectPtr conn,
virFreeCallback freecb)
{
struct private_data *priv = conn->privateData;
+ int ret = -1;
+
+ remoteDriverLock(priv);
+
+ if (virConnectCloseCallbackRegister(priv->closeCallback, conn, cb, opaque, freecb)
< 0)
+ goto cleanup;
+
+ if (call(conn, priv, 0, REMOTE_PROC_CONNECT_CLOSE_CALLBACK_REGISTER,
+ (xdrproc_t) xdr_void, (char *) NULL,
+ (xdrproc_t) xdr_void, (char *) NULL) == -1) {
+ virConnectCloseCallbackUnregister(priv->closeCallback);
+ goto cleanup;
+ }
- return virConnectCloseCallbackRegister(priv->closeCallback, conn, cb, opaque,
freecb);
+ ret = 0;
+ cleanup:
+ remoteDriverUnlock(priv);
+ return ret;
}
static int
remoteConnectUnregisterCloseCallback(virConnectPtr conn, virConnectCloseFunc cb
ATTRIBUTE_UNUSED)
{
struct private_data *priv = conn->privateData;
+ int ret = -1;
+
+ remoteDriverLock(priv);
+
+ if (call(conn, priv, 0, REMOTE_PROC_CONNECT_CLOSE_CALLBACK_UNREGISTER,
+ (xdrproc_t) xdr_void, (char *) NULL,
+ (xdrproc_t) xdr_void, (char *) NULL) == -1) {
+ goto cleanup;
+ }
virConnectCloseCallbackUnregister(priv->closeCallback);
- return 0;
+
+ ret = 0;
+ cleanup:
+ remoteDriverUnlock(priv);
+ return ret;
}
/* get_nonnull_domain and get_nonnull_network turn an on-wire
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 9f1be6b..3d54a69 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3063,6 +3063,10 @@ struct remote_domain_event_callback_device_added_msg {
remote_nonnull_string devAlias;
};
+struct remote_connect_event_connection_closed_msg {
+ int reason;
+};
+
struct remote_connect_get_cpu_model_names_args {
remote_nonnull_string arch;
int need_results;
@@ -5696,5 +5700,23 @@ enum remote_procedure {
* @generate:both
* @acl: domain:set_password
*/
- REMOTE_PROC_DOMAIN_SET_USER_PASSWORD = 357
+ REMOTE_PROC_DOMAIN_SET_USER_PASSWORD = 357,
+
+ /**
+ * @generate: none
+ * @acl: none
+ */
+ REMOTE_PROC_CONNECT_CLOSE_CALLBACK_REGISTER = 358,
+
+ /**
+ * @generate: none
+ * @acl: none
+ */
+ REMOTE_PROC_CONNECT_CLOSE_CALLBACK_UNREGISTER = 359,
+
+ /**
+ * @generate: none
+ * @acl: none
+ */
+ REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED = 360
};
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 48c3bd8..7a8e1c4 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -2502,6 +2502,9 @@ struct remote_domain_event_callback_device_added_msg {
remote_nonnull_domain dom;
remote_nonnull_string devAlias;
};
+struct remote_connect_event_connection_closed_msg {
+ int reason;
+};
struct remote_connect_get_cpu_model_names_args {
remote_nonnull_string arch;
int need_results;
@@ -3042,4 +3045,7 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_ADD_IOTHREAD = 355,
REMOTE_PROC_DOMAIN_DEL_IOTHREAD = 356,
REMOTE_PROC_DOMAIN_SET_USER_PASSWORD = 357,
+ REMOTE_PROC_CONNECT_CLOSE_CALLBACK_REGISTER = 358,
+ REMOTE_PROC_CONNECT_CLOSE_CALLBACK_UNREGISTER = 359,
+ REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED = 360,
};
--
1.7.1