[Spice-devel] [PATCH spice-gtk v2 3/4] Add support for SPICE_COMMON_CAP_MINI_HEADER

Yonit Halperin yhalperi at redhat.com
Tue Jan 10 12:54:36 PST 2012


Don't send/receive serial and sub_list when the server supports the
above cap.
---
 gtk/channel-base.c       |   12 ++-
 gtk/spice-channel-priv.h |   14 +++-
 gtk/spice-channel.c      |  191 +++++++++++++++++++++++++++++++++++++--------
 3 files changed, 176 insertions(+), 41 deletions(-)

diff --git a/gtk/channel-base.c b/gtk/channel-base.c
index 54232ef..e41b1f5 100644
--- a/gtk/channel-base.c
+++ b/gtk/channel-base.c
@@ -119,7 +119,8 @@ void spice_channel_handle_wait_for_channels(SpiceChannel *channel, SpiceMsgIn *i
     SpiceMsgWaitForChannels *wfc = spice_msg_in_parsed(in);
     int i;
 
-    g_return_if_fail(in->header.size >= sizeof(*wfc) + wfc->wait_count * sizeof(wfc->wait_list[0]));
+    g_return_if_fail(spice_header_get_msg_size(in->header, channel->priv->use_mini_header) >=
+                     sizeof(*wfc) + wfc->wait_count * sizeof(wfc->wait_list[0]));
 
     for (i = 0; i < wfc->wait_count; ++i) {
         WaitForChannelData data = {
@@ -167,8 +168,10 @@ void spice_channel_handle_migrate(SpiceChannel *channel, SpiceMsgIn *in)
         spice_channel_recv_msg(channel, get_msg_handler, &data);
         if (!data) {
             g_warning("expected SPICE_MSG_MIGRATE_DATA, got empty message");
-        } else if (data->header.type != SPICE_MSG_MIGRATE_DATA) {
-            g_warning("expected SPICE_MSG_MIGRATE_DATA, got %d", data->header.type);
+        } else if (spice_header_get_msg_type(data->header, c->use_mini_header) !=
+                   SPICE_MSG_MIGRATE_DATA) {
+            g_warning("expected SPICE_MSG_MIGRATE_DATA, got %d",
+                      spice_header_get_msg_type(data->header, c->use_mini_header));
         }
     }
 
@@ -176,7 +179,8 @@ void spice_channel_handle_migrate(SpiceChannel *channel, SpiceMsgIn *in)
 
     if ((mig->flags & SPICE_MIGRATE_NEED_DATA_TRANSFER) && (data != NULL)) {
         out = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_MIGRATE_DATA);
-        spice_marshaller_add(out->marshaller, data->data, data->header.size);
+        spice_marshaller_add(out->marshaller, data->data,
+                             spice_header_get_msg_size(data->header, c->use_mini_header));
         spice_msg_out_send_internal(out);
     }
 }
diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
index ea510c7..a3d1cd2 100644
--- a/gtk/spice-channel-priv.h
+++ b/gtk/spice-channel-priv.h
@@ -40,19 +40,21 @@
 
 G_BEGIN_DECLS
 
+#define MAX_SPICE_DATA_HEADER_SIZE sizeof(SpiceDataHeader)
+
 struct _SpiceMsgOut {
     int                   refcount;
     SpiceChannel          *channel;
     SpiceMessageMarshallers *marshallers;
     SpiceMarshaller       *marshaller;
-    SpiceDataHeader       *header;
+    uint8_t               *header;
     gboolean              ro_check;
 };
 
 struct _SpiceMsgIn {
     int                   refcount;
     SpiceChannel          *channel;
-    SpiceDataHeader       header;
+    uint8_t               header[MAX_SPICE_DATA_HEADER_SIZE];
     uint8_t               *data;
     int                   hpos,dpos;
     uint8_t               *parsed;
@@ -86,6 +88,10 @@ struct _SpiceChannelPrivate {
     unsigned int                sasl_decoded_offset;
 #endif
 
+    gboolean                    use_mini_header;
+    uint64_t                    out_serial;
+    uint64_t                    in_serial;
+
     /* not swapped */
     SpiceSession                *session;
     struct coroutine            coroutine;
@@ -109,7 +115,6 @@ struct _SpiceChannelPrivate {
     int                         connection_id;
     int                         channel_id;
     int                         channel_type;
-    int                         serial;
     SpiceLinkHeader             link_hdr;
     SpiceLinkMess               link_msg;
     SpiceLinkHeader             peer_hdr;
@@ -146,6 +151,9 @@ void spice_msg_out_send(SpiceMsgOut *out);
 void spice_msg_out_send_internal(SpiceMsgOut *out);
 void spice_msg_out_hexdump(SpiceMsgOut *out, unsigned char *data, int len);
 
+uint16_t spice_header_get_msg_type(uint8_t *header, gboolean is_mini_header);
+uint32_t spice_header_get_msg_size(uint8_t *header, gboolean is_mini_header);
+
 void spice_channel_up(SpiceChannel *channel);
 void spice_channel_wakeup(SpiceChannel *channel);
 
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index d0c719d..f397c22 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -98,7 +98,8 @@ static void spice_channel_init(SpiceChannel *channel)
 
     c = channel->priv = SPICE_CHANNEL_GET_PRIVATE(channel);
 
-    c->serial = 1;
+    c->out_serial = 1;
+    c->in_serial = 1;
     c->fd = -1;
     strcpy(c->name, "?");
     c->caps = g_array_new(FALSE, TRUE, sizeof(guint32));
@@ -106,6 +107,7 @@ static void spice_channel_init(SpiceChannel *channel)
     c->remote_caps = g_array_new(FALSE, TRUE, sizeof(guint32));
     c->remote_common_caps = g_array_new(FALSE, TRUE, sizeof(guint32));
     spice_channel_set_common_capability(channel, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION);
+    spice_channel_set_common_capability(channel, SPICE_COMMON_CAP_MINI_HEADER);
     g_queue_init(&c->xmit_queue);
     g_static_mutex_init(&c->xmit_queue_lock);
     c->main_thread = g_thread_self();
@@ -347,6 +349,101 @@ static void spice_channel_class_init(SpiceChannelClass *klass)
 }
 
 /* ---------------------------------------------------------------- */
+/* private header api                                               */
+
+static inline void spice_header_set_msg_type(uint8_t *header, gboolean is_mini_header,
+                                             uint16_t type)
+{
+    if (is_mini_header) {
+        ((SpiceMiniDataHeader *)header)->type = type;
+    } else {
+        ((SpiceDataHeader *)header)->type = type;
+    }
+}
+
+static inline void spice_header_set_msg_size(uint8_t *header, gboolean is_mini_header,
+                                             uint32_t size)
+{
+    if (is_mini_header) {
+        ((SpiceMiniDataHeader *)header)->size = size;
+    } else {
+        ((SpiceDataHeader *)header)->size = size;
+    }
+}
+
+G_GNUC_INTERNAL
+uint16_t spice_header_get_msg_type(uint8_t *header, gboolean is_mini_header)
+{
+    if (is_mini_header) {
+        return ((SpiceMiniDataHeader *)header)->type;
+    } else {
+        return ((SpiceDataHeader *)header)->type;
+    }
+}
+
+G_GNUC_INTERNAL
+uint32_t spice_header_get_msg_size(uint8_t *header, gboolean is_mini_header)
+{
+    if (is_mini_header) {
+        return ((SpiceMiniDataHeader *)header)->size;
+    } else {
+        return ((SpiceDataHeader *)header)->size;
+    }
+}
+
+static inline int spice_header_get_header_size(gboolean is_mini_header)
+{
+    return is_mini_header ? sizeof(SpiceMiniDataHeader) : sizeof(SpiceDataHeader);
+}
+
+static inline void spice_header_set_msg_serial(uint8_t *header, gboolean is_mini_header,
+                                               uint64_t serial)
+{
+    if (!is_mini_header) {
+        ((SpiceDataHeader *)header)->serial = serial;
+    }
+}
+
+static inline void spice_header_reset_msg_sub_list(uint8_t *header, gboolean is_mini_header)
+{
+    if (!is_mini_header) {
+        ((SpiceDataHeader *)header)->sub_list = 0;
+    }
+}
+
+static inline uint64_t spice_header_get_in_msg_serial(SpiceMsgIn *in)
+{
+    SpiceChannelPrivate *c = in->channel->priv;
+    uint8_t *header = in->header;
+
+    if (c->use_mini_header) {
+        return c->in_serial;
+    } else {
+        return ((SpiceDataHeader *)header)->serial;
+    }
+}
+
+static inline uint64_t spice_header_get_out_msg_serial(SpiceMsgOut *out)
+{
+    SpiceChannelPrivate *c = out->channel->priv;
+
+    if (c->use_mini_header) {
+        return c->out_serial;
+    } else {
+        return ((SpiceDataHeader *)out->header)->serial;
+    }
+}
+
+static inline uint32_t spice_header_get_msg_sub_list(uint8_t *header, gboolean is_mini_header)
+{
+    if (is_mini_header) {
+        return 0;
+    } else {
+        return ((SpiceDataHeader *)header)->sub_list;
+    }
+}
+
+/* ---------------------------------------------------------------- */
 /* private msg api                                                  */
 
 G_GNUC_INTERNAL
@@ -359,6 +456,7 @@ SpiceMsgIn *spice_msg_in_new(SpiceChannel *channel)
     in = spice_new0(SpiceMsgIn, 1);
     in->refcount = 1;
     in->channel  = channel;
+
     return in;
 }
 
@@ -371,8 +469,8 @@ SpiceMsgIn *spice_msg_in_sub_new(SpiceChannel *channel, SpiceMsgIn *parent,
     g_return_val_if_fail(channel != NULL, NULL);
 
     in = spice_msg_in_new(channel);
-    in->header.type = sub->type;
-    in->header.size = sub->size;
+    spice_header_set_msg_type(in->header, channel->priv->use_mini_header, sub->type);
+    spice_header_set_msg_size(in->header, channel->priv->use_mini_header, sub->size);
     in->data = (uint8_t*)(sub+1);
     in->dpos = sub->size;
     in->parent = parent;
@@ -411,7 +509,7 @@ int spice_msg_in_type(SpiceMsgIn *in)
 {
     g_return_val_if_fail(in != NULL, -1);
 
-    return in->header.type;
+    return spice_header_get_msg_type(in->header, in->channel->priv->use_mini_header);
 }
 
 G_GNUC_INTERNAL
@@ -455,8 +553,10 @@ void spice_msg_in_hexdump(SpiceMsgIn *in)
     SpiceChannelPrivate *c = in->channel->priv;
 
     fprintf(stderr, "--\n<< hdr: %s serial %" PRIu64 " type %d size %d sub-list %d\n",
-            c->name, in->header.serial, in->header.type,
-            in->header.size, in->header.sub_list);
+            c->name, spice_header_get_in_msg_serial(in),
+            spice_header_get_msg_type(in->header, c->use_mini_header),
+            spice_header_get_msg_size(in->header, c->use_mini_header),
+            spice_header_get_msg_sub_list(in->header, c->use_mini_header));
     hexdump("<< msg", in->data, in->dpos);
 }
 
@@ -466,8 +566,11 @@ void spice_msg_out_hexdump(SpiceMsgOut *out, unsigned char *data, int len)
     SpiceChannelPrivate *c = out->channel->priv;
 
     fprintf(stderr, "--\n>> hdr: %s serial %" PRIu64 " type %d size %d sub-list %d\n",
-            c->name, out->header->serial, out->header->type,
-            out->header->size, out->header->sub_list);
+            c->name,
+            spice_header_get_out_msg_serial(out),
+            spice_header_get_msg_type(out->header, c->use_mini_header),
+            spice_header_get_msg_size(out->header, c->use_mini_header),
+            spice_header_get_msg_sub_list(out->header, c->use_mini_header));
     hexdump(">> msg", data, len);
 }
 
@@ -510,12 +613,15 @@ SpiceMsgOut *spice_msg_out_new(SpiceChannel *channel, int type)
 
     out->marshallers = c->marshallers;
     out->marshaller = spice_marshaller_new();
-    out->header = (SpiceDataHeader *)
-        spice_marshaller_reserve_space(out->marshaller, sizeof(SpiceDataHeader));
-    spice_marshaller_set_base(out->marshaller, sizeof(SpiceDataHeader));
-    out->header->serial = c->serial++;
-    out->header->type = type;
-    out->header->sub_list = 0;
+
+    out->header = spice_marshaller_reserve_space(out->marshaller,
+                                                 spice_header_get_header_size(c->use_mini_header));
+    spice_marshaller_set_base(out->marshaller, spice_header_get_header_size(c->use_mini_header));
+    spice_header_set_msg_type(out->header, c->use_mini_header, type);
+    spice_header_set_msg_serial(out->header, c->use_mini_header, c->out_serial);
+    spice_header_reset_msg_sub_list(out->header, c->use_mini_header);
+
+    c->out_serial++;
     return out;
 }
 
@@ -710,6 +816,7 @@ static void spice_channel_write_msg(SpiceChannel *channel, SpiceMsgOut *out)
     uint8_t *data;
     int free_data;
     size_t len;
+    uint32_t msg_size;
 
     g_return_if_fail(channel != NULL);
     g_return_if_fail(out != NULL);
@@ -721,8 +828,9 @@ static void spice_channel_write_msg(SpiceChannel *channel, SpiceMsgOut *out)
         return;
     }
 
-    out->header->size =
-        spice_marshaller_get_total_size(out->marshaller) - sizeof(SpiceDataHeader);
+    msg_size = spice_marshaller_get_total_size(out->marshaller) -
+               spice_header_get_header_size(channel->priv->use_mini_header);
+    spice_header_set_msg_size(out->header, channel->priv->use_mini_header, msg_size);
     data = spice_marshaller_linearize(out->marshaller, 0, &len, &free_data);
     /* spice_msg_out_hexdump(out, data, len); */
     spice_channel_write(channel, data, len);
@@ -1569,7 +1677,8 @@ static void spice_channel_recv_link_msg(SpiceChannel *channel)
             goto error;
         }
     }
-
+    c->use_mini_header = spice_channel_test_common_capability(channel,
+                                                              SPICE_COMMON_CAP_MINI_HEADER);
     return;
 
 error:
@@ -1600,54 +1709,65 @@ void spice_channel_recv_msg(SpiceChannel *channel,
 {
     SpiceChannelPrivate *c = channel->priv;
     SpiceMsgIn *in;
+    int header_size;
+    int msg_size;
+    int msg_type;
+    int sub_list_offset = 0;
     int rc;
 
     if (!c->msg_in) {
         c->msg_in = spice_msg_in_new(channel);
     }
     in = c->msg_in;
+    header_size = spice_header_get_header_size(c->use_mini_header);
 
     /* receive message */
-    if (in->hpos < sizeof(in->header)) {
-        rc = spice_channel_read(channel, (uint8_t*)&in->header + in->hpos,
-                                sizeof(in->header) - in->hpos);
+    if (in->hpos < header_size) {
+        rc = spice_channel_read(channel, in->header + in->hpos,
+                                header_size - in->hpos);
         if (rc < 0) {
             g_critical("recv hdr: %s", strerror(errno));
             return;
         }
         in->hpos += rc;
-        if (in->hpos < sizeof(in->header))
+        if (in->hpos < header_size)
             return;
-        in->data = spice_malloc(in->header.size);
+        in->data = spice_malloc(spice_header_get_msg_size(in->header, c->use_mini_header));
     }
-    if (in->dpos < in->header.size) {
+    msg_size = spice_header_get_msg_size(in->header, c->use_mini_header);
+    if (in->dpos < msg_size) {
         rc = spice_channel_read(channel, in->data + in->dpos,
-                                in->header.size - in->dpos);
+                                msg_size - in->dpos);
         if (rc < 0) {
             g_critical("recv msg: %s", strerror(errno));
             return;
         }
         in->dpos += rc;
-        if (in->dpos < in->header.size)
+        if (in->dpos < msg_size)
             return;
     }
 
-    if (in->header.type == SPICE_MSG_LIST || in->header.sub_list) {
+    msg_type = spice_header_get_msg_type(in->header, c->use_mini_header);
+    sub_list_offset = spice_header_get_msg_sub_list(in->header, c->use_mini_header);
+
+    if (msg_type == SPICE_MSG_LIST || sub_list_offset) {
         SpiceSubMessageList *sub_list;
         SpiceSubMessage *sub;
         SpiceMsgIn *sub_in;
         int i;
 
-        sub_list = (SpiceSubMessageList *)(in->data + in->header.sub_list);
+        sub_list = (SpiceSubMessageList *)(in->data + sub_list_offset);
         for (i = 0; i < sub_list->size; i++) {
             sub = (SpiceSubMessage *)(in->data + sub_list->sub_messages[i]);
             sub_in = spice_msg_in_sub_new(channel, in, sub);
             sub_in->parsed = c->parser(sub_in->data, sub_in->data + sub_in->dpos,
-                                       sub_in->header.type, c->peer_hdr.minor_version,
+                                       spice_header_get_msg_type(sub_in->header,
+                                                                 c->use_mini_header),
+                                       c->peer_hdr.minor_version,
                                        &sub_in->psize, &sub_in->pfree);
             if (sub_in->parsed == NULL) {
                 g_critical("failed to parse sub-message: %s type %d",
-                           c->name, sub_in->header.type);
+                           c->name, spice_header_get_msg_type(sub_in->header, c->use_mini_header));
                 return;
             }
             msg_handler(channel, sub_in, data);
@@ -1665,16 +1785,16 @@ void spice_channel_recv_msg(SpiceChannel *channel,
         }
     }
 
-    if (in->header.type == SPICE_MSG_LIST) {
+    if (msg_type == SPICE_MSG_LIST) {
         goto end;
     }
 
     /* parse message */
-    in->parsed = c->parser(in->data, in->data + in->dpos, in->header.type,
+    in->parsed = c->parser(in->data, in->data + in->dpos, msg_type,
                            c->peer_hdr.minor_version, &in->psize, &in->pfree);
     if (in->parsed == NULL) {
         g_critical("failed to parse message: %s type %d",
-                   c->name, in->header.type);
+                   c->name, msg_type);
         goto end;
     }
 
@@ -1684,8 +1804,10 @@ void spice_channel_recv_msg(SpiceChannel *channel,
     msg_handler(channel, in, data);
 
 end:
-    c->last_message_serial = in->header.serial;
-
+    /* If the server uses full header, the serial is not necessarily equal
+     * to c->in_serial (the server can sometimes skip serials) */
+    c->last_message_serial = spice_header_get_in_msg_serial(in);
+    c->in_serial++;
     /* release message */
     c->msg_in = NULL;
     spice_msg_in_unref(in);
@@ -2226,6 +2348,7 @@ static void channel_reset(SpiceChannel *channel, gboolean migrating)
     g_array_set_size(c->caps, 0);
     /* Restore our default capabilities in case the channel gets re-used */
     spice_channel_set_common_capability(channel, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION);
+    spice_channel_set_common_capability(channel, SPICE_COMMON_CAP_MINI_HEADER);
 }
 
 /* system or coroutine context */
-- 
1.7.6.4



More information about the Spice-devel mailing list