[Spice-devel] [PATCH migration 01/19] server: set & test channel capabilities in red_channel

Yonit Halperin yhalperi at redhat.com
Wed Oct 12 03:38:51 PDT 2011


The code for setting and testing channel capabilities was
unnecessarily duplicated. Now it is in red_channel.

Signed-off-by: Yonit Halperin <yhalperi at redhat.com>
---
 server/inputs_channel.c    |    4 +-
 server/main_channel.c      |   27 ++++----
 server/main_channel.h      |   20 ++++--
 server/red_channel.c       |   94 ++++++++++++++++++++++++---
 server/red_channel.h       |   33 ++++++++--
 server/red_tunnel_worker.c |    3 +-
 server/red_worker.c        |    3 +-
 server/reds.c              |  149 +++++++++++++++----------------------------
 server/smartcard.c         |    4 +-
 server/snd_worker.c        |   66 +++++++------------
 server/spicevmc.c          |    4 +-
 11 files changed, 226 insertions(+), 181 deletions(-)

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index 24fc621..c8b42e3 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -496,7 +496,9 @@ static void inputs_connect(RedChannel *channel, RedClient *client,
     icc = (InputsChannelClient*)red_channel_client_create(sizeof(InputsChannelClient),
                                                           channel,
                                                           client,
-                                                          stream);
+                                                          stream,
+                                                          num_common_caps, common_caps,
+                                                          num_caps, caps);
     icc->motion_count = 0;
     inputs_pipe_add_init(&icc->base);
 }
diff --git a/server/main_channel.c b/server/main_channel.c
index 43c0f3f..49028b3 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -39,17 +39,13 @@
 #include "server/demarshallers.h"
 #include "common/ring.h"
 #include "common/messages.h"
-#include "reds.h"
 #include "main_channel.h"
+#include "reds.h"
 #include "red_channel.h"
 #include "generated_marshallers.h"
 
 #define ZERO_BUF_SIZE 4096
 
-// approximate max receive message size for main channel
-#define RECEIVE_BUF_SIZE \
-    (4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
-
 #define REDS_MAX_SEND_IOVEC 100
 
 #define NET_TEST_WARMUP_BYTES 0
@@ -143,11 +139,6 @@ struct MainChannelClient {
 #endif
 };
 
-struct MainChannel {
-    RedChannel base;
-    uint8_t recv_buf[RECEIVE_BUF_SIZE];
-};
-
 enum NetTestStage {
     NET_TEST_STAGE_INVALID,
     NET_TEST_STAGE_WARMUP,
@@ -911,12 +902,18 @@ uint32_t main_channel_client_get_link_id(MainChannelClient *mcc)
     return mcc->connection_id;
 }
 
-MainChannelClient *main_channel_client_create(MainChannel *main_chan, RedClient *client,
-                                              RedsStream *stream, uint32_t connection_id)
+static MainChannelClient *main_channel_client_create(MainChannel *main_chan, RedClient *client,
+                                                     RedsStream *stream, uint32_t connection_id,
+                                                     int num_common_caps, uint32_t *common_caps,
+                                                     int num_caps, uint32_t *caps)
 {
     MainChannelClient *mcc = (MainChannelClient*)red_channel_client_create(sizeof(MainChannelClient),
                                                                            &main_chan->base,
-                                                                           client, stream);
+                                                                           client, stream,
+                                                                           num_common_caps,
+                                                                           common_caps,
+                                                                           num_caps,
+                                                                           caps);
 
     mcc->connection_id = connection_id;
     mcc->bitrate_per_sec = ~0;
@@ -942,7 +939,9 @@ MainChannelClient *main_channel_link(MainChannel *channel, RedClient *client,
     // into usage somewhere (not an issue until we return migration to it's
     // former glory)
     red_printf("add main channel client");
-    mcc = main_channel_client_create(channel, client, stream, connection_id);
+    mcc = main_channel_client_create(channel, client, stream, connection_id,
+                                     num_common_caps, common_caps,
+                                     num_caps, caps);
     return mcc;
 }
 
diff --git a/server/main_channel.h b/server/main_channel.h
index 713bcd0..2ae05e8 100644
--- a/server/main_channel.h
+++ b/server/main_channel.h
@@ -45,7 +45,20 @@ struct MainMigrateData {
     uint32_t write_queue_size;
 };
 
-typedef struct MainChannel MainChannel;
+// TODO: Defines used to calculate receive buffer size, and also by reds.c
+// other options: is to make a reds_main_consts.h, to duplicate defines.
+#define REDS_AGENT_WINDOW_SIZE 10
+#define REDS_NUM_INTERNAL_AGENT_MESSAGES 1
+
+// approximate max receive message size for main channel
+#define RECEIVE_BUF_SIZE \
+    (4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
+
+typedef struct MainChannel {
+    RedChannel base;
+    uint8_t recv_buf[RECEIVE_BUF_SIZE];
+} MainChannel;
+
 
 MainChannel *main_channel_init(void);
 RedClient *main_channel_get_client_by_link_id(MainChannel *main_chan, uint32_t link_id);
@@ -82,9 +95,4 @@ int main_channel_client_is_low_bandwidth(MainChannelClient *mcc);
 uint64_t main_channel_client_get_bitrate_per_sec(MainChannelClient *mcc);
 int main_channel_is_connected(MainChannel *main_chan);
 
-// TODO: Defines used to calculate receive buffer size, and also by reds.c
-// other options: is to make a reds_main_consts.h, to duplicate defines.
-#define REDS_AGENT_WINDOW_SIZE 10
-#define REDS_NUM_INTERNAL_AGENT_MESSAGES 1
-
 #endif
diff --git a/server/red_channel.c b/server/red_channel.c
index 8993cc3..51415cb 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -358,11 +358,43 @@ static void red_channel_add_client(RedChannel *channel, RedChannelClient *rcc)
     channel->clients_num++;
 }
 
-RedChannelClient *red_channel_client_create(
-    int size,
-    RedChannel *channel,
-    RedClient  *client,
-    RedsStream *stream)
+static void red_channel_client_set_remote_caps(RedChannelClient* rcc,
+                                               int num_common_caps, uint32_t *common_caps,
+                                               int num_caps, uint32_t *caps)
+{
+    rcc->remote_caps.num_common_caps = num_common_caps;
+    rcc->remote_caps.common_caps = spice_memdup(common_caps, num_common_caps * sizeof(uint32_t));
+
+    rcc->remote_caps.num_caps = num_caps;
+    rcc->remote_caps.caps = spice_memdup(caps, num_caps * sizeof(uint32_t));
+}
+
+static void red_channel_client_destroy_remote_caps(RedChannelClient* rcc)
+{
+    rcc->remote_caps.num_common_caps = 0;
+    free(rcc->remote_caps.common_caps);
+    rcc->remote_caps.num_caps = 0;
+    free(rcc->remote_caps.caps);
+}
+
+int red_channel_client_test_remote_common_cap(RedChannelClient *rcc, uint32_t cap)
+{
+    return test_capabilty(rcc->remote_caps.common_caps,
+                          rcc->remote_caps.num_common_caps,
+                          cap);
+}
+
+int red_channel_client_test_remote_cap(RedChannelClient *rcc, uint32_t cap)
+{
+    return test_capabilty(rcc->remote_caps.caps,
+                          rcc->remote_caps.num_caps,
+                          cap);
+}
+
+RedChannelClient *red_channel_client_create(int size, RedChannel *channel, RedClient  *client,
+                                            RedsStream *stream,
+                                            int num_common_caps, uint32_t *common_caps,
+                                            int num_caps, uint32_t *caps)
 {
     RedChannelClient *rcc;
 
@@ -384,6 +416,9 @@ RedChannelClient *red_channel_client_create(
     rcc->outgoing.cb = &channel->outgoing_cb;
     rcc->outgoing.pos = 0;
     rcc->outgoing.size = 0;
+
+    red_channel_client_set_remote_caps(rcc, num_common_caps, common_caps, num_caps, caps);
+
     if (!channel->channel_cbs.config_socket(rcc)) {
         goto error;
     }
@@ -564,10 +599,36 @@ void red_channel_register_client_cbs(RedChannel *channel, ClientCbs *client_cbs)
     }
 }
 
-void red_channel_set_caps(RedChannel *channel, int num_caps, uint32_t *caps)
+int test_capabilty(uint32_t *caps, int num_caps, uint32_t cap)
 {
-    channel->num_caps = num_caps;
-    channel->caps = caps;
+    uint32_t index = cap / 32;
+    if (num_caps < index + 1) {
+        return FALSE;
+    }
+
+    return (caps[index] & (1 << (cap % 32))) != 0;
+}
+
+static void add_capability(uint32_t **caps, int *num_caps, uint32_t cap)
+{
+    int nbefore, n;
+
+    nbefore = *num_caps;
+    n = cap / 32;
+    *num_caps = MAX(*num_caps, n + 1);
+    *caps = spice_renew(uint32_t, *caps, *num_caps);
+    memset(*caps + nbefore, 0, (*num_caps - nbefore) * sizeof(uint32_t));
+    (*caps)[n] |= (1 << (cap % 32));
+}
+
+void red_channel_set_common_cap(RedChannel *channel, uint32_t cap)
+{
+    add_capability(&channel->local_caps.common_caps, &channel->local_caps.num_common_caps, cap);
+}
+
+void red_channel_set_cap(RedChannel *channel, uint32_t cap)
+{
+    add_capability(&channel->local_caps.caps, &channel->local_caps.num_caps, cap);
 }
 
 void red_channel_set_data(RedChannel *channel, void *data)
@@ -585,6 +646,7 @@ void red_channel_client_destroy(RedChannelClient *rcc)
     if (rcc->send_data.marshaller) {
         spice_marshaller_destroy(rcc->send_data.marshaller);
     }
+    red_channel_client_destroy_remote_caps(rcc);
     free(rcc);
 }
 
@@ -600,9 +662,15 @@ void red_channel_destroy(RedChannel *channel)
         red_channel_client_destroy(
             SPICE_CONTAINEROF(link, RedChannelClient, channel_link));
     }
-    if (channel->caps) {
-        free(channel->caps);
+
+    if (channel->local_caps.num_common_caps) {
+        free(channel->local_caps.common_caps);
+    }
+
+    if (channel->local_caps.num_caps) {
+        free(channel->local_caps.caps);
     }
+
     free(channel);
 }
 
@@ -979,7 +1047,9 @@ void red_channel_disconnect(RedChannel *channel)
 
 RedChannelClient *red_channel_client_create_dummy(int size,
                                                   RedChannel *channel,
-                                                  RedClient  *client)
+                                                  RedClient  *client,
+                                                  int num_common_caps, uint32_t *common_caps,
+                                                  int num_caps, uint32_t *caps)
 {
     RedChannelClient *rcc;
 
@@ -987,6 +1057,7 @@ RedChannelClient *red_channel_client_create_dummy(int size,
     rcc = spice_malloc0(size);
     rcc->client = client;
     rcc->channel = channel;
+    red_channel_client_set_remote_caps(rcc, num_common_caps, common_caps, num_caps, caps);
     red_channel_add_client(channel, rcc);
     return rcc;
 }
@@ -994,6 +1065,7 @@ RedChannelClient *red_channel_client_create_dummy(int size,
 void red_channel_client_destroy_dummy(RedChannelClient *rcc)
 {
     red_channel_remove_client(rcc);
+    red_channel_client_destroy_remote_caps(rcc);
     free(rcc);
 }
 
diff --git a/server/red_channel.h b/server/red_channel.h
index 2ebb6b6..d044253 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -143,7 +143,7 @@ typedef uint64_t (*channel_handle_migrate_data_get_serial_proc)(RedChannelClient
 
 
 typedef void (*channel_client_connect_proc)(RedChannel *channel, RedClient *client, RedsStream *stream,
-                                            int migration, int num_common_caps, uint32_t *common_caps,
+                                            int migration, int num_common_cap, uint32_t *common_caps,
                                             int num_caps, uint32_t *caps);
 typedef void (*channel_client_disconnect_proc)(RedChannelClient *base);
 typedef void (*channel_client_migrate_proc)(RedChannelClient *base);
@@ -178,6 +178,15 @@ typedef struct {
     channel_client_migrate_proc migrate;
 } ClientCbs;
 
+typedef struct RedChannelCapabilities {
+    int num_common_caps;
+    uint32_t *common_caps;
+    int num_caps;
+    uint32_t *caps;
+} RedChannelCapabilities;
+
+int test_capabilty(uint32_t *caps, int num_caps, uint32_t cap);
+
 struct RedChannelClient {
     RingItem channel_link;
     RingItem client_link;
@@ -206,12 +215,16 @@ struct RedChannelClient {
     int id; // debugging purposes
     Ring pipe;
     uint32_t pipe_size;
+
+    RedChannelCapabilities remote_caps;
 };
 
 struct RedChannel {
     uint32_t type;
     uint32_t id;
 
+    RingItem link; // channels link for reds
+
     SpiceCoreInterface *core;
     int migrate;
     int handle_acks;
@@ -232,8 +245,7 @@ struct RedChannel {
     ChannelCbs channel_cbs;
     ClientCbs client_cbs;
 
-    int num_caps;
-    uint32_t *caps;
+    RedChannelCapabilities local_caps;
 
     void *data;
 
@@ -265,19 +277,23 @@ RedChannel *red_channel_create_parser(int size,
 
 void red_channel_register_client_cbs(RedChannel *channel, ClientCbs *client_cbs);
 // caps are freed when the channel is destroyed
-void red_channel_set_caps(RedChannel *channel, int num_caps, uint32_t *caps);
+void red_channel_set_common_cap(RedChannel *channel, uint32_t cap);
+void red_channel_set_cap(RedChannel *channel, uint32_t cap);
 void red_channel_set_data(RedChannel *channel, void *data);
 
 RedChannelClient *red_channel_client_create(int size, RedChannel *channel, RedClient *client,
-                                            RedsStream *stream);
-
+                                            RedsStream *stream,
+                                            int num_common_caps, uint32_t *common_caps,
+                                            int num_caps, uint32_t *caps);
 // TODO: tmp, for channels that don't use RedChannel yet (e.g., snd channel), but
 // do use the client callbacks. So the channel clients are not connected (the channel doesn't
 // have list of them, but they do have a link to the channel, and the client has a list of them)
 RedChannel *red_channel_create_dummy(int size, uint32_t type, uint32_t id);
 RedChannelClient *red_channel_client_create_dummy(int size,
                                                   RedChannel *channel,
-                                                  RedClient  *client);
+                                                  RedClient  *client,
+                                                  int num_common_caps, uint32_t *common_caps,
+                                                  int num_caps, uint32_t *caps);
 void red_channel_client_destroy_dummy(RedChannelClient *rcc);
 
 
@@ -294,6 +310,9 @@ int red_channel_client_is_connected(RedChannelClient *rcc);
 void red_channel_client_destroy(RedChannelClient *rcc);
 void red_channel_destroy(RedChannel *channel);
 
+int red_channel_client_test_remote_common_cap(RedChannelClient *rcc, uint32_t cap);
+int red_channel_client_test_remote_cap(RedChannelClient *rcc, uint32_t cap);
+
 /* shutdown is the only safe thing to do out of the client/channel
  * thread. It will not touch the rings, just shutdown the socket.
  * It should be followed by some way to gurantee a disconnection. */
diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index 6c36fec..1e8267e 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -3445,7 +3445,8 @@ static void handle_tunnel_channel_link(RedChannel *channel, RedClient *client,
     }
 
     tcc = (TunnelChannelClient*)red_channel_client_create(sizeof(TunnelChannelClient),
-                                                          channel, client, stream);
+                                                          channel, client, stream,
+                                                          0, NULL, 0, NULL);
 
     tcc->worker = worker;
     tcc->worker->channel_client = tcc;
diff --git a/server/red_worker.c b/server/red_worker.c
index 7af715d..0f91259 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9452,7 +9452,8 @@ static CommonChannelClient *common_channel_client_create(int size,
 {
     MainChannelClient *mcc = red_client_get_main(client);
     RedChannelClient *rcc =
-        red_channel_client_create(size, &common->base, client, stream);
+        red_channel_client_create(size, &common->base, client, stream,
+                                  0, NULL, 0, NULL);
     CommonChannelClient *common_cc = (CommonChannelClient*)rcc;
     common_cc->worker = common->worker;
 
diff --git a/server/reds.c b/server/reds.c
index 90779ff..ff609ce 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -191,14 +191,6 @@ typedef struct RedsStatValue {
 
 typedef struct RedsMigSpice RedsMigSpice;
 
-typedef struct RedsChannel {
-    struct RedsChannel *next;
-    RedChannel *base;
-
-    int num_common_caps;
-    uint32_t *common_caps;
-} RedsChannel;
-
 typedef struct RedsState {
     int listen_socket;
     int secure_listen_socket;
@@ -216,7 +208,7 @@ typedef struct RedsState {
     int mig_target;
     RedsMigSpice *mig_spice;
     int num_of_channels;
-    RedsChannel *channels;
+    Ring channels;
     int mouse_mode;
     int is_client_mouse_allowed;
     int dispatcher_allows_client_mouse;
@@ -301,7 +293,6 @@ struct ChannelSecurityOptions {
     ChannelSecurityOptions *next;
 };
 
-static void reds_dispose_channel(RedsChannel *channel);
 
 static ChannelSecurityOptions *channels_security = NULL;
 static int default_channel_security =
@@ -514,42 +505,32 @@ void reds_update_stat_value(uint32_t value)
 
 void reds_register_channel(RedChannel *channel)
 {
-    RedsChannel *reds_channel;
-
     ASSERT(reds);
-    // TODO: should channels be released upon some destructor?
-    reds_channel = spice_malloc0(sizeof(RedsChannel));
-    reds_channel->base = channel;
-    reds_channel->next = reds->channels;
-    reds->channels = reds_channel;
+    ring_add(&reds->channels, &channel->link);
     reds->num_of_channels++;
 }
 
 void reds_unregister_channel(RedChannel *channel)
 {
-    RedsChannel **now = &reds->channels;
-
-    while (*now) {
-        if ((*now)->base == channel) {
-            RedsChannel *free_channel = *now;
-            *now = free_channel->next;
-            reds_dispose_channel(free_channel);
-            free(free_channel);
-            reds->num_of_channels--;
-            return;
-        }
-        now = &(*now)->next;
+    if (ring_item_is_linked(&channel->link)) {
+        ring_remove(&channel->link);
+        reds->num_of_channels--;
+    } else {
+        red_printf("not found");
     }
-    red_printf("not found");
 }
 
-static RedsChannel *reds_find_channel(uint32_t type, uint32_t id)
+static RedChannel *reds_find_channel(uint32_t type, uint32_t id)
 {
-    RedsChannel *channel = reds->channels;
-    while (channel && !(channel->base->type == type && channel->base->id == id)) {
-        channel = channel->next;
+    RingItem *now;
+
+    RING_FOREACH(now, &reds->channels) {
+        RedChannel *channel = SPICE_CONTAINEROF(now, RedChannel, link);
+        if (channel->type == type && channel->id == id) {
+            return channel;
+        }
     }
-    return channel;
+    return NULL;
 }
 
 static void reds_mig_cleanup(void)
@@ -986,11 +967,11 @@ SPICE_GNUC_VISIBLE int spice_server_get_num_clients(SpiceServer *s)
 static int secondary_channels[] = {
     SPICE_CHANNEL_MAIN, SPICE_CHANNEL_DISPLAY, SPICE_CHANNEL_CURSOR, SPICE_CHANNEL_INPUTS};
 
-static int channel_is_secondary(RedsChannel *channel)
+static int channel_is_secondary(RedChannel *channel)
 {
     int i;
     for (i = 0 ; i < sizeof(secondary_channels)/sizeof(secondary_channels[0]); ++i) {
-        if (channel->base->type == secondary_channels[i]) {
+        if (channel->type == secondary_channels[i]) {
             return TRUE;
         }
     }
@@ -999,21 +980,20 @@ static int channel_is_secondary(RedsChannel *channel)
 
 void reds_fill_channels(SpiceMsgChannels *channels_info)
 {
-    RedsChannel *channel;
-    int i;
+    RingItem *now;
     int used_channels = 0;
 
     channels_info->num_of_channels = reds->num_of_channels;
-    channel = reds->channels;
-    for (i = 0; i < reds->num_of_channels; i++, channel = channel->next) {
-        ASSERT(channel);
+    RING_FOREACH(now, &reds->channels) {
+        RedChannel *channel = SPICE_CONTAINEROF(now, RedChannel, link);
         if (reds->num_clients > 1 && !channel_is_secondary(channel)) {
             continue;
         }
-        channels_info->channels[used_channels].type = channel->base->type;
-        channels_info->channels[used_channels].id = channel->base->id;
+        channels_info->channels[used_channels].type = channel->type;
+        channels_info->channels[used_channels].id = channel->id;
         used_channels++;
     }
+
     channels_info->num_of_channels = used_channels;
     if (used_channels != reds->num_of_channels) {
         red_printf("sent %d out of %d", used_channels, reds->num_of_channels);
@@ -1387,46 +1367,22 @@ static int sync_write(RedsStream *stream, const void *in_buf, size_t n)
     return TRUE;
 }
 
-static void reds_channel_set_common_caps(RedsChannel *channel, int cap, int active)
-{
-    int nbefore, n;
-
-    nbefore = channel->num_common_caps;
-    n = cap / 32;
-    channel->num_common_caps = MAX(channel->num_common_caps, n + 1);
-    channel->common_caps = spice_renew(uint32_t, channel->common_caps, channel->num_common_caps);
-    memset(channel->common_caps + nbefore, 0,
-           (channel->num_common_caps - nbefore) * sizeof(uint32_t));
-    if (active) {
-        channel->common_caps[n] |= (1 << cap);
-    } else {
-        channel->common_caps[n] &= ~(1 << cap);
-    }
-}
-
-static void reds_channel_init_auth_caps(RedsChannel *channel)
+static void reds_channel_init_auth_caps(RedChannel *channel)
 {
     if (sasl_enabled) {
-        reds_channel_set_common_caps(channel, SPICE_COMMON_CAP_AUTH_SASL, TRUE);
+        red_channel_set_common_cap(channel, SPICE_COMMON_CAP_AUTH_SASL);
     } else {
-        reds_channel_set_common_caps(channel, SPICE_COMMON_CAP_AUTH_SPICE, TRUE);
+        red_channel_set_common_cap(channel, SPICE_COMMON_CAP_AUTH_SPICE);
     }
-    reds_channel_set_common_caps(channel, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION, TRUE);
-}
-
-static void reds_dispose_channel(RedsChannel *channel)
-{
-    free(channel->common_caps);
-    channel->common_caps = NULL;
-    channel->num_common_caps = 0;
+    red_channel_set_common_cap(channel, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION);
 }
 
 static int reds_send_link_ack(RedLinkInfo *link)
 {
     SpiceLinkHeader header;
     SpiceLinkReply ack;
-    RedsChannel common_caps = { 0, };
-    RedsChannel *channel;
+    RedChannel *channel;
+    RedChannelCapabilities *channel_caps;
     BUF_MEM *bmBuf;
     BIO *bio;
     int ret = FALSE;
@@ -1440,13 +1396,16 @@ static int reds_send_link_ack(RedLinkInfo *link)
 
     channel = reds_find_channel(link->link_mess->channel_type, 0);
     if (!channel) {
-        channel = &common_caps;
+        ASSERT(link->link_mess->channel_type == SPICE_CHANNEL_MAIN);
+        ASSERT(reds->main_channel);
+        channel = &reds->main_channel->base;
     }
 
     reds_channel_init_auth_caps(channel); /* make sure common caps are set */
 
-    ack.num_common_caps = channel->num_common_caps;
-    ack.num_channel_caps = channel->base ? channel->base->num_caps : 0;
+    channel_caps = &channel->local_caps;
+    ack.num_common_caps = channel_caps->num_common_caps;
+    ack.num_channel_caps = channel_caps->num_caps;
     header.size += (ack.num_common_caps + ack.num_channel_caps) * sizeof(uint32_t);
     ack.caps_offset = sizeof(SpiceLinkReply);
 
@@ -1472,17 +1431,14 @@ static int reds_send_link_ack(RedLinkInfo *link)
         goto end;
     if (!sync_write(link->stream, &ack, sizeof(ack)))
         goto end;
-    if (!sync_write(link->stream, channel->common_caps, channel->num_common_caps * sizeof(uint32_t)))
+    if (!sync_write(link->stream, channel_caps->common_caps, channel_caps->num_common_caps * sizeof(uint32_t)))
+        goto end;
+    if (!sync_write(link->stream, channel_caps->caps, channel_caps->num_caps * sizeof(uint32_t)))
         goto end;
-    if (channel->base) {
-        if (!sync_write(link->stream, channel->base->caps, channel->base->num_caps * sizeof(uint32_t)))
-            goto end;
-    }
 
     ret = TRUE;
 
 end:
-    reds_dispose_channel(&common_caps);
     BIO_free(bio);
     return ret;
 }
@@ -1541,6 +1497,8 @@ static void reds_handle_main_link(RedLinkInfo *link)
     MainChannelClient *mcc;
 
     red_printf("");
+    ASSERT(reds->main_channel);
+
     link_mess = link->link_mess;
     if (!reds->allow_multiple_clients) {
         reds_disconnect();
@@ -1575,10 +1533,6 @@ static void reds_handle_main_link(RedLinkInfo *link)
     link->link_mess = NULL;
     reds_link_free(link);
     caps = (uint32_t *)((uint8_t *)link_mess + link_mess->caps_offset);
-    if (!reds->main_channel) {
-        reds->main_channel = main_channel_init();
-        ASSERT(reds->main_channel);
-    }
     client = red_client_new();
     ring_add(&reds->clients, &client->link);
     reds->num_clients++;
@@ -1644,7 +1598,7 @@ static void openssl_init(RedLinkInfo *link)
 
 static void reds_handle_other_links(RedLinkInfo *link)
 {
-    RedsChannel *channel;
+    RedChannel *channel;
     RedClient *client = NULL;
     RedsStream *stream;
     SpiceLinkMess *link_mess;
@@ -1686,12 +1640,12 @@ static void reds_handle_other_links(RedLinkInfo *link)
     link->link_mess = NULL;
     reds_link_free(link);
     caps = (uint32_t *)((uint8_t *)link_mess + link_mess->caps_offset);
-    channel->base->client_cbs.connect(channel->base, client, stream, reds->mig_target,
-                                      link_mess->num_common_caps,
-                                      link_mess->num_common_caps ? caps : NULL,
-                                      link_mess->num_channel_caps,
-                                      link_mess->num_channel_caps ?
-                                          caps + link_mess->num_common_caps : NULL);
+    channel->client_cbs.connect(channel, client, stream, reds->mig_target,
+                                link_mess->num_common_caps,
+                                link_mess->num_common_caps ? caps : NULL,
+                                link_mess->num_channel_caps,
+                                link_mess->num_channel_caps ?
+                                caps + link_mess->num_common_caps : NULL);
     free(link_mess);
 }
 
@@ -2458,8 +2412,8 @@ static void reds_handle_read_link_done(void *opaque)
         return;
     }
 
-    auth_selection = link_mess->num_common_caps > 0 &&
-        (caps[0] & (1 << SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION));;
+    auth_selection = test_capabilty(caps, link_mess->num_common_caps,
+                                    SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION);
 
     if (!reds_security_check(link)) {
         if (link->stream->ssl) {
@@ -3519,6 +3473,7 @@ static int do_spice_init(SpiceCoreInterface *core_interface)
     init_vd_agent_resources();
     ring_init(&reds->clients);
     reds->num_clients = 0;
+    ring_init(&reds->channels);
 
     if (!(reds->mig_timer = core->timer_add(migrate_timout, NULL))) {
         red_error("migration timer create failed");
@@ -3575,7 +3530,7 @@ static int do_spice_init(SpiceCoreInterface *core_interface)
     }
 #endif
 
-    reds->main_channel = NULL;
+    reds->main_channel = main_channel_init();
     inputs_init();
 
     reds->mouse_mode = SPICE_MOUSE_MODE_SERVER;
diff --git a/server/smartcard.c b/server/smartcard.c
index 056caa6..f9cafdf 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -493,7 +493,9 @@ static void smartcard_connect(RedChannel *channel, RedClient *client,
 {
     RedChannelClient *rcc;
 
-    rcc = red_channel_client_create(sizeof(RedChannelClient), channel, client, stream);
+    rcc = red_channel_client_create(sizeof(RedChannelClient), channel, client, stream,
+                                    num_common_caps, common_caps,
+                                    num_caps, caps);
     red_channel_client_ack_zero_messages_window(rcc);
 }
 
diff --git a/server/snd_worker.c b/server/snd_worker.c
index 98f3cd1..048da34 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -118,8 +118,6 @@ struct SndChannel {
     snd_channel_handle_message_proc handle_message;
     snd_channel_on_message_done_proc on_message_done;
     snd_channel_cleanup_channel_proc cleanup;
-    int num_caps;
-    uint32_t *caps;
 };
 
 typedef struct AudioFrame AudioFrame;
@@ -196,18 +194,6 @@ static uint32_t playback_compression = SPICE_AUDIO_DATA_MODE_CELT_0_5_1;
 
 static void snd_receive(void* data);
 
-static int check_cap(uint32_t *caps, int num_caps, uint32_t cap)
-{
-    uint32_t i = cap / 32;
-
-    cap = 1 << (cap % 32);
-    if (i >= num_caps) {
-        return FALSE;
-    }
-
-    return caps[i] & cap;
-}
-
 static SndChannel *snd_channel_get(SndChannel *channel)
 {
     channel->refs++;
@@ -239,7 +225,6 @@ static void snd_disconnect_channel(SndChannel *channel)
     channel->stream->watch = NULL;
     reds_stream_free(channel->stream);
     spice_marshaller_destroy(channel->send_data.marshaller);
-    free(channel->caps);
     snd_channel_put(channel);
 }
 
@@ -579,8 +564,10 @@ static int snd_playback_send_volume(PlaybackChannel *playback_channel)
     SndChannel *channel = &playback_channel->base;
     SpicePlaybackState *st = SPICE_CONTAINEROF(channel->worker, SpicePlaybackState, worker);
 
-    if (!check_cap(channel->caps, channel->num_caps, SPICE_PLAYBACK_CAP_VOLUME))
+    if (!red_channel_client_test_remote_cap(channel->channel_client,
+                                            SPICE_PLAYBACK_CAP_VOLUME)) {
         return TRUE;
+    }
 
     return snd_send_volume(channel, &st->volume, SPICE_MSG_PLAYBACK_VOLUME);
 }
@@ -603,8 +590,10 @@ static int snd_playback_send_mute(PlaybackChannel *playback_channel)
     SndChannel *channel = &playback_channel->base;
     SpicePlaybackState *st = SPICE_CONTAINEROF(channel->worker, SpicePlaybackState, worker);
 
-    if (!check_cap(channel->caps, channel->num_caps, SPICE_PLAYBACK_CAP_VOLUME))
+    if (!red_channel_client_test_remote_cap(channel->channel_client,
+                                            SPICE_PLAYBACK_CAP_VOLUME)) {
         return TRUE;
+    }
 
     return snd_send_mute(channel, &st->volume, SPICE_MSG_PLAYBACK_MUTE);
 }
@@ -695,8 +684,10 @@ static int snd_record_send_volume(RecordChannel *record_channel)
     SndChannel *channel = &record_channel->base;
     SpiceRecordState *st = SPICE_CONTAINEROF(channel->worker, SpiceRecordState, worker);
 
-    if (!check_cap(channel->caps, channel->num_caps, SPICE_RECORD_CAP_VOLUME))
+    if (!red_channel_client_test_remote_cap(channel->channel_client,
+                                            SPICE_RECORD_CAP_VOLUME)) {
         return TRUE;
+    }
 
     return snd_send_volume(channel, &st->volume, SPICE_MSG_RECORD_VOLUME);
 }
@@ -706,8 +697,10 @@ static int snd_record_send_mute(RecordChannel *record_channel)
     SndChannel *channel = &record_channel->base;
     SpiceRecordState *st = SPICE_CONTAINEROF(channel->worker, SpiceRecordState, worker);
 
-    if (!check_cap(channel->caps, channel->num_caps, SPICE_RECORD_CAP_VOLUME))
+    if (!red_channel_client_test_remote_cap(channel->channel_client,
+                                            SPICE_RECORD_CAP_VOLUME)) {
         return TRUE;
+    }
 
     return snd_send_mute(channel, &st->volume, SPICE_MSG_RECORD_MUTE);
 }
@@ -941,12 +934,12 @@ static SndChannel *__new_channel(SndWorker *worker, int size, uint32_t channel_i
     channel->handle_message = handle_message;
     channel->on_message_done = on_message_done;
     channel->cleanup = cleanup;
-    channel->num_caps = num_caps;
-    channel->caps = spice_memdup(caps, num_caps * sizeof(uint32_t));
 
     channel->channel_client = red_channel_client_create_dummy(sizeof(RedChannelClient),
                                                               worker->base_channel,
-                                                              client);
+                                                              client,
+                                                              0, NULL,
+                                                              num_caps, caps);
     return channel;
 
 error2:
@@ -1140,6 +1133,7 @@ static void snd_set_playback_peer(RedChannel *channel, RedClient *client, RedsSt
     CELTEncoder *celt_encoder;
     CELTMode *celt_mode;
     int celt_error;
+    RedChannelClient *rcc;
 
     snd_disconnect_channel(worker->connection);
 
@@ -1169,13 +1163,15 @@ static void snd_set_playback_peer(RedChannel *channel, RedClient *client, RedsSt
         goto error_2;
     }
     worker->connection = &playback_channel->base;
+    rcc = playback_channel->base.channel_client;
     snd_playback_free_frame(playback_channel, &playback_channel->frames[0]);
     snd_playback_free_frame(playback_channel, &playback_channel->frames[1]);
     snd_playback_free_frame(playback_channel, &playback_channel->frames[2]);
 
     playback_channel->celt_mode = celt_mode;
     playback_channel->celt_encoder = celt_encoder;
-    playback_channel->mode = check_cap(caps, num_caps, SPICE_PLAYBACK_CAP_CELT_0_5_1) ?
+    playback_channel->mode = red_channel_client_test_remote_cap(rcc,
+                                                                SPICE_PLAYBACK_CAP_CELT_0_5_1) ?
         playback_compression : SPICE_AUDIO_DATA_MODE_RAW;
 
     on_new_playback_channel(worker);
@@ -1431,8 +1427,6 @@ static void remove_worker(SndWorker *worker)
 void snd_attach_playback(SpicePlaybackInstance *sin)
 {
     SndWorker *playback_worker;
-    int num_caps;
-    uint32_t *caps;
     RedChannel *channel;
     ClientCbs client_cbs = {0,};
 
@@ -1449,12 +1443,8 @@ void snd_attach_playback(SpicePlaybackInstance *sin)
     client_cbs.migrate = snd_playback_migrate_channel_client;
     red_channel_register_client_cbs(channel, &client_cbs);
     red_channel_set_data(channel, playback_worker);
-
-    num_caps = 1;
-    caps = spice_new(uint32_t, 1);
-    caps[0] = (1 << SPICE_PLAYBACK_CAP_CELT_0_5_1) |
-              (1 << SPICE_PLAYBACK_CAP_VOLUME);
-    red_channel_set_caps(channel, num_caps, caps);
+    red_channel_set_cap(channel, SPICE_PLAYBACK_CAP_CELT_0_5_1);
+    red_channel_set_cap(channel, SPICE_PLAYBACK_CAP_VOLUME);
 
     playback_worker->base_channel = channel;
     add_worker(playback_worker);
@@ -1464,8 +1454,6 @@ void snd_attach_playback(SpicePlaybackInstance *sin)
 void snd_attach_record(SpiceRecordInstance *sin)
 {
     SndWorker *record_worker;
-    int num_caps;
-    uint32_t *caps;
     RedChannel *channel;
     ClientCbs client_cbs = {0,};
 
@@ -1482,12 +1470,8 @@ void snd_attach_record(SpiceRecordInstance *sin)
     client_cbs.migrate = snd_record_migrate_channel_client;
     red_channel_register_client_cbs(channel, &client_cbs);
     red_channel_set_data(channel, record_worker);
-
-    num_caps = 1;
-    caps = spice_new(uint32_t, 1);
-    caps[0] = (1 << SPICE_RECORD_CAP_CELT_0_5_1) |
-              (1 << SPICE_RECORD_CAP_VOLUME);
-    red_channel_set_caps(channel, num_caps, caps);
+    red_channel_set_cap(channel, SPICE_RECORD_CAP_CELT_0_5_1);
+    red_channel_set_cap(channel, SPICE_RECORD_CAP_VOLUME);
 
     record_worker->base_channel = channel;
     add_worker(record_worker);
@@ -1538,8 +1522,8 @@ void snd_set_playback_compression(int on)
         if (now->base_channel->type == SPICE_CHANNEL_PLAYBACK && now->connection) {
             SndChannel* sndchannel = now->connection;
             PlaybackChannel* playback = (PlaybackChannel*)now->connection;
-            if (!check_cap(sndchannel->caps, sndchannel->num_caps,
-                           SPICE_PLAYBACK_CAP_CELT_0_5_1)) {
+            if (!red_channel_client_test_remote_cap(sndchannel->channel_client,
+                                                    SPICE_PLAYBACK_CAP_CELT_0_5_1)) {
                 ASSERT(playback->mode == SPICE_AUDIO_DATA_MODE_RAW);
                 continue;
             }
diff --git a/server/spicevmc.c b/server/spicevmc.c
index 9ccc0d1..8580984 100644
--- a/server/spicevmc.c
+++ b/server/spicevmc.c
@@ -206,7 +206,9 @@ static void spicevmc_connect(RedChannel *channel, RedClient *client,
         return;
     }
 
-    rcc = red_channel_client_create(sizeof(RedChannelClient), channel, client, stream);
+    rcc = red_channel_client_create(sizeof(RedChannelClient), channel, client, stream,
+                                    num_common_caps, common_caps,
+                                    num_caps, caps);
     if (!rcc) {
         return;
     }
-- 
1.7.6.4



More information about the Spice-devel mailing list