]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
ServerClient: Flush cached data
authorMichal Privoznik <mprivozn@redhat.com>
Tue, 1 Nov 2011 13:14:54 +0000 (14:14 +0100)
committerJiri Denemark <jdenemar@redhat.com>
Tue, 1 Nov 2011 14:58:05 +0000 (15:58 +0100)
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

index 1256f0fdd95eb071c9cf6018fef883a63ee2e9da..2f5ae8faca676f295621ce495ceab8f6a0e6be2d 100644 (file)
@@ -72,6 +72,8 @@ struct _virNetServerClient
 #if HAVE_SASL
     virNetSASLSessionPtr sasl;
 #endif
+    int sockTimer; /* Timer to be fired upon cached data,
+                    * so we jump out from poll() immediately */
 
     /* Count of messages in the 'tx' queue,
      * and the server worker pool 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)
 {
@@ -204,6 +207,9 @@ static void virNetServerClientUpdateEvent(virNetServerClientPtr client)
     mode = virNetServerClientCalculateHandleMode(client);
 
     virNetSocketUpdateIOCallback(client->sock, mode);
+
+    if (client->rx && virNetSocketHasCachedData(client->sock))
+        virEventUpdateTimeout(client->sockTimer, 0);
 }
 
 
@@ -293,6 +299,19 @@ virNetServerClientCheckAccess(virNetServerClientPtr client)
     return 0;
 }
 
+static void virNetServerClientSockTimerFunc(int timer,
+                                            void *opaque)
+{
+    virNetServerClientPtr client = opaque;
+    virNetServerClientLock(client);
+    virEventUpdateTimeout(timer, -1);
+    /* Although client->rx != NULL when this timer is enabled, it might have
+     * changed since the client was unlocked in the meantime. */
+    if (client->rx)
+        virNetServerClientDispatchRead(client);
+    virNetServerClientUnlock(client);
+}
+
 
 virNetServerClientPtr virNetServerClientNew(virNetSocketPtr sock,
                                             int auth,
@@ -319,6 +338,11 @@ virNetServerClientPtr virNetServerClientNew(virNetSocketPtr sock,
     client->tlsCtxt = tls;
     client->nrequests_max = nrequests_max;
 
+    client->sockTimer = virEventAddTimeout(-1, virNetServerClientSockTimerFunc,
+                                           client, NULL);
+    if (client->sockTimer < 0)
+        goto error;
+
     if (tls)
         virNetTLSContextRef(tls);
 
@@ -557,6 +581,8 @@ void virNetServerClientFree(virNetServerClientPtr client)
 #if HAVE_SASL
     virNetSASLSessionFree(client->sasl);
 #endif
+    if (client->sockTimer > 0)
+        virEventRemoveTimeout(client->sockTimer);
     virNetTLSSessionFree(client->tls);
     virNetTLSContextFree(client->tlsCtxt);
     virNetSocketFree(client->sock);
@@ -990,7 +1016,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);
         }
     }