[Spice-devel] [PATCH spice-server] reds: Send link replies with less chunks

Frediano Ziglio fziglio at redhat.com
Tue Mar 7 12:35:35 UTC 2017


Send header and reply together.
This potentially save up to 160 bytes on the network.
This as sending multiple chunks you can have different framing,
specifically:
- if you use TLS every chunk get encrypted separately
  (reds-stream, currently usually 29 bytes for every chunks);
- tcp settings and no delay on socket. More likely with fast
  connections or better network cards. The tcp framing is
  usually about 80 bytes;
- additional tcp acknowledge (usually 64 bytes).
So 80 + 29 + 64 = 173 bytes.

Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
---
 server/reds.c | 58 +++++++++++++++++++++++++++++++---------------------------
 1 file changed, 31 insertions(+), 27 deletions(-)

Changes since v2:
- explain the comment.

Changes since v1:
- added some comment;
- check structure alignment.


diff --git a/server/reds.c b/server/reds.c
index fc720a3..41f24bb 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1459,8 +1459,10 @@ static bool red_link_info_test_capability(const RedLinkInfo *link, uint32_t cap)
 
 static int reds_send_link_ack(RedsState *reds, RedLinkInfo *link)
 {
-    SpiceLinkHeader header;
-    SpiceLinkReply ack;
+    struct {
+        SpiceLinkHeader header;
+        SpiceLinkReply ack;
+    } msg;
     RedChannel *channel;
     const RedChannelCapabilities *channel_caps;
     BUF_MEM *bmBuf;
@@ -1468,12 +1470,14 @@ static int reds_send_link_ack(RedsState *reds, RedLinkInfo *link)
     int ret = FALSE;
     size_t hdr_size;
 
-    header.magic = SPICE_MAGIC;
-    hdr_size = sizeof(ack);
-    header.major_version = GUINT32_TO_LE(SPICE_VERSION_MAJOR);
-    header.minor_version = GUINT32_TO_LE(SPICE_VERSION_MINOR);
+    SPICE_VERIFY(sizeof(msg) == sizeof(SpiceLinkHeader) + sizeof(SpiceLinkReply));
 
-    ack.error = GUINT32_TO_LE(SPICE_LINK_ERR_OK);
+    msg.header.magic = SPICE_MAGIC;
+    hdr_size = sizeof(msg.ack);
+    msg.header.major_version = GUINT32_TO_LE(SPICE_VERSION_MAJOR);
+    msg.header.minor_version = GUINT32_TO_LE(SPICE_VERSION_MINOR);
+
+    msg.ack.error = GUINT32_TO_LE(SPICE_LINK_ERR_OK);
 
     channel = reds_find_channel(reds, link->link_mess->channel_type,
                                 link->link_mess->channel_id);
@@ -1489,12 +1493,12 @@ static int reds_send_link_ack(RedsState *reds, RedLinkInfo *link)
     reds_channel_init_auth_caps(link, channel); /* make sure common caps are set */
 
     channel_caps = red_channel_get_local_capabilities(channel);
-    ack.num_common_caps = GUINT32_TO_LE(channel_caps->num_common_caps);
-    ack.num_channel_caps = GUINT32_TO_LE(channel_caps->num_caps);
+    msg.ack.num_common_caps = GUINT32_TO_LE(channel_caps->num_common_caps);
+    msg.ack.num_channel_caps = GUINT32_TO_LE(channel_caps->num_caps);
     hdr_size += channel_caps->num_common_caps * sizeof(uint32_t);
     hdr_size += channel_caps->num_caps * sizeof(uint32_t);
-    header.size = GUINT32_TO_LE(hdr_size);
-    ack.caps_offset = GUINT32_TO_LE(sizeof(SpiceLinkReply));
+    msg.header.size = GUINT32_TO_LE(hdr_size);
+    msg.ack.caps_offset = GUINT32_TO_LE(sizeof(SpiceLinkReply));
     if (!reds->config->sasl_enabled
         || !red_link_info_test_capability(link, SPICE_COMMON_CAP_AUTH_SASL)) {
         if (!(link->tiTicketing.rsa = RSA_new())) {
@@ -1520,7 +1524,7 @@ static int reds_send_link_ack(RedsState *reds, RedLinkInfo *link)
 
         i2d_RSA_PUBKEY_bio(bio, link->tiTicketing.rsa);
         BIO_get_mem_ptr(bio, &bmBuf);
-        memcpy(ack.pub_key, bmBuf->data, sizeof(ack.pub_key));
+        memcpy(msg.ack.pub_key, bmBuf->data, sizeof(msg.ack.pub_key));
     } else {
         /* if the client sets the AUTH_SASL cap, it indicates that it
          * supports SASL, and will use it if the server supports SASL as
@@ -1532,12 +1536,10 @@ static int reds_send_link_ack(RedsState *reds, RedLinkInfo *link)
          * will fail.
          */
         spice_warning("not initialising RSA key");
-        memset(ack.pub_key, '\0', sizeof(ack.pub_key));
+        memset(msg.ack.pub_key, '\0', sizeof(msg.ack.pub_key));
     }
 
-    if (!reds_stream_write_all(link->stream, &header, sizeof(header)))
-        goto end;
-    if (!reds_stream_write_all(link->stream, &ack, sizeof(ack)))
+    if (!reds_stream_write_all(link->stream, &msg, sizeof(msg)))
         goto end;
     for (unsigned int i = 0; i < channel_caps->num_common_caps; i++) {
         guint32 cap = GUINT32_TO_LE(channel_caps->common_caps[i]);
@@ -1560,17 +1562,19 @@ end:
 
 static bool reds_send_link_error(RedLinkInfo *link, uint32_t error)
 {
-    SpiceLinkHeader header;
-    SpiceLinkReply reply;
-
-    header.magic = SPICE_MAGIC;
-    header.size = GUINT32_TO_LE(sizeof(reply));
-    header.major_version = GUINT32_TO_LE(SPICE_VERSION_MAJOR);
-    header.minor_version = GUINT32_TO_LE(SPICE_VERSION_MINOR);
-    memset(&reply, 0, sizeof(reply));
-    reply.error = GUINT32_TO_LE(error);
-    return reds_stream_write_all(link->stream, &header, sizeof(header)) && reds_stream_write_all(link->stream, &reply,
-                                                                         sizeof(reply));
+    struct {
+        SpiceLinkHeader header;
+        SpiceLinkReply reply;
+    } msg;
+    SPICE_VERIFY(sizeof(msg) == sizeof(SpiceLinkHeader) + sizeof(SpiceLinkReply));
+
+    msg.header.magic = SPICE_MAGIC;
+    msg.header.size = GUINT32_TO_LE(sizeof(msg.reply));
+    msg.header.major_version = GUINT32_TO_LE(SPICE_VERSION_MAJOR);
+    msg.header.minor_version = GUINT32_TO_LE(SPICE_VERSION_MINOR);
+    memset(&msg.reply, 0, sizeof(msg.reply));
+    msg.reply.error = GUINT32_TO_LE(error);
+    return reds_stream_write_all(link->stream, &msg, sizeof(msg));
 }
 
 static void reds_info_new_channel(RedLinkInfo *link, int connection_id)
-- 
2.9.3



More information about the Spice-devel mailing list