<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<meta name="Generator" content="Microsoft Word 12 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:SimSun;
        panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:SimSun;
        panose-1:2 1 6 0 3 1 1 1 1 1;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        text-align:justify;
        text-justify:inter-ideograph;
        font-size:10.5pt;
        font-family:"Calibri","sans-serif";}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
span.EmailStyle17
        {mso-style-type:personal-compose;
        font-family:"Calibri","sans-serif";
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;}
/* Page Definitions */
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 90.0pt 72.0pt 90.0pt;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="ZH-CN" link="blue" vlink="purple" style="text-justify-trim:punctuation">
<div class="WordSection1">
<p class="MsoNormal"><span lang="EN-US">From 6b42792cfee124a742999e698e348e99b382ba16 Mon Sep 17 00:00:00 2001<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">From: c00207022 <caoxinhua@huawei.com><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">Date: Thu, 2 Mar 2017 12:07:27 +0800<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">Subject: [PATCH] libvirt-remote:fix use-after-free when sending event message<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">[Changelog]:If there is a process with a client which registers event callbacks,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">and it calls libvirt's API which uses the same virConnectPtr in that<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">callback function. When this process exit abnormally lead to client<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">disconnect, there is a possibility that the libvirtd's main thread is use<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">virServerClient to send event just after the virServerClient been freed by job<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">thread.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">Following is backtrace:<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#0  0x00007fda223d66d8 in virClassIsDerivedFrom (klass=0xdeadbeef, parent=0x7fda24c81b40) at util/virobject.c:169<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#1  0x00007fda223d6a1e in virObjectIsClass (anyobj=anyobj@entry=0x7fd9e575b400, klass=<optimized out>) at util/virobject.c:365<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#2  0x00007fda223d6a44 in virObjectLock (anyobj=0x7fd9e575b400) at util/virobject.c:317<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#3  0x00007fda22507f71 in virNetServerClientSendMessage (client=client@entry=0x7fd9e575b400, msg=msg@entry=0x7fd9ec30de90)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">at rpc/virnetserverclient.c:1422<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#4  0x00007fda230d714d in remoteDispatchObjectEventSend (client=0x7fd9e575b400, program=0x7fda24c844e0, procnr=348,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">proc=0x7fda2310e5e0 <xdr_remote_domain_event_callback_tunable_msg>, data=0x7ffc3857fdb0) at remote.c:3803<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#5  0x00007fda230dd71b in remoteRelayDomainEventTunable (conn=<optimized out>, dom=0x7fda27cd7660, params=0x7fda27f3aae0, nparams=1,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">opaque=0x7fd9e6c99e00) at remote.c:1033<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#6  0x00007fda224484cb in virDomainEventDispatchDefaultFunc (conn=0x7fda27cd0120, event=0x7fda2736ea00,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">cb=0x7fda230dd610 <remoteRelayDomainEventTunable>, cbopaque=0x7fd9e6c99e00) at conf/domain_event.c:1910<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#7  0x00007fda22446871 in virObjectEventStateDispatchCallbacks (callbacks=<optimized out>, callbacks=<optimized out>, event=0x7fda2736ea00,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">state=0x7fda24ca3960) at conf/object_event.c:722<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#8  virObjectEventStateQueueDispatch (callbacks=0x7fda24c65800, queue=0x7ffc3857fe90, state=0x7fda24ca3960) at conf/object_event.c:736<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#9  virObjectEventStateFlush (state=0x7fda24ca3960) at conf/object_event.c:814<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#10 virObjectEventTimer (timer=<optimized out>, opaque=0x7fda24ca3960) at conf/object_event.c:560<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#11 0x00007fda223ae8b9 in virEventPollDispatchTimeouts () at util/vireventpoll.c:458<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#12 virEventPollRunOnce () at util/vireventpoll.c:654<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#13 0x00007fda223ad1d2 in virEventRunDefaultImpl () at util/virevent.c:314<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#14 0x00007fda225046cd in virNetDaemonRun (dmn=0x7fda24c775c0) at rpc/virnetdaemon.c:818<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">#15 0x00007fda230d6351 in main (argc=<optimized out>, argv=<optimized out>) at libvirtd.c:1623<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">Let's clean all event callback when client close.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">Signed-off-by: Caoxinhua <caoxinhua@huawei.com><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">---<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">daemon/remote.c | 76 +++++++++++++++++++++------------------------------------<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">1 file changed, 28 insertions(+), 48 deletions(-)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">diff --git a/daemon/remote.c b/daemon/remote.c<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">index 23c9de4..fb7cd50 100644<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">--- a/daemon/remote.c<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+++ b/daemon/remote.c<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">@@ -101,6 +101,7 @@ static void make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNod<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">static void make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">static void make_nonnull_nwfilter(remote_nonnull_nwfilter *net_dst, virNWFilterPtr nwfilter_src);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">static void make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+static void remoteClientCleanEventCallbacks(struct daemonClientPrivate *priv);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> static int<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">remoteSerializeDomainDiskErrors(virDomainDiskErrorPtr errors,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">@@ -1483,24 +1484,15 @@ void remoteRelayConnectionClosedEvent(virConnectPtr conn ATTRIBUTE_UNUSED, int r<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">                                   &msg);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-/*<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">- * You must hold lock for at least the client<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">- * We don't free stuff here, merely disconnect the client's<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">- * network socket & resources.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">- * We keep the libvirt connection open until any async<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">- * jobs have finished, then clean it up elsewhere<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">- */<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-void remoteClientFreeFunc(void *data)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+static void remoteClientCleanEventCallbacks(struct daemonClientPrivate *priv)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">{<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-    struct daemonClientPrivate *priv = data;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">     /* Deregister event delivery callback */<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-    if (priv->conn) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-        virIdentityPtr sysident = virIdentityGetSystem();<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+    if (priv && priv->conn) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         size_t i;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+        virIdentityPtr sysident = virIdentityGetSystem();<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         virIdentitySetCurrent(sysident);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+        virMutexLock(&priv->lock);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         for (i = 0; i < priv->ndomainEventCallbacks; i++) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">             int callbackID = priv->domainEventCallbacks[i]->callbackID;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">             if (callbackID < 0) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">@@ -1514,6 +1506,7 @@ void remoteClientFreeFunc(void *data)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">                 VIR_WARN("unexpected domain event deregister failure");<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         VIR_FREE(priv->domainEventCallbacks);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+        priv->ndomainEventCallbacks = 0;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         for (i = 0; i < priv->nnetworkEventCallbacks; i++) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">             int callbackID = priv->networkEventCallbacks[i]->callbackID;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">@@ -1529,36 +1522,7 @@ void remoteClientFreeFunc(void *data)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">                 VIR_WARN("unexpected network event deregister failure");<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         VIR_FREE(priv->networkEventCallbacks);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-        for (i = 0; i < priv->nstorageEventCallbacks; i++) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-            int callbackID = priv->storageEventCallbacks[i]->callbackID;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-            if (callbackID < 0) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-                VIR_WARN("unexpected incomplete storage pool callback %zu", i);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-                continue;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-            }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-            VIR_DEBUG("Deregistering remote storage pool event relay %d",<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-                      callbackID);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-            priv->storageEventCallbacks[i]->callbackID = -1;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-            if (virConnectStoragePoolEventDeregisterAny(priv->conn,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-                                                        callbackID) < 0)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-                VIR_WARN("unexpected storage pool event deregister failure");<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-        }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-        VIR_FREE(priv->storageEventCallbacks);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-        for (i = 0; i < priv->nnodeDeviceEventCallbacks; i++) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-            int callbackID = priv->nodeDeviceEventCallbacks[i]->callbackID;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-            if (callbackID < 0) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-                VIR_WARN("unexpected incomplete node device callback %zu", i);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-                continue;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-            }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-            VIR_DEBUG("Deregistering remote node device event relay %d",<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-                      callbackID);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-            priv->nodeDeviceEventCallbacks[i]->callbackID = -1;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-            if (virConnectNodeDeviceEventDeregisterAny(priv->conn,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-                                                       callbackID) < 0)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-                VIR_WARN("unexpected node device event deregister failure");<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-        }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-        VIR_FREE(priv->nodeDeviceEventCallbacks);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+        priv->nnetworkEventCallbacks = 0;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         for (i = 0; i < priv->nqemuEventCallbacks; i++) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">             int callbackID = priv->qemuEventCallbacks[i]->callbackID;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">@@ -1574,31 +1538,47 @@ void remoteClientFreeFunc(void *data)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">                 VIR_WARN("unexpected qemu monitor event deregister failure");<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         VIR_FREE(priv->qemuEventCallbacks);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+        priv->nqemuEventCallbacks = 0;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         if (priv->closeRegistered) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">             if (virConnectUnregisterCloseCallback(priv->conn,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">                                                   remoteRelayConnectionClosedEvent) < 0)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">                 VIR_WARN("unexpected close callback event deregister failure");<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-        virConnectClose(priv->conn);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+        virMutexUnlock(&priv->lock);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         virIdentitySetCurrent(NULL);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">         virObjectUnref(sysident);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">     }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+}<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+/*<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+ * You must hold lock for at least the client<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+ * We don't free stuff here, merely disconnect the client's<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+ * network socket & resources.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+ * We keep the libvirt connection open until any async<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+ * jobs have finished, then clean it up elsewhere<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+ */<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+void remoteClientFreeFunc(void *data)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+{<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+    struct daemonClientPrivate *priv = data;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+    if (!priv || !priv->conn)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+        return;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+    remoteClientCleanEventCallbacks(priv);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+    virConnectClose(priv->conn);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">     VIR_FREE(priv);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">static void remoteClientCloseFunc(virNetServerClientPtr client)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">{<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">     struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">     daemonRemoveAllClientStreams(priv->streams);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">+    remoteClientCleanEventCallbacks(priv);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">void *remoteClientInitHook(virNetServerClientPtr client,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">                            void *opaque ATTRIBUTE_UNUSED)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">{<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">-- <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">1.8.3.1<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
</div>
</body>
</html>