summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYonit Halperin <yhalperi@redhat.com>2012-05-20 13:23:19 +0300
committerYonit Halperin <yhalperi@redhat.com>2012-05-21 09:08:42 +0300
commit1b9162b5cfe4043df851e8ecaa503b8261ba5868 (patch)
treeab0794a92a94da3e77aa7f8ba4cf55abaffd595f
parent720d316153d1160ba6114950b0e7f55c86b0ac1c (diff)
server/red_channel: prevent creating more than one channel client with the same type+id
-rw-r--r--server/red_channel.c50
1 files changed, 46 insertions, 4 deletions
diff --git a/server/red_channel.c b/server/red_channel.c
index 4858bb5..a7ef934 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -40,6 +40,7 @@
static void red_channel_client_event(int fd, int event, void *data);
static void red_client_add_channel(RedClient *client, RedChannelClient *rcc);
static void red_client_remove_channel(RedChannelClient *rcc);
+static RedChannelClient *red_client_get_channel(RedClient *client, int type, int id);
static void red_channel_client_restore_main_sender(RedChannelClient *rcc);
static uint32_t full_header_get_msg_size(SpiceDataHeaderOpaque *header)
@@ -514,13 +515,27 @@ int red_channel_client_test_remote_cap(RedChannelClient *rcc, uint32_t cap)
cap);
}
+static int red_channle_client_pre_create_validate(RedChannel *channel, RedClient *client)
+{
+ if (red_client_get_channel(client, channel->type, channel->id)) {
+ spice_printerr("Error client %p: duplicate channel type %d id %d",
+ client, channel->type, channel->id);
+ return FALSE;
+ }
+ return TRUE;
+}
+
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;
+ RedChannelClient *rcc = NULL;
+ pthread_mutex_lock(&client->lock);
+ if (!red_channle_client_pre_create_validate(channel, client)) {
+ goto error;
+ }
spice_assert(stream && channel && size >= sizeof(RedChannelClient));
rcc = spice_malloc0(size);
rcc->stream = stream;
@@ -570,10 +585,12 @@ RedChannelClient *red_channel_client_create(int size, RedChannel *channel, RedCl
rcc->id = channel->clients_num;
red_channel_add_client(channel, rcc);
red_client_add_channel(client, rcc);
+ pthread_mutex_unlock(&client->lock);
return rcc;
error:
free(rcc);
reds_stream_free(stream);
+ pthread_mutex_unlock(&client->lock);
return NULL;
}
@@ -1220,9 +1237,14 @@ RedChannelClient *red_channel_client_create_dummy(int size,
int num_common_caps, uint32_t *common_caps,
int num_caps, uint32_t *caps)
{
- RedChannelClient *rcc;
+ RedChannelClient *rcc = NULL;
spice_assert(size >= sizeof(RedChannelClient));
+
+ pthread_mutex_lock(&client->lock);
+ if (!red_channle_client_pre_create_validate(channel, client)) {
+ goto error;
+ }
rcc = spice_malloc0(size);
rcc->client = client;
rcc->channel = channel;
@@ -1241,7 +1263,11 @@ RedChannelClient *red_channel_client_create_dummy(int size,
rcc->incoming.serial = 1;
red_channel_add_client(channel, rcc);
+ pthread_mutex_unlock(&client->lock);
return rcc;
+error:
+ pthread_mutex_unlock(&client->lock);
+ return NULL;
}
void red_channel_client_destroy_dummy(RedChannelClient *rcc)
@@ -1454,13 +1480,29 @@ void red_client_destroy(RedClient *client)
free(client);
}
+/* client->lock should be locked */
+static RedChannelClient *red_client_get_channel(RedClient *client, int type, int id)
+{
+ RingItem *link;
+ RedChannelClient *rcc;
+ RedChannelClient *ret = NULL;
+
+ RING_FOREACH(link, &client->channels) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, client_link);
+ if (rcc->channel->type == type && rcc->channel->id == id) {
+ ret = rcc;
+ break;
+ }
+ }
+ return ret;
+}
+
+/* client->lock should be locked */
static void red_client_add_channel(RedClient *client, RedChannelClient *rcc)
{
spice_assert(rcc && client);
- pthread_mutex_lock(&client->lock);
ring_add(&client->channels, &rcc->client_link);
client->channels_num++;
- pthread_mutex_unlock(&client->lock);
}
MainChannelClient *red_client_get_main(RedClient *client) {