summaryrefslogtreecommitdiffstats
path: root/server/reds.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/reds.c')
-rw-r--r--server/reds.c60
1 files changed, 41 insertions, 19 deletions
diff --git a/server/reds.c b/server/reds.c
index 65e32d1b..c4a05d53 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -198,6 +198,8 @@ typedef struct RedsState {
int disconnecting;
VDIPortState agent_state;
int pending_mouse_event;
+ Ring clients;
+ int num_clients;
uint32_t link_id;
Channel *main_channel_factory;
MainChannel *main_channel;
@@ -535,15 +537,6 @@ static Channel *reds_find_channel(uint32_t type, uint32_t id)
return channel;
}
-static void reds_shatdown_channels()
-{
- Channel *channel = reds->channels;
- while (channel) {
- channel->shutdown(channel);
- channel = channel->next;
- }
-}
-
static void reds_mig_cleanup()
{
if (reds->mig_inprogress) {
@@ -594,14 +587,14 @@ static int reds_main_channel_connected(void)
return !!reds->main_channel;
}
-void reds_disconnect()
+void reds_client_disconnect(RedClient *client)
{
- if (!reds_main_channel_connected() || reds->disconnecting) {
+ if (!reds_main_channel_connected() || client->disconnecting) {
return;
}
red_printf("");
- reds->disconnecting = TRUE;
+ client->disconnecting = TRUE;
reds->link_id = 0;
/* Reset write filter to start with clean state on client reconnect */
@@ -612,14 +605,26 @@ void reds_disconnect()
reds->agent_state.read_filter.result = AGENT_MSG_FILTER_DISCARD;
reds->agent_state.read_filter.discard_all = TRUE;
- reds_shatdown_channels();
- reds->main_channel_factory->shutdown(reds->main_channel_factory);
- reds->main_channel_factory->data = NULL;
- reds->main_channel = NULL;
+ ring_remove(&client->link);
+ reds->num_clients--;
+ red_client_destroy(client);
+
reds_mig_cleanup();
reds->disconnecting = FALSE;
}
+// TODO: go over all usage of reds_disconnect, most/some of it should be converted to
+// reds_client_disconnect
+static void reds_disconnect(void)
+{
+ RingItem *link, *next;
+
+ red_printf("");
+ RING_FOREACH_SAFE(link, next, &reds->clients) {
+ reds_client_disconnect(SPICE_CONTAINEROF(link, RedClient, link));
+ }
+}
+
static void reds_mig_disconnect()
{
if (reds_main_channel_connected()) {
@@ -1342,6 +1347,7 @@ void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end)
static int sync_write(RedsStream *stream, const void *in_buf, size_t n)
{
const uint8_t *buf = (uint8_t *)in_buf;
+
while (n) {
int now = reds_stream_write(stream, buf, n);
if (now <= 0) {
@@ -1441,7 +1447,6 @@ static int reds_send_link_ack(RedLinkInfo *link)
BIO_get_mem_ptr(bio, &bmBuf);
memcpy(ack.pub_key, bmBuf->data, sizeof(ack.pub_key));
-
if (!sync_write(link->stream, &header, sizeof(header)))
goto end;
if (!sync_write(link->stream, &ack, sizeof(ack)))
@@ -1499,6 +1504,7 @@ static void reds_send_link_result(RedLinkInfo *link, uint32_t error)
// actually be joined with reds_handle_other_links, become reds_handle_link
static void reds_handle_main_link(RedLinkInfo *link)
{
+ RedClient *client;
RedsStream *stream;
SpiceLinkMess *link_mess;
uint32_t *caps;
@@ -1541,13 +1547,17 @@ static void reds_handle_main_link(RedLinkInfo *link)
if (!reds->main_channel_factory) {
reds->main_channel_factory = main_channel_init();
}
- mcc = main_channel_link(reds->main_channel_factory,
+ client = red_client_new();
+ ring_add(&reds->clients, &client->link);
+ reds->num_clients++;
+ mcc = main_channel_link(reds->main_channel_factory, 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);
reds->main_channel = (MainChannel*)reds->main_channel_factory->data;
ASSERT(reds->main_channel);
free(link_mess);
+ red_client_set_main(client, mcc);
if (vdagent) {
reds->agent_state.read_filter.discard_all = FALSE;
@@ -1603,11 +1613,21 @@ static void openssl_init(RedLinkInfo *link)
static void reds_handle_other_links(RedLinkInfo *link)
{
Channel *channel;
+ RedClient *client = NULL;
RedsStream *stream;
SpiceLinkMess *link_mess;
uint32_t *caps;
link_mess = link->link_mess;
+ if (reds->num_clients == 1) {
+ client = SPICE_CONTAINEROF(ring_get_head(&reds->clients), RedClient, link);
+ }
+
+ if (!client) {
+ reds_send_link_result(link, SPICE_LINK_ERR_BAD_CONNECTION_ID);
+ reds_link_free(link);
+ return;
+ }
if (!reds->link_id || reds->link_id != link_mess->connection_id) {
reds_send_link_result(link, SPICE_LINK_ERR_BAD_CONNECTION_ID);
@@ -1635,7 +1655,7 @@ 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->link(channel, stream, reds->mig_target, link_mess->num_common_caps,
+ channel->link(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);
@@ -3463,6 +3483,8 @@ static int do_spice_init(SpiceCoreInterface *core_interface)
reds->listen_socket = -1;
reds->secure_listen_socket = -1;
init_vd_agent_resources();
+ ring_init(&reds->clients);
+ reds->num_clients = 0;
if (!(reds->mig_timer = core->timer_add(migrate_timout, NULL))) {
red_error("migration timer create failed");