[libvirt] [PATCH] ServerClient: Flush SASL data

Michal Privoznik mprivozn at redhat.com
Tue Nov 1 13:14:54 UTC 2011


If daemon is using SASL it reads client data into a cache. This cache is
big (usually 65KB) and can thus contain 2 or more messages. However,
on socket event we can dispatch only one message. So if we read two
messages at once, the second will not be dispatched as the socket event
goes away with filling the cache.
Moreover, when dispatching the cache we need to remember to take care
of client max requests limit.
---
 src/rpc/virnetserverclient.c |   34 +++++++++++++++++++++++++++++++++-
 1 files changed, 33 insertions(+), 1 deletions(-)

diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c
index 1256f0f..69af746 100644
--- a/src/rpc/virnetserverclient.c
+++ b/src/rpc/virnetserverclient.c
@@ -71,6 +71,8 @@ struct _virNetServerClient
     virNetTLSSessionPtr tls;
 #if HAVE_SASL
     virNetSASLSessionPtr sasl;
+    int sasl_timer; /* Timer to be fired upon cached data,
+                       so we jump out from poll() immediately */
 #endif
 
     /* Count of messages in the 'tx' queue,
@@ -103,6 +105,7 @@ struct _virNetServerClient
 
 static void virNetServerClientDispatchEvent(virNetSocketPtr sock, int events, void *opaque);
 static void virNetServerClientUpdateEvent(virNetServerClientPtr client);
+static void virNetServerClientDispatchRead(virNetServerClientPtr client);
 
 static void virNetServerClientLock(virNetServerClientPtr client)
 {
@@ -191,6 +194,19 @@ static int virNetServerClientRegisterEvent(virNetServerClientPtr client)
     return 0;
 }
 
+static void virNetServerClientDispatchReadTimerFunc(int timer,
+                                                    void *opaque)
+{
+    virNetServerClientPtr client = opaque;
+    virNetServerClientLock(client);
+    virEventUpdateTimeout(timer, -1);
+    /* Even if this timer is enabled iff client->rx != NULL,
+     * but meanwhile client was unlocked, so it might have changed */
+    if (client->rx)
+        virNetServerClientDispatchRead(client);
+    virNetServerClientUnlock(client);
+}
+
 /*
  * @client: a locked client object
  */
@@ -204,6 +220,19 @@ static void virNetServerClientUpdateEvent(virNetServerClientPtr client)
     mode = virNetServerClientCalculateHandleMode(client);
 
     virNetSocketUpdateIOCallback(client->sock, mode);
+#ifdef HAVE_SASL
+    if (client->nrequests < client->nrequests_max &&
+        client->rx &&
+        virNetSocketHasCachedData(client->sock)) {
+        if (client->sasl_timer)
+            virEventUpdateTimeout(client->sasl_timer, 0);
+        else
+            client->sasl_timer = virEventAddTimeout(0,
+                                                    virNetServerClientDispatchReadTimerFunc,
+                                                    client,
+                                                    NULL);
+    }
+#endif
 }
 
 
@@ -556,6 +585,8 @@ void virNetServerClientFree(virNetServerClientPtr client)
     VIR_FREE(client->identity);
 #if HAVE_SASL
     virNetSASLSessionFree(client->sasl);
+    if (client->sasl_timer)
+        virEventRemoveTimeout(client->sasl_timer);
 #endif
     virNetTLSSessionFree(client->tls);
     virNetTLSContextFree(client->tlsCtxt);
@@ -990,7 +1021,8 @@ virNetServerClientDispatchEvent(virNetSocketPtr sock, int events, void *opaque)
         } else {
             if (events & VIR_EVENT_HANDLE_WRITABLE)
                 virNetServerClientDispatchWrite(client);
-            if (events & VIR_EVENT_HANDLE_READABLE)
+            if (events & VIR_EVENT_HANDLE_READABLE &&
+                client->rx)
                 virNetServerClientDispatchRead(client);
         }
     }
-- 
1.7.3.4




More information about the libvir-list mailing list