From 0bf518cd3daad526a16468e82c1d6c715535e9ba Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Wed, 5 Oct 2011 09:05:13 +0200 Subject: server: set & test channel capabilities in red_channel The code for setting and testing channel capabilities was unnecessarily duplicated. Now it is in red_channel. RedsChannel was dropped from Reds; It was used only for holding the channels common capabilities, which are now held in RedChannel. --- 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 24fc6211..c8b42e3e 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 43c0f3f2..49028b3f 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 713bcd09..2ae05e8b 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 8993cc37..51415cbf 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 2ebb6b63..d044253a 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 6c36fecb..1e8267e8 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 6756af97..4337d16b 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -9449,7 +9449,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 65c98aef..31e255f4 100644 --- a/server/reds.c +++ b/server/reds.c @@ -192,14 +192,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; @@ -217,7 +209,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; @@ -302,7 +294,6 @@ struct ChannelSecurityOptions { ChannelSecurityOptions *next; }; -static void reds_dispose_channel(RedsChannel *channel); static ChannelSecurityOptions *channels_security = NULL; static int default_channel_security = @@ -515,42 +506,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) @@ -987,11 +968,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; } } @@ -1000,21 +981,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); @@ -1388,46 +1368,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; @@ -1441,13 +1397,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); @@ -1473,17 +1432,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; } @@ -1542,6 +1498,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(); @@ -1576,10 +1534,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++; @@ -1645,7 +1599,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; @@ -1687,12 +1641,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); } @@ -2459,8 +2413,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) { @@ -3521,6 +3475,7 @@ static int do_spice_init(SpiceCoreInterface *core_interface) ring_init(&reds->clients); reds->num_clients = 0; main_dispatcher_init(core); + ring_init(&reds->channels); if (!(reds->mig_timer = core->timer_add(migrate_timout, NULL))) { red_error("migration timer create failed"); @@ -3577,7 +3532,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 056caa62..f9cafdfa 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 98f3cd12..048da349 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 9ccc0d17..85809840 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; } -- cgit