mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2026-01-08 12:24:55 +00:00
server/red_channel (all): introduce RedChannelClient
This commit adds a RedChannelClient that now owns the stream connection, but still doesn't own the pipe. There is only a single RCC per RC right now (and RC still means RedChannel, RedClient will be introduced later). All internal api changes are in server/red_channel.h, hence the need to update all channels. red_worker.c is affected the most because it makes use of direct access to some of RedChannel still. API changes: 1. red_channel_client_create added. rec_channel_create -> (red_channel_create, red_channel_client_create) 2. two way connection: rcc->channel, channel->rcc (later channel will hold a list, and there will be a RedClient to hold the list of channels per client) 3. seperation of channel disconnect and channel_client_disconnect TODO: usbredir added untested.
This commit is contained in:
parent
75b6a305ff
commit
7e8e13593e
@ -164,9 +164,9 @@ const VDAgentMouseState *inputs_get_mouse_state(void)
|
||||
return &g_inputs_channel->mouse_state;
|
||||
}
|
||||
|
||||
static uint8_t *inputs_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header)
|
||||
static uint8_t *inputs_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header)
|
||||
{
|
||||
InputsChannel *inputs_channel = SPICE_CONTAINEROF(channel, InputsChannel, base);
|
||||
InputsChannel *inputs_channel = SPICE_CONTAINEROF(rcc->channel, InputsChannel, base);
|
||||
|
||||
if (msg_header->size > RECEIVE_BUF_SIZE) {
|
||||
red_printf("error: too large incoming message");
|
||||
@ -175,7 +175,7 @@ static uint8_t *inputs_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataH
|
||||
return inputs_channel->recv_buf;
|
||||
}
|
||||
|
||||
static void inputs_channel_release_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header,
|
||||
static void inputs_channel_release_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header,
|
||||
uint8_t *msg)
|
||||
{
|
||||
}
|
||||
@ -249,17 +249,17 @@ static void inputs_pipe_add_type(InputsChannel *channel, int type)
|
||||
red_channel_pipe_add_push(&channel->base, &pipe_item->base);
|
||||
}
|
||||
|
||||
static void inputs_channel_release_pipe_item(RedChannel *channel,
|
||||
static void inputs_channel_release_pipe_item(RedChannelClient *rcc,
|
||||
PipeItem *base, int item_pushed)
|
||||
{
|
||||
free(base);
|
||||
}
|
||||
|
||||
static void inputs_channel_send_item(RedChannel *channel, PipeItem *base)
|
||||
static void inputs_channel_send_item(RedChannelClient *rcc, PipeItem *base)
|
||||
{
|
||||
SpiceMarshaller *m = red_channel_get_marshaller(channel);
|
||||
SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
|
||||
|
||||
red_channel_init_send_data(channel, base->type, base);
|
||||
red_channel_client_init_send_data(rcc, base->type, base);
|
||||
switch (base->type) {
|
||||
case PIPE_ITEM_KEY_MODIFIERS:
|
||||
{
|
||||
@ -288,12 +288,12 @@ static void inputs_channel_send_item(RedChannel *channel, PipeItem *base)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
red_channel_begin_send_message(channel);
|
||||
red_channel_client_begin_send_message(rcc);
|
||||
}
|
||||
|
||||
static int inputs_channel_handle_parsed(RedChannel *channel, uint32_t size, uint16_t type, void *message)
|
||||
static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type, void *message)
|
||||
{
|
||||
InputsChannel *inputs_channel = (InputsChannel *)channel;
|
||||
InputsChannel *inputs_channel = (InputsChannel *)rcc->channel;
|
||||
uint8_t *buf = (uint8_t *)message;
|
||||
|
||||
ASSERT(g_inputs_channel == inputs_channel);
|
||||
@ -446,10 +446,10 @@ static void inputs_relase_keys(void)
|
||||
kbd_push_scan(keyboard, 0x38 | 0x80); //LALT
|
||||
}
|
||||
|
||||
static void inputs_channel_on_error(RedChannel *channel)
|
||||
static void inputs_channel_on_error(RedChannelClient *rcc)
|
||||
{
|
||||
inputs_relase_keys();
|
||||
reds_disconnect();
|
||||
red_channel_client_destroy(rcc);
|
||||
}
|
||||
|
||||
static void inputs_shutdown(Channel *channel)
|
||||
@ -485,11 +485,11 @@ static void inputs_pipe_add_init(InputsChannel *inputs_channel)
|
||||
red_channel_pipe_add_push(&inputs_channel->base, &item->base);
|
||||
}
|
||||
|
||||
static int inputs_channel_config_socket(RedChannel *channel)
|
||||
static int inputs_channel_config_socket(RedChannelClient *rcc)
|
||||
{
|
||||
int flags;
|
||||
int delay_val = 1;
|
||||
RedsStream *stream = red_channel_get_stream(channel);
|
||||
RedsStream *stream = red_channel_client_get_stream(rcc);
|
||||
|
||||
if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY,
|
||||
&delay_val, sizeof(delay_val)) == -1) {
|
||||
@ -505,7 +505,7 @@ static int inputs_channel_config_socket(RedChannel *channel)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void inputs_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
|
||||
static void inputs_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
|
||||
{
|
||||
}
|
||||
|
||||
@ -514,11 +514,13 @@ static void inputs_link(Channel *channel, RedsStream *stream, int migration,
|
||||
uint32_t *caps)
|
||||
{
|
||||
InputsChannel *inputs_channel;
|
||||
red_printf("");
|
||||
RedChannelClient *rcc;
|
||||
|
||||
ASSERT(channel->data == NULL);
|
||||
|
||||
red_printf("input channel create");
|
||||
g_inputs_channel = inputs_channel = (InputsChannel*)red_channel_create_parser(
|
||||
sizeof(*inputs_channel), stream, core, migration, FALSE /* handle_acks */
|
||||
sizeof(*inputs_channel), core, migration, FALSE /* handle_acks */
|
||||
,inputs_channel_config_socket
|
||||
,spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL)
|
||||
,inputs_channel_handle_parsed
|
||||
@ -533,6 +535,9 @@ static void inputs_link(Channel *channel, RedsStream *stream, int migration,
|
||||
,NULL
|
||||
,NULL);
|
||||
ASSERT(inputs_channel);
|
||||
red_printf("input channel client create");
|
||||
rcc = red_channel_client_create(sizeof(RedChannelClient), &g_inputs_channel->base, stream);
|
||||
ASSERT(rcc);
|
||||
channel->data = inputs_channel;
|
||||
inputs_pipe_add_init(inputs_channel);
|
||||
}
|
||||
|
||||
@ -421,7 +421,8 @@ static void main_channel_marshall_migrate_data_item(SpiceMarshaller *m, int seri
|
||||
data->ping_id = ping_id;
|
||||
}
|
||||
|
||||
static uint64_t main_channel_handle_migrate_data_get_serial(RedChannel *base,
|
||||
static uint64_t main_channel_handle_migrate_data_get_serial(
|
||||
RedChannelClient *rcc,
|
||||
uint32_t size, void *message)
|
||||
{
|
||||
MainMigrateData *data = message;
|
||||
@ -433,10 +434,10 @@ static uint64_t main_channel_handle_migrate_data_get_serial(RedChannel *base,
|
||||
return data->serial;
|
||||
}
|
||||
|
||||
static uint64_t main_channel_handle_migrate_data(RedChannel *base,
|
||||
static uint64_t main_channel_handle_migrate_data(RedChannelClient *rcc,
|
||||
uint32_t size, void *message)
|
||||
{
|
||||
MainChannel *main_chan = SPICE_CONTAINEROF(base, MainChannel, base);
|
||||
MainChannel *main_chan = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
|
||||
MainMigrateData *data = message;
|
||||
|
||||
if (size < sizeof(*data)) {
|
||||
@ -607,12 +608,12 @@ static void main_channel_marshall_multi_media_time(SpiceMarshaller *m,
|
||||
spice_marshall_msg_main_multi_media_time(m, &time_mes);
|
||||
}
|
||||
|
||||
static void main_channel_send_item(RedChannel *channel, PipeItem *base)
|
||||
static void main_channel_send_item(RedChannelClient *rcc, PipeItem *base)
|
||||
{
|
||||
SpiceMarshaller *m = red_channel_get_marshaller(channel);
|
||||
MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel, base);
|
||||
MainChannel *main_chan = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
|
||||
SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
|
||||
|
||||
red_channel_init_send_data(channel, base->type, base);
|
||||
red_channel_client_init_send_data(rcc, base->type, base);
|
||||
switch (base->type) {
|
||||
case SPICE_MSG_MAIN_CHANNELS_LIST:
|
||||
main_channel_marshall_channels(m);
|
||||
@ -642,7 +643,7 @@ static void main_channel_send_item(RedChannel *channel, PipeItem *base)
|
||||
break;
|
||||
case SPICE_MSG_MIGRATE_DATA:
|
||||
main_channel_marshall_migrate_data_item(m,
|
||||
red_channel_get_message_serial(&main_chan->base),
|
||||
red_channel_client_get_message_serial(rcc),
|
||||
main_chan->ping_id);
|
||||
break;
|
||||
case SPICE_MSG_MAIN_INIT:
|
||||
@ -668,18 +669,18 @@ static void main_channel_send_item(RedChannel *channel, PipeItem *base)
|
||||
main_channel_marshall_migrate_switch(m);
|
||||
break;
|
||||
};
|
||||
red_channel_begin_send_message(channel);
|
||||
red_channel_client_begin_send_message(rcc);
|
||||
}
|
||||
|
||||
static void main_channel_release_pipe_item(RedChannel *channel,
|
||||
static void main_channel_release_pipe_item(RedChannelClient *rcc,
|
||||
PipeItem *base, int item_pushed)
|
||||
{
|
||||
free(base);
|
||||
}
|
||||
|
||||
static int main_channel_handle_parsed(RedChannel *channel, uint32_t size, uint16_t type, void *message)
|
||||
static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type, void *message)
|
||||
{
|
||||
MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel, base);
|
||||
MainChannel *main_chan = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
|
||||
|
||||
switch (type) {
|
||||
case SPICE_MSGC_MAIN_AGENT_START:
|
||||
@ -770,35 +771,36 @@ static int main_channel_handle_parsed(RedChannel *channel, uint32_t size, uint16
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void main_channel_on_error(RedChannel *channel)
|
||||
static void main_channel_on_error(RedChannelClient *rcc)
|
||||
{
|
||||
reds_disconnect();
|
||||
}
|
||||
|
||||
static uint8_t *main_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header)
|
||||
static uint8_t *main_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header)
|
||||
{
|
||||
MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel, base);
|
||||
MainChannel *main_chan = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
|
||||
|
||||
return main_chan->recv_buf;
|
||||
}
|
||||
|
||||
static void main_channel_release_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header,
|
||||
static void main_channel_release_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header,
|
||||
uint8_t *msg)
|
||||
{
|
||||
}
|
||||
|
||||
static int main_channel_config_socket(RedChannel *channel)
|
||||
static int main_channel_config_socket(RedChannelClient *rcc)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void main_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
|
||||
static void main_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
|
||||
{
|
||||
}
|
||||
|
||||
static int main_channel_handle_migrate_flush_mark(RedChannel *base)
|
||||
static int main_channel_handle_migrate_flush_mark(RedChannelClient *rcc)
|
||||
{
|
||||
main_channel_push_migrate_data_item(SPICE_CONTAINEROF(base, MainChannel, base));
|
||||
main_channel_push_migrate_data_item(SPICE_CONTAINEROF(rcc->channel,
|
||||
MainChannel, base));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -807,26 +809,30 @@ static void main_channel_link(Channel *channel, RedsStream *stream, int migratio
|
||||
uint32_t *caps)
|
||||
{
|
||||
MainChannel *main_chan;
|
||||
red_printf("");
|
||||
ASSERT(channel->data == NULL);
|
||||
|
||||
main_chan = (MainChannel*)red_channel_create_parser(
|
||||
sizeof(*main_chan), stream, core, migration, FALSE /* handle_acks */
|
||||
,main_channel_config_socket
|
||||
,spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL)
|
||||
,main_channel_handle_parsed
|
||||
,main_channel_alloc_msg_rcv_buf
|
||||
,main_channel_release_msg_rcv_buf
|
||||
,main_channel_hold_pipe_item
|
||||
,main_channel_send_item
|
||||
,main_channel_release_pipe_item
|
||||
,main_channel_on_error
|
||||
,main_channel_on_error
|
||||
,main_channel_handle_migrate_flush_mark
|
||||
,main_channel_handle_migrate_data
|
||||
,main_channel_handle_migrate_data_get_serial);
|
||||
ASSERT(main_chan);
|
||||
channel->data = main_chan;
|
||||
if (channel->data == NULL) {
|
||||
red_printf("create main channel");
|
||||
channel->data = red_channel_create_parser(
|
||||
sizeof(*main_chan), core, migration, FALSE /* handle_acks */
|
||||
,main_channel_config_socket
|
||||
,spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL)
|
||||
,main_channel_handle_parsed
|
||||
,main_channel_alloc_msg_rcv_buf
|
||||
,main_channel_release_msg_rcv_buf
|
||||
,main_channel_hold_pipe_item
|
||||
,main_channel_send_item
|
||||
,main_channel_release_pipe_item
|
||||
,main_channel_on_error
|
||||
,main_channel_on_error
|
||||
,main_channel_handle_migrate_flush_mark
|
||||
,main_channel_handle_migrate_data
|
||||
,main_channel_handle_migrate_data_get_serial);
|
||||
ASSERT(channel->data);
|
||||
}
|
||||
main_chan = (MainChannel*)channel->data;
|
||||
red_printf("add main channel client");
|
||||
red_channel_client_create(sizeof(RedChannelClient), channel->data, stream);
|
||||
}
|
||||
|
||||
int main_channel_getsockname(Channel *channel, struct sockaddr *sa, socklen_t *salen)
|
||||
|
||||
@ -33,8 +33,7 @@
|
||||
#include "red_channel.h"
|
||||
#include "generated_marshallers.h"
|
||||
|
||||
static PipeItem *red_channel_pipe_get(RedChannel *channel);
|
||||
static void red_channel_event(int fd, int event, void *data);
|
||||
static void red_channel_client_event(int fd, int event, void *data);
|
||||
|
||||
/* return the number of bytes read. -1 in case of error */
|
||||
static int red_peer_receive(RedsStream *stream, uint8_t *buf, uint32_t size)
|
||||
@ -152,9 +151,14 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
|
||||
}
|
||||
}
|
||||
|
||||
void red_channel_client_receive(RedChannelClient *rcc)
|
||||
{
|
||||
red_peer_handle_incoming(rcc->stream, &rcc->incoming);
|
||||
}
|
||||
|
||||
void red_channel_receive(RedChannel *channel)
|
||||
{
|
||||
red_peer_handle_incoming(channel->stream, &channel->incoming);
|
||||
red_channel_client_receive(channel->rcc);
|
||||
}
|
||||
|
||||
static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handler)
|
||||
@ -201,124 +205,194 @@ static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handle
|
||||
}
|
||||
}
|
||||
|
||||
static void red_channel_on_output(void *opaque, int n)
|
||||
static void red_channel_client_on_output(void *opaque, int n)
|
||||
{
|
||||
RedChannel *channel = opaque;
|
||||
RedChannelClient *rcc = opaque;
|
||||
|
||||
stat_inc_counter(channel->out_bytes_counter, n);
|
||||
stat_inc_counter(rcc->channel->out_bytes_counter, n);
|
||||
}
|
||||
|
||||
void red_channel_default_peer_on_error(RedChannel *channel)
|
||||
void red_channel_client_default_peer_on_error(RedChannelClient *rcc)
|
||||
{
|
||||
channel->disconnect(channel);
|
||||
rcc->channel->disconnect(rcc);
|
||||
}
|
||||
|
||||
static void red_channel_peer_on_incoming_error(RedChannel *channel)
|
||||
static void red_channel_peer_on_incoming_error(RedChannelClient *rcc)
|
||||
{
|
||||
channel->on_incoming_error(channel);
|
||||
rcc->channel->on_incoming_error(rcc);
|
||||
}
|
||||
|
||||
static void red_channel_peer_on_outgoing_error(RedChannel *channel)
|
||||
static void red_channel_peer_on_outgoing_error(RedChannelClient *rcc)
|
||||
{
|
||||
channel->on_outgoing_error(channel);
|
||||
rcc->channel->on_outgoing_error(rcc);
|
||||
}
|
||||
|
||||
static int red_channel_peer_get_out_msg_size(void *opaque)
|
||||
static int red_channel_client_peer_get_out_msg_size(void *opaque)
|
||||
{
|
||||
RedChannel *channel = (RedChannel *)opaque;
|
||||
RedChannelClient *rcc = (RedChannelClient *)opaque;
|
||||
|
||||
return channel->send_data.size;
|
||||
return rcc->send_data.size;
|
||||
}
|
||||
|
||||
static void red_channel_peer_prepare_out_msg(void *opaque, struct iovec *vec, int *vec_size, int pos)
|
||||
static void red_channel_client_peer_prepare_out_msg(
|
||||
void *opaque, struct iovec *vec, int *vec_size, int pos)
|
||||
{
|
||||
RedChannel *channel = (RedChannel *)opaque;
|
||||
RedChannelClient *rcc = (RedChannelClient *)opaque;
|
||||
|
||||
*vec_size = spice_marshaller_fill_iovec(channel->send_data.marshaller,
|
||||
*vec_size = spice_marshaller_fill_iovec(rcc->send_data.marshaller,
|
||||
vec, MAX_SEND_VEC, pos);
|
||||
}
|
||||
|
||||
static void red_channel_peer_on_out_block(void *opaque)
|
||||
static void red_channel_client_peer_on_out_block(void *opaque)
|
||||
{
|
||||
RedChannel *channel = (RedChannel *)opaque;
|
||||
RedChannelClient *rcc = (RedChannelClient *)opaque;
|
||||
|
||||
channel->send_data.blocked = TRUE;
|
||||
channel->core->watch_update_mask(channel->stream->watch,
|
||||
rcc->send_data.blocked = TRUE;
|
||||
rcc->channel->core->watch_update_mask(rcc->stream->watch,
|
||||
SPICE_WATCH_EVENT_READ |
|
||||
SPICE_WATCH_EVENT_WRITE);
|
||||
}
|
||||
|
||||
static void red_channel_reset_send_data(RedChannel *channel)
|
||||
static void red_channel_client_reset_send_data(RedChannelClient *rcc)
|
||||
{
|
||||
spice_marshaller_reset(channel->send_data.marshaller);
|
||||
channel->send_data.header = (SpiceDataHeader *)
|
||||
spice_marshaller_reserve_space(channel->send_data.marshaller, sizeof(SpiceDataHeader));
|
||||
spice_marshaller_set_base(channel->send_data.marshaller, sizeof(SpiceDataHeader));
|
||||
channel->send_data.header->type = 0;
|
||||
channel->send_data.header->size = 0;
|
||||
channel->send_data.header->sub_list = 0;
|
||||
channel->send_data.header->serial = ++channel->send_data.serial;
|
||||
spice_marshaller_reset(rcc->send_data.marshaller);
|
||||
rcc->send_data.header = (SpiceDataHeader *)
|
||||
spice_marshaller_reserve_space(rcc->send_data.marshaller, sizeof(SpiceDataHeader));
|
||||
spice_marshaller_set_base(rcc->send_data.marshaller, sizeof(SpiceDataHeader));
|
||||
rcc->send_data.header->type = 0;
|
||||
rcc->send_data.header->size = 0;
|
||||
rcc->send_data.header->sub_list = 0;
|
||||
rcc->send_data.header->serial = ++rcc->send_data.serial;
|
||||
}
|
||||
|
||||
void red_channel_client_push_set_ack(RedChannelClient *rcc)
|
||||
{
|
||||
red_channel_pipe_add_type(rcc->channel, PIPE_ITEM_TYPE_SET_ACK);
|
||||
}
|
||||
|
||||
void red_channel_push_set_ack(RedChannel *channel)
|
||||
{
|
||||
// TODO - MC, should replace with add_type_all (or whatever I'll name it)
|
||||
red_channel_pipe_add_type(channel, PIPE_ITEM_TYPE_SET_ACK);
|
||||
}
|
||||
|
||||
static void red_channel_send_set_ack(RedChannel *channel)
|
||||
static void red_channel_client_send_set_ack(RedChannelClient *rcc)
|
||||
{
|
||||
SpiceMsgSetAck ack;
|
||||
|
||||
ASSERT(channel);
|
||||
red_channel_init_send_data(channel, SPICE_MSG_SET_ACK, NULL);
|
||||
ack.generation = ++channel->ack_data.generation;
|
||||
ack.window = channel->ack_data.client_window;
|
||||
channel->ack_data.messages_window = 0;
|
||||
ASSERT(rcc);
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_SET_ACK, NULL);
|
||||
ack.generation = ++rcc->ack_data.generation;
|
||||
ack.window = rcc->ack_data.client_window;
|
||||
rcc->ack_data.messages_window = 0;
|
||||
|
||||
spice_marshall_msg_set_ack(channel->send_data.marshaller, &ack);
|
||||
spice_marshall_msg_set_ack(rcc->send_data.marshaller, &ack);
|
||||
|
||||
red_channel_begin_send_message(channel);
|
||||
red_channel_client_begin_send_message(rcc);
|
||||
}
|
||||
|
||||
static void red_channel_send_item(RedChannel *channel, PipeItem *item)
|
||||
static void red_channel_client_send_item(RedChannelClient *rcc, PipeItem *item)
|
||||
{
|
||||
red_channel_reset_send_data(channel);
|
||||
int handled = TRUE;
|
||||
|
||||
ASSERT(red_channel_client_no_item_being_sent(rcc));
|
||||
red_channel_client_reset_send_data(rcc);
|
||||
switch (item->type) {
|
||||
case PIPE_ITEM_TYPE_SET_ACK:
|
||||
red_channel_send_set_ack(channel);
|
||||
return;
|
||||
red_channel_client_send_set_ack(rcc);
|
||||
break;
|
||||
default:
|
||||
handled = FALSE;
|
||||
}
|
||||
if (!handled) {
|
||||
rcc->channel->send_item(rcc, item);
|
||||
}
|
||||
/* only reached if not handled here */
|
||||
channel->send_item(channel, item);
|
||||
}
|
||||
|
||||
static void red_channel_release_item(RedChannel *channel, PipeItem *item, int item_pushed)
|
||||
static void red_channel_client_release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
|
||||
{
|
||||
int handled = TRUE;
|
||||
|
||||
switch (item->type) {
|
||||
case PIPE_ITEM_TYPE_SET_ACK:
|
||||
free(item);
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
handled = FALSE;
|
||||
}
|
||||
if (!handled) {
|
||||
rcc->channel->release_item(rcc, item, item_pushed);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void red_channel_client_release_sent_item(RedChannelClient *rcc)
|
||||
{
|
||||
if (rcc->send_data.item) {
|
||||
red_channel_client_release_item(rcc,
|
||||
rcc->send_data.item, TRUE);
|
||||
rcc->send_data.item = NULL;
|
||||
}
|
||||
/* only reached if not handled here */
|
||||
channel->release_item(channel, item, item_pushed);
|
||||
}
|
||||
|
||||
static void red_channel_peer_on_out_msg_done(void *opaque)
|
||||
{
|
||||
RedChannel *channel = (RedChannel *)opaque;
|
||||
channel->send_data.size = 0;
|
||||
if (channel->send_data.item) {
|
||||
red_channel_release_item(channel, channel->send_data.item, TRUE);
|
||||
channel->send_data.item = NULL;
|
||||
}
|
||||
if (channel->send_data.blocked) {
|
||||
channel->send_data.blocked = FALSE;
|
||||
channel->core->watch_update_mask(channel->stream->watch,
|
||||
RedChannelClient *rcc = (RedChannelClient *)opaque;
|
||||
|
||||
rcc->send_data.size = 0;
|
||||
red_channel_client_release_sent_item(rcc);
|
||||
if (rcc->send_data.blocked) {
|
||||
rcc->send_data.blocked = FALSE;
|
||||
rcc->channel->core->watch_update_mask(rcc->stream->watch,
|
||||
SPICE_WATCH_EVENT_READ);
|
||||
}
|
||||
}
|
||||
|
||||
RedChannel *red_channel_create(int size, RedsStream *stream,
|
||||
static void red_channel_add_client(RedChannel *channel, RedChannelClient *rcc)
|
||||
{
|
||||
ASSERT(rcc);
|
||||
channel->rcc = rcc;
|
||||
}
|
||||
|
||||
RedChannelClient *red_channel_client_create(
|
||||
int size,
|
||||
RedChannel *channel,
|
||||
RedsStream *stream)
|
||||
{
|
||||
RedChannelClient *rcc = NULL;
|
||||
|
||||
ASSERT(stream && channel && size >= sizeof(RedChannelClient));
|
||||
rcc = spice_malloc0(size);
|
||||
rcc->stream = stream;
|
||||
rcc->channel = channel;
|
||||
rcc->ack_data.messages_window = ~0; // blocks send message (maybe use send_data.blocked +
|
||||
// block flags)
|
||||
rcc->ack_data.client_generation = ~0;
|
||||
rcc->ack_data.client_window = CLIENT_ACK_WINDOW;
|
||||
rcc->send_data.marshaller = spice_marshaller_new();
|
||||
|
||||
rcc->incoming.opaque = rcc;
|
||||
rcc->incoming.cb = &channel->incoming_cb;
|
||||
|
||||
rcc->outgoing.opaque = rcc;
|
||||
rcc->outgoing.cb = &channel->outgoing_cb;
|
||||
rcc->outgoing.pos = 0;
|
||||
rcc->outgoing.size = 0;
|
||||
if (!channel->config_socket(rcc)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
stream->watch = channel->core->watch_add(stream->socket,
|
||||
SPICE_WATCH_EVENT_READ,
|
||||
red_channel_client_event, rcc);
|
||||
red_channel_add_client(channel, rcc);
|
||||
return rcc;
|
||||
error:
|
||||
free(rcc);
|
||||
reds_stream_free(stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RedChannel *red_channel_create(int size,
|
||||
SpiceCoreInterface *core,
|
||||
int migrate, int handle_acks,
|
||||
channel_configure_socket_proc config_socket,
|
||||
@ -339,7 +413,6 @@ RedChannel *red_channel_create(int size, RedsStream *stream,
|
||||
ASSERT(config_socket && disconnect && handle_message && alloc_recv_buf &&
|
||||
release_item);
|
||||
channel = spice_malloc0(size);
|
||||
|
||||
channel->handle_acks = handle_acks;
|
||||
channel->disconnect = disconnect;
|
||||
channel->send_item = send_item;
|
||||
@ -348,69 +421,40 @@ RedChannel *red_channel_create(int size, RedsStream *stream,
|
||||
channel->handle_migrate_flush_mark = handle_migrate_flush_mark;
|
||||
channel->handle_migrate_data = handle_migrate_data;
|
||||
channel->handle_migrate_data_get_serial = handle_migrate_data_get_serial;
|
||||
channel->config_socket = config_socket;
|
||||
|
||||
channel->stream = stream;
|
||||
channel->core = core;
|
||||
channel->ack_data.messages_window = ~0; // blocks send message (maybe use send_data.blocked +
|
||||
// block flags)
|
||||
channel->ack_data.client_generation = ~0;
|
||||
channel->ack_data.client_window = CLIENT_ACK_WINDOW;
|
||||
|
||||
channel->migrate = migrate;
|
||||
ring_init(&channel->pipe);
|
||||
channel->send_data.marshaller = spice_marshaller_new();
|
||||
|
||||
channel->incoming.opaque = channel;
|
||||
channel->incoming_cb.alloc_msg_buf = (alloc_msg_recv_buf_proc)alloc_recv_buf;
|
||||
channel->incoming_cb.release_msg_buf = (release_msg_recv_buf_proc)release_recv_buf;
|
||||
channel->incoming_cb.handle_message = (handle_message_proc)handle_message;
|
||||
channel->incoming_cb.on_error = (on_incoming_error_proc)red_channel_default_peer_on_error;
|
||||
|
||||
channel->outgoing.opaque = channel;
|
||||
channel->outgoing.pos = 0;
|
||||
channel->outgoing.size = 0;
|
||||
|
||||
channel->outgoing_cb.get_msg_size = red_channel_peer_get_out_msg_size;
|
||||
channel->outgoing_cb.prepare = red_channel_peer_prepare_out_msg;
|
||||
channel->outgoing_cb.on_block = red_channel_peer_on_out_block;
|
||||
channel->outgoing_cb.on_error = (on_outgoing_error_proc)red_channel_default_peer_on_error;
|
||||
channel->incoming_cb.on_error =
|
||||
(on_incoming_error_proc)red_channel_client_default_peer_on_error;
|
||||
channel->outgoing_cb.get_msg_size = red_channel_client_peer_get_out_msg_size;
|
||||
channel->outgoing_cb.prepare = red_channel_client_peer_prepare_out_msg;
|
||||
channel->outgoing_cb.on_block = red_channel_client_peer_on_out_block;
|
||||
channel->outgoing_cb.on_error =
|
||||
(on_outgoing_error_proc)red_channel_client_default_peer_on_error;
|
||||
channel->outgoing_cb.on_msg_done = red_channel_peer_on_out_msg_done;
|
||||
channel->outgoing_cb.on_output = red_channel_on_output;
|
||||
|
||||
channel->incoming.cb = &channel->incoming_cb;
|
||||
channel->outgoing.cb = &channel->outgoing_cb;
|
||||
channel->outgoing_cb.on_output = red_channel_client_on_output;
|
||||
|
||||
channel->shut = 0; // came here from inputs, perhaps can be removed? XXX
|
||||
channel->out_bytes_counter = 0;
|
||||
|
||||
if (!config_socket(channel)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
channel->stream->watch = channel->core->watch_add(channel->stream->socket,
|
||||
SPICE_WATCH_EVENT_READ,
|
||||
red_channel_event, channel);
|
||||
|
||||
return channel;
|
||||
|
||||
error:
|
||||
spice_marshaller_destroy(channel->send_data.marshaller);
|
||||
free(channel);
|
||||
reds_stream_free(stream);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void do_nothing_disconnect(RedChannel *red_channel)
|
||||
static void do_nothing_disconnect(RedChannelClient *rcc)
|
||||
{
|
||||
}
|
||||
|
||||
static int do_nothing_handle_message(RedChannel *red_channel, SpiceDataHeader *header, uint8_t *msg)
|
||||
static int do_nothing_handle_message(RedChannelClient *rcc, SpiceDataHeader *header, uint8_t *msg)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
RedChannel *red_channel_create_parser(int size, RedsStream *stream,
|
||||
RedChannel *red_channel_create_parser(int size,
|
||||
SpiceCoreInterface *core,
|
||||
int migrate, int handle_acks,
|
||||
channel_configure_socket_proc config_socket,
|
||||
@ -427,7 +471,7 @@ RedChannel *red_channel_create_parser(int size, RedsStream *stream,
|
||||
channel_handle_migrate_data_proc handle_migrate_data,
|
||||
channel_handle_migrate_data_get_serial_proc handle_migrate_data_get_serial)
|
||||
{
|
||||
RedChannel *channel = red_channel_create(size, stream,
|
||||
RedChannel *channel = red_channel_create(size,
|
||||
core, migrate, handle_acks, config_socket, do_nothing_disconnect,
|
||||
do_nothing_handle_message, alloc_recv_buf, release_recv_buf, hold_item,
|
||||
send_item, release_item, handle_migrate_flush_mark, handle_migrate_data,
|
||||
@ -438,62 +482,152 @@ RedChannel *red_channel_create_parser(int size, RedsStream *stream,
|
||||
}
|
||||
channel->incoming_cb.handle_parsed = (handle_parsed_proc)handle_parsed;
|
||||
channel->incoming_cb.parser = parser;
|
||||
channel->on_incoming_error = incoming_error;
|
||||
channel->on_outgoing_error = outgoing_error;
|
||||
channel->incoming_cb.on_error = (on_incoming_error_proc)red_channel_peer_on_incoming_error;
|
||||
channel->outgoing_cb.on_error = (on_outgoing_error_proc)red_channel_peer_on_outgoing_error;
|
||||
channel->on_incoming_error = incoming_error;
|
||||
channel->on_outgoing_error = outgoing_error;
|
||||
return channel;
|
||||
}
|
||||
|
||||
void red_channel_client_destroy(RedChannelClient *rcc)
|
||||
{
|
||||
red_channel_client_disconnect(rcc);
|
||||
spice_marshaller_destroy(rcc->send_data.marshaller);
|
||||
free(rcc);
|
||||
}
|
||||
|
||||
void red_channel_destroy(RedChannel *channel)
|
||||
{
|
||||
if (!channel) {
|
||||
return;
|
||||
}
|
||||
red_channel_pipe_clear(channel);
|
||||
reds_stream_free(channel->stream);
|
||||
spice_marshaller_destroy(channel->send_data.marshaller);
|
||||
if (channel->rcc) {
|
||||
red_channel_client_destroy(channel->rcc);
|
||||
}
|
||||
free(channel);
|
||||
}
|
||||
|
||||
static void red_channel_client_shutdown(RedChannelClient *rcc)
|
||||
{
|
||||
if (rcc->stream && !rcc->stream->shutdown) {
|
||||
rcc->channel->core->watch_remove(rcc->stream->watch);
|
||||
rcc->stream->watch = NULL;
|
||||
shutdown(rcc->stream->socket, SHUT_RDWR);
|
||||
rcc->stream->shutdown = TRUE;
|
||||
rcc->incoming.shut = TRUE;
|
||||
}
|
||||
red_channel_client_release_sent_item(rcc);
|
||||
}
|
||||
|
||||
void red_channel_shutdown(RedChannel *channel)
|
||||
{
|
||||
red_printf("");
|
||||
if (channel->stream && !channel->stream->shutdown) {
|
||||
channel->core->watch_update_mask(channel->stream->watch,
|
||||
SPICE_WATCH_EVENT_READ);
|
||||
red_channel_pipe_clear(channel);
|
||||
shutdown(channel->stream->socket, SHUT_RDWR);
|
||||
channel->stream->shutdown = TRUE;
|
||||
channel->incoming.shut = TRUE;
|
||||
if (channel->rcc) {
|
||||
red_channel_client_shutdown(channel->rcc);
|
||||
}
|
||||
red_channel_pipe_clear(channel);
|
||||
}
|
||||
|
||||
void red_channel_client_send(RedChannelClient *rcc)
|
||||
{
|
||||
red_peer_handle_outgoing(rcc->stream, &rcc->outgoing);
|
||||
}
|
||||
|
||||
void red_channel_send(RedChannel *channel)
|
||||
{
|
||||
if (channel->rcc) {
|
||||
red_channel_client_send(channel->rcc);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int red_channel_client_waiting_for_ack(RedChannelClient *rcc)
|
||||
{
|
||||
return (rcc->channel->handle_acks &&
|
||||
(rcc->ack_data.messages_window > rcc->ack_data.client_window * 2));
|
||||
}
|
||||
|
||||
// TODO: add refs and target to PipeItem. Right now this only works for a
|
||||
// single client (or actually, it's worse - first come first served)
|
||||
static inline PipeItem *red_channel_client_pipe_get(RedChannelClient *rcc)
|
||||
{
|
||||
PipeItem *item;
|
||||
|
||||
if (!rcc || rcc->send_data.blocked
|
||||
|| red_channel_client_waiting_for_ack(rcc)
|
||||
|| !(item = (PipeItem *)ring_get_tail(&rcc->channel->pipe))) {
|
||||
return NULL;
|
||||
}
|
||||
--rcc->channel->pipe_size;
|
||||
ring_remove(&item->link);
|
||||
return item;
|
||||
}
|
||||
|
||||
static void red_channel_client_push(RedChannelClient *rcc)
|
||||
{
|
||||
PipeItem *pipe_item;
|
||||
|
||||
if (!rcc->during_send) {
|
||||
rcc->during_send = TRUE;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rcc->send_data.blocked) {
|
||||
red_channel_client_send(rcc);
|
||||
}
|
||||
|
||||
while ((pipe_item = red_channel_client_pipe_get(rcc))) {
|
||||
red_channel_client_send_item(rcc, pipe_item);
|
||||
}
|
||||
rcc->during_send = FALSE;
|
||||
}
|
||||
|
||||
void red_channel_push(RedChannel *channel)
|
||||
{
|
||||
if (!channel || !channel->rcc) {
|
||||
return;
|
||||
}
|
||||
red_channel_client_push(channel->rcc);
|
||||
}
|
||||
|
||||
static void red_channel_client_init_outgoing_messages_window(RedChannelClient *rcc)
|
||||
{
|
||||
rcc->ack_data.messages_window = 0;
|
||||
red_channel_client_push(rcc);
|
||||
}
|
||||
|
||||
// TODO: this function doesn't make sense because the window should be client (WAN/LAN)
|
||||
// specific
|
||||
void red_channel_init_outgoing_messages_window(RedChannel *channel)
|
||||
{
|
||||
channel->ack_data.messages_window = 0;
|
||||
red_channel_push(channel);
|
||||
red_channel_client_init_outgoing_messages_window(channel->rcc);
|
||||
}
|
||||
|
||||
static void red_channel_handle_migrate_flush_mark(RedChannel *channel)
|
||||
{
|
||||
if (channel->handle_migrate_flush_mark) {
|
||||
channel->handle_migrate_flush_mark(channel);
|
||||
channel->handle_migrate_flush_mark(channel->rcc);
|
||||
}
|
||||
}
|
||||
|
||||
static void red_channel_handle_migrate_data(RedChannel *channel, uint32_t size, void *message)
|
||||
// TODO: the whole migration is broken with multiple clients. What do we want to do?
|
||||
// basically just
|
||||
// 1) source send mark to all
|
||||
// 2) source gets at various times the data (waits for all)
|
||||
// 3) source migrates to target
|
||||
// 4) target sends data to all
|
||||
// So need to make all the handlers work with per channel/client data (what data exactly?)
|
||||
static void red_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
|
||||
{
|
||||
if (!channel->handle_migrate_data) {
|
||||
if (!rcc->channel->handle_migrate_data) {
|
||||
return;
|
||||
}
|
||||
ASSERT(red_channel_get_message_serial(channel) == 0);
|
||||
red_channel_set_message_serial(channel,
|
||||
channel->handle_migrate_data_get_serial(channel, size, message));
|
||||
channel->handle_migrate_data(channel, size, message);
|
||||
ASSERT(red_channel_client_get_message_serial(rcc) == 0);
|
||||
red_channel_client_set_message_serial(rcc,
|
||||
rcc->channel->handle_migrate_data_get_serial(rcc, size, message));
|
||||
rcc->channel->handle_migrate_data(rcc, size, message);
|
||||
}
|
||||
|
||||
int red_channel_handle_message(RedChannel *channel, uint32_t size,
|
||||
int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
|
||||
uint16_t type, void *message)
|
||||
{
|
||||
switch (type) {
|
||||
@ -502,21 +636,21 @@ int red_channel_handle_message(RedChannel *channel, uint32_t size,
|
||||
red_printf("bad message size");
|
||||
return FALSE;
|
||||
}
|
||||
channel->ack_data.client_generation = *(uint32_t *)(message);
|
||||
rcc->ack_data.client_generation = *(uint32_t *)(message);
|
||||
break;
|
||||
case SPICE_MSGC_ACK:
|
||||
if (channel->ack_data.client_generation == channel->ack_data.generation) {
|
||||
channel->ack_data.messages_window -= channel->ack_data.client_window;
|
||||
red_channel_push(channel);
|
||||
if (rcc->ack_data.client_generation == rcc->ack_data.generation) {
|
||||
rcc->ack_data.messages_window -= rcc->ack_data.client_window;
|
||||
red_channel_client_push(rcc);
|
||||
}
|
||||
break;
|
||||
case SPICE_MSGC_DISCONNECTING:
|
||||
break;
|
||||
case SPICE_MSGC_MIGRATE_FLUSH_MARK:
|
||||
red_channel_handle_migrate_flush_mark(channel);
|
||||
red_channel_handle_migrate_flush_mark(rcc->channel);
|
||||
break;
|
||||
case SPICE_MSGC_MIGRATE_DATA:
|
||||
red_channel_handle_migrate_data(channel, size, message);
|
||||
red_channel_handle_migrate_data(rcc, size, message);
|
||||
break;
|
||||
default:
|
||||
red_printf("invalid message type %u", type);
|
||||
@ -525,75 +659,54 @@ int red_channel_handle_message(RedChannel *channel, uint32_t size,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void red_channel_event(int fd, int event, void *data)
|
||||
static void red_channel_client_event(int fd, int event, void *data)
|
||||
{
|
||||
RedChannel *channel = (RedChannel *)data;
|
||||
RedChannelClient *rcc = (RedChannelClient *)data;
|
||||
|
||||
if (event & SPICE_WATCH_EVENT_READ) {
|
||||
red_channel_receive(channel);
|
||||
red_channel_client_receive(rcc);
|
||||
}
|
||||
if (event & SPICE_WATCH_EVENT_WRITE) {
|
||||
red_channel_push(channel);
|
||||
red_channel_client_push(rcc);
|
||||
}
|
||||
}
|
||||
|
||||
void red_channel_init_send_data(RedChannel *channel, uint16_t msg_type, PipeItem *item)
|
||||
void red_channel_client_init_send_data(RedChannelClient *rcc, uint16_t msg_type, PipeItem *item)
|
||||
{
|
||||
ASSERT(channel->send_data.item == NULL);
|
||||
channel->send_data.header->type = msg_type;
|
||||
channel->send_data.item = item;
|
||||
ASSERT(red_channel_client_no_item_being_sent(rcc));
|
||||
ASSERT(msg_type != 0);
|
||||
rcc->send_data.header->type = msg_type;
|
||||
rcc->send_data.item = item;
|
||||
if (item) {
|
||||
channel->hold_item(channel, item);
|
||||
rcc->channel->hold_item(rcc, item);
|
||||
}
|
||||
}
|
||||
|
||||
void red_channel_send(RedChannel *channel)
|
||||
void red_channel_client_begin_send_message(RedChannelClient *rcc)
|
||||
{
|
||||
red_peer_handle_outgoing(channel->stream, &channel->outgoing);
|
||||
}
|
||||
SpiceMarshaller *m = rcc->send_data.marshaller;
|
||||
|
||||
void red_channel_begin_send_message(RedChannel *channel)
|
||||
{
|
||||
spice_marshaller_flush(channel->send_data.marshaller);
|
||||
channel->send_data.size = spice_marshaller_get_total_size(channel->send_data.marshaller);
|
||||
channel->send_data.header->size = channel->send_data.size - sizeof(SpiceDataHeader);
|
||||
channel->ack_data.messages_window++;
|
||||
channel->send_data.header = NULL; /* avoid writing to this until we have a new message */
|
||||
red_channel_send(channel);
|
||||
}
|
||||
|
||||
void red_channel_push(RedChannel *channel)
|
||||
{
|
||||
PipeItem *pipe_item;
|
||||
|
||||
if (!channel) {
|
||||
// TODO - better check: type in channel_allowed_types. Better: type in channel_allowed_types(channel_state)
|
||||
if (rcc->send_data.header->type == 0) {
|
||||
red_printf("BUG: header->type == 0");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel->during_send) {
|
||||
channel->during_send = TRUE;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel->send_data.blocked) {
|
||||
red_channel_send(channel);
|
||||
}
|
||||
|
||||
while ((pipe_item = red_channel_pipe_get(channel))) {
|
||||
red_channel_send_item(channel, pipe_item);
|
||||
}
|
||||
channel->during_send = FALSE;
|
||||
spice_marshaller_flush(m);
|
||||
rcc->send_data.size = spice_marshaller_get_total_size(m);
|
||||
rcc->send_data.header->size = rcc->send_data.size - sizeof(SpiceDataHeader);
|
||||
rcc->ack_data.messages_window++;
|
||||
rcc->send_data.header = NULL; /* avoid writing to this until we have a new message */
|
||||
red_channel_client_send(rcc);
|
||||
}
|
||||
|
||||
uint64_t red_channel_get_message_serial(RedChannel *channel)
|
||||
uint64_t red_channel_client_get_message_serial(RedChannelClient *rcc)
|
||||
{
|
||||
return channel->send_data.serial;
|
||||
return rcc->send_data.serial;
|
||||
}
|
||||
|
||||
void red_channel_set_message_serial(RedChannel *channel, uint64_t serial)
|
||||
void red_channel_client_set_message_serial(RedChannelClient *rcc, uint64_t serial)
|
||||
{
|
||||
channel->send_data.serial = serial;
|
||||
rcc->send_data.serial = serial;
|
||||
}
|
||||
|
||||
void red_channel_pipe_item_init(RedChannel *channel, PipeItem *item, int type)
|
||||
@ -657,28 +770,19 @@ void red_channel_pipe_add_type(RedChannel *channel, int pipe_item_type)
|
||||
red_channel_push(channel);
|
||||
}
|
||||
|
||||
static inline int red_channel_waiting_for_ack(RedChannel *channel)
|
||||
{
|
||||
return (channel->handle_acks && (channel->ack_data.messages_window > channel->ack_data.client_window * 2));
|
||||
}
|
||||
|
||||
static inline PipeItem *red_channel_pipe_get(RedChannel *channel)
|
||||
{
|
||||
PipeItem *item;
|
||||
|
||||
if (!channel || channel->send_data.blocked ||
|
||||
red_channel_waiting_for_ack(channel) ||
|
||||
!(item = (PipeItem *)ring_get_tail(&channel->pipe))) {
|
||||
return NULL;
|
||||
}
|
||||
--channel->pipe_size;
|
||||
ring_remove(&item->link);
|
||||
return item;
|
||||
}
|
||||
|
||||
int red_channel_is_connected(RedChannel *channel)
|
||||
{
|
||||
return !!channel->stream;
|
||||
return channel->rcc != NULL;
|
||||
}
|
||||
|
||||
void red_channel_client_clear_sent_item(RedChannelClient *rcc)
|
||||
{
|
||||
if (rcc->send_data.item) {
|
||||
red_channel_client_release_item(rcc, rcc->send_data.item, TRUE);
|
||||
rcc->send_data.item = NULL;
|
||||
}
|
||||
rcc->send_data.blocked = FALSE;
|
||||
rcc->send_data.size = 0;
|
||||
}
|
||||
|
||||
void red_channel_pipe_clear(RedChannel *channel)
|
||||
@ -686,82 +790,161 @@ void red_channel_pipe_clear(RedChannel *channel)
|
||||
PipeItem *item;
|
||||
|
||||
ASSERT(channel);
|
||||
if (channel->send_data.item) {
|
||||
red_channel_release_item(channel, channel->send_data.item, TRUE);
|
||||
channel->send_data.item = NULL;
|
||||
if (channel->rcc) {
|
||||
red_channel_client_clear_sent_item(channel->rcc);
|
||||
}
|
||||
while ((item = (PipeItem *)ring_get_head(&channel->pipe))) {
|
||||
ring_remove(&item->link);
|
||||
red_channel_release_item(channel, item, FALSE);
|
||||
red_channel_client_release_item(channel->rcc, item, FALSE);
|
||||
}
|
||||
channel->pipe_size = 0;
|
||||
}
|
||||
|
||||
void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc)
|
||||
{
|
||||
rcc->ack_data.messages_window = 0;
|
||||
}
|
||||
|
||||
void red_channel_ack_zero_messages_window(RedChannel *channel)
|
||||
{
|
||||
channel->ack_data.messages_window = 0;
|
||||
red_channel_client_ack_zero_messages_window(channel->rcc);
|
||||
}
|
||||
|
||||
void red_channel_ack_set_client_window(RedChannel *channel, int client_window)
|
||||
void red_channel_client_ack_set_client_window(RedChannelClient *rcc, int client_window)
|
||||
{
|
||||
channel->ack_data.client_window = client_window;
|
||||
rcc->ack_data.client_window = client_window;
|
||||
}
|
||||
|
||||
int red_channel_all_blocked(RedChannel *channel)
|
||||
void red_channel_ack_set_client_window(RedChannel* channel, int client_window)
|
||||
{
|
||||
return channel->send_data.blocked;
|
||||
}
|
||||
|
||||
int red_channel_any_blocked(RedChannel *channel)
|
||||
{
|
||||
return channel->send_data.blocked;
|
||||
}
|
||||
|
||||
int red_channel_send_message_pending(RedChannel *channel)
|
||||
{
|
||||
return channel->send_data.header->type != 0;
|
||||
}
|
||||
|
||||
/* accessors for RedChannel */
|
||||
SpiceMarshaller *red_channel_get_marshaller(RedChannel *channel)
|
||||
{
|
||||
return channel->send_data.marshaller;
|
||||
}
|
||||
|
||||
RedsStream *red_channel_get_stream(RedChannel *channel)
|
||||
{
|
||||
return channel->stream;
|
||||
}
|
||||
|
||||
SpiceDataHeader *red_channel_get_header(RedChannel *channel)
|
||||
{
|
||||
return channel->send_data.header;
|
||||
}
|
||||
/* end of accessors */
|
||||
|
||||
int red_channel_get_first_socket(RedChannel *channel)
|
||||
{
|
||||
if (!channel->stream) {
|
||||
return -1;
|
||||
if (channel->rcc) {
|
||||
red_channel_client_ack_set_client_window(channel->rcc, client_window);
|
||||
}
|
||||
return channel->stream->socket;
|
||||
}
|
||||
|
||||
int red_channel_item_being_sent(RedChannel *channel, PipeItem *item)
|
||||
void red_channel_client_disconnect(RedChannelClient *rcc)
|
||||
{
|
||||
return channel->send_data.item == item;
|
||||
}
|
||||
red_printf("%p (channel %p)", rcc, rcc->channel);
|
||||
|
||||
int red_channel_no_item_being_sent(RedChannel *channel)
|
||||
{
|
||||
return channel->send_data.item == NULL;
|
||||
if (rcc->send_data.item) {
|
||||
rcc->channel->release_item(rcc, rcc->send_data.item, FALSE);
|
||||
}
|
||||
// TODO: clear our references from the pipe
|
||||
reds_stream_free(rcc->stream);
|
||||
rcc->send_data.item = NULL;
|
||||
rcc->send_data.blocked = FALSE;
|
||||
rcc->send_data.size = 0;
|
||||
rcc->channel->rcc = NULL;
|
||||
}
|
||||
|
||||
void red_channel_disconnect(RedChannel *channel)
|
||||
{
|
||||
red_channel_pipe_clear(channel);
|
||||
reds_stream_free(channel->stream);
|
||||
channel->stream = NULL;
|
||||
channel->send_data.blocked = FALSE;
|
||||
channel->send_data.size = 0;
|
||||
if (channel->rcc) {
|
||||
red_channel_client_disconnect(channel->rcc);
|
||||
}
|
||||
}
|
||||
|
||||
int red_channel_all_clients_serials_are_zero(RedChannel *channel)
|
||||
{
|
||||
return (!channel->rcc || channel->rcc->send_data.serial == 0);
|
||||
}
|
||||
|
||||
void red_channel_apply_clients(RedChannel *channel, channel_client_visitor v)
|
||||
{
|
||||
if (channel->rcc) {
|
||||
v(channel->rcc);
|
||||
}
|
||||
}
|
||||
|
||||
void red_channel_apply_clients_data(RedChannel *channel, channel_client_visitor_data v, void *data)
|
||||
{
|
||||
if (channel->rcc) {
|
||||
v(channel->rcc, data);
|
||||
}
|
||||
}
|
||||
|
||||
void red_channel_set_shut(RedChannel *channel)
|
||||
{
|
||||
if (channel->rcc) {
|
||||
channel->rcc->incoming.shut = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
int red_channel_all_blocked(RedChannel *channel)
|
||||
{
|
||||
return !channel || !channel->rcc || channel->rcc->send_data.blocked;
|
||||
}
|
||||
|
||||
int red_channel_any_blocked(RedChannel *channel)
|
||||
{
|
||||
return !channel || !channel->rcc || channel->rcc->send_data.blocked;
|
||||
}
|
||||
|
||||
int red_channel_client_blocked(RedChannelClient *rcc)
|
||||
{
|
||||
return rcc && rcc->send_data.blocked;
|
||||
}
|
||||
|
||||
int red_channel_client_send_message_pending(RedChannelClient *rcc)
|
||||
{
|
||||
return rcc->send_data.header->type != 0;
|
||||
}
|
||||
|
||||
/* accessors for RedChannelClient */
|
||||
SpiceMarshaller *red_channel_client_get_marshaller(RedChannelClient *rcc)
|
||||
{
|
||||
return rcc->send_data.marshaller;
|
||||
}
|
||||
|
||||
RedsStream *red_channel_client_get_stream(RedChannelClient *rcc)
|
||||
{
|
||||
return rcc->stream;
|
||||
}
|
||||
|
||||
SpiceDataHeader *red_channel_client_get_header(RedChannelClient *rcc)
|
||||
{
|
||||
return rcc->send_data.header;
|
||||
}
|
||||
/* end of accessors */
|
||||
|
||||
int red_channel_get_first_socket(RedChannel *channel)
|
||||
{
|
||||
if (!channel->rcc || !channel->rcc->stream) {
|
||||
return -1;
|
||||
}
|
||||
return channel->rcc->stream->socket;
|
||||
}
|
||||
|
||||
int red_channel_client_item_being_sent(RedChannelClient *rcc, PipeItem *item)
|
||||
{
|
||||
return rcc->send_data.item == item;
|
||||
}
|
||||
|
||||
int red_channel_item_being_sent(RedChannel *channel, PipeItem *item)
|
||||
{
|
||||
return channel->rcc && red_channel_client_item_being_sent(channel->rcc, item);
|
||||
}
|
||||
|
||||
int red_channel_no_item_being_sent(RedChannel *channel)
|
||||
{
|
||||
return !channel->rcc || red_channel_client_no_item_being_sent(channel->rcc);
|
||||
}
|
||||
|
||||
int red_channel_client_no_item_being_sent(RedChannelClient *rcc)
|
||||
{
|
||||
return !rcc || (rcc->send_data.size == 0);
|
||||
}
|
||||
|
||||
static void red_channel_client_pipe_remove(RedChannelClient *rcc, PipeItem *item)
|
||||
{
|
||||
rcc->channel->pipe_size--;
|
||||
ring_remove(&item->link);
|
||||
}
|
||||
|
||||
void red_channel_client_pipe_remove_and_release(RedChannelClient *rcc,
|
||||
PipeItem *item)
|
||||
{
|
||||
red_channel_client_pipe_remove(rcc, item);
|
||||
red_channel_client_release_item(rcc, item, FALSE);
|
||||
}
|
||||
|
||||
@ -97,6 +97,9 @@ typedef struct BufDescriptor {
|
||||
uint8_t *data;
|
||||
} BufDescriptor;
|
||||
|
||||
typedef struct RedChannel RedChannel;
|
||||
typedef struct RedChannelClient RedChannelClient;
|
||||
|
||||
/* Messages handled by red_channel
|
||||
* SET_ACK - sent to client on channel connection
|
||||
* Note that the numbers don't have to correspond to spice message types,
|
||||
@ -112,37 +115,33 @@ typedef struct PipeItem {
|
||||
int type;
|
||||
} PipeItem;
|
||||
|
||||
typedef struct RedChannel RedChannel;
|
||||
|
||||
typedef uint8_t *(*channel_alloc_msg_recv_buf_proc)(RedChannel *channel,
|
||||
typedef uint8_t *(*channel_alloc_msg_recv_buf_proc)(RedChannelClient *channel,
|
||||
SpiceDataHeader *msg_header);
|
||||
typedef int (*channel_handle_parsed_proc)(RedChannel *channel, uint32_t size, uint16_t type,
|
||||
typedef int (*channel_handle_parsed_proc)(RedChannelClient *rcc, uint32_t size, uint16_t type,
|
||||
void *message);
|
||||
typedef int (*channel_handle_message_proc)(RedChannel *channel,
|
||||
typedef int (*channel_handle_message_proc)(RedChannelClient *rcc,
|
||||
SpiceDataHeader *header, uint8_t *msg);
|
||||
typedef void (*channel_release_msg_recv_buf_proc)(RedChannel *channel,
|
||||
typedef void (*channel_release_msg_recv_buf_proc)(RedChannelClient *channel,
|
||||
SpiceDataHeader *msg_header, uint8_t *msg);
|
||||
typedef void (*channel_disconnect_proc)(RedChannel *channel);
|
||||
typedef int (*channel_configure_socket_proc)(RedChannel *channel);
|
||||
typedef void (*channel_send_pipe_item_proc)(RedChannel *channel, PipeItem *item);
|
||||
typedef void (*channel_hold_pipe_item_proc)(RedChannel *channel, PipeItem *item);
|
||||
typedef void (*channel_release_pipe_item_proc)(RedChannel *channel,
|
||||
typedef void (*channel_disconnect_proc)(RedChannelClient *rcc);
|
||||
typedef int (*channel_configure_socket_proc)(RedChannelClient *rcc);
|
||||
typedef void (*channel_send_pipe_item_proc)(RedChannelClient *rcc, PipeItem *item);
|
||||
typedef void (*channel_hold_pipe_item_proc)(RedChannelClient *rcc, PipeItem *item);
|
||||
typedef void (*channel_release_pipe_item_proc)(RedChannelClient *rcc,
|
||||
PipeItem *item, int item_pushed);
|
||||
typedef void (*channel_on_incoming_error_proc)(RedChannel *channel);
|
||||
typedef void (*channel_on_outgoing_error_proc)(RedChannel *channel);
|
||||
typedef void (*channel_on_incoming_error_proc)(RedChannelClient *rcc);
|
||||
typedef void (*channel_on_outgoing_error_proc)(RedChannelClient *rcc);
|
||||
|
||||
typedef int (*channel_handle_migrate_flush_mark_proc)(RedChannel *channel);
|
||||
typedef uint64_t (*channel_handle_migrate_data_proc)(RedChannel *channel,
|
||||
typedef int (*channel_handle_migrate_flush_mark_proc)(RedChannelClient *base);
|
||||
typedef uint64_t (*channel_handle_migrate_data_proc)(RedChannelClient *base,
|
||||
uint32_t size, void *message);
|
||||
typedef uint64_t (*channel_handle_migrate_data_get_serial_proc)(RedChannel *channel,
|
||||
typedef uint64_t (*channel_handle_migrate_data_get_serial_proc)(RedChannelClient *base,
|
||||
uint32_t size, void *message);
|
||||
|
||||
struct RedChannel {
|
||||
struct RedChannelClient {
|
||||
RingItem channel_link;
|
||||
RedChannel *channel;
|
||||
RedsStream *stream;
|
||||
SpiceCoreInterface *core;
|
||||
int migrate;
|
||||
int handle_acks;
|
||||
|
||||
struct {
|
||||
uint32_t generation;
|
||||
uint32_t client_generation;
|
||||
@ -150,9 +149,6 @@ struct RedChannel {
|
||||
uint32_t client_window;
|
||||
} ack_data;
|
||||
|
||||
Ring pipe;
|
||||
uint32_t pipe_size;
|
||||
|
||||
struct {
|
||||
SpiceMarshaller *marshaller;
|
||||
SpiceDataHeader *header;
|
||||
@ -164,16 +160,28 @@ struct RedChannel {
|
||||
|
||||
OutgoingHandler outgoing;
|
||||
IncomingHandler incoming;
|
||||
int during_send;
|
||||
};
|
||||
|
||||
struct RedChannel {
|
||||
SpiceCoreInterface *core;
|
||||
int migrate;
|
||||
int handle_acks;
|
||||
|
||||
RedChannelClient *rcc;
|
||||
|
||||
Ring pipe;
|
||||
uint32_t pipe_size;
|
||||
|
||||
OutgoingHandlerInterface outgoing_cb;
|
||||
IncomingHandlerInterface incoming_cb;
|
||||
|
||||
channel_configure_socket_proc config_socket;
|
||||
channel_disconnect_proc disconnect;
|
||||
channel_send_pipe_item_proc send_item;
|
||||
channel_hold_pipe_item_proc hold_item;
|
||||
channel_release_pipe_item_proc release_item;
|
||||
|
||||
int during_send;
|
||||
/* Stuff below added for Main and Inputs channels switch to RedChannel
|
||||
* (might be removed later) */
|
||||
channel_on_incoming_error_proc on_incoming_error; /* alternative to disconnect */
|
||||
@ -190,7 +198,7 @@ struct RedChannel {
|
||||
|
||||
/* if one of the callbacks should cause disconnect, use red_channel_shutdown and don't
|
||||
explicitly destroy the channel */
|
||||
RedChannel *red_channel_create(int size, RedsStream *stream,
|
||||
RedChannel *red_channel_create(int size,
|
||||
SpiceCoreInterface *core,
|
||||
int migrate, int handle_acks,
|
||||
channel_configure_socket_proc config_socket,
|
||||
@ -207,7 +215,7 @@ RedChannel *red_channel_create(int size, RedsStream *stream,
|
||||
|
||||
/* alternative constructor, meant for marshaller based (inputs,main) channels,
|
||||
* will become default eventually */
|
||||
RedChannel *red_channel_create_parser(int size, RedsStream *stream,
|
||||
RedChannel *red_channel_create_parser(int size,
|
||||
SpiceCoreInterface *core,
|
||||
int migrate, int handle_acks,
|
||||
channel_configure_socket_proc config_socket,
|
||||
@ -223,29 +231,31 @@ RedChannel *red_channel_create_parser(int size, RedsStream *stream,
|
||||
channel_handle_migrate_flush_mark_proc handle_migrate_flush_mark,
|
||||
channel_handle_migrate_data_proc handle_migrate_data,
|
||||
channel_handle_migrate_data_get_serial_proc handle_migrate_data_get_serial);
|
||||
|
||||
RedChannelClient *red_channel_client_create(int size, RedChannel *channel,
|
||||
RedsStream *stream);
|
||||
int red_channel_is_connected(RedChannel *channel);
|
||||
|
||||
void red_channel_client_destroy(RedChannelClient *rcc);
|
||||
void red_channel_destroy(RedChannel *channel);
|
||||
|
||||
/* should be called when a new channel is ready to send messages */
|
||||
void red_channel_init_outgoing_messages_window(RedChannel *channel);
|
||||
|
||||
/* handles general channel msgs from the client */
|
||||
int red_channel_handle_message(RedChannel *channel, uint32_t size,
|
||||
int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
|
||||
uint16_t type, void *message);
|
||||
|
||||
/* default error handler that disconnects channel */
|
||||
void red_channel_default_peer_on_error(RedChannel *channel);
|
||||
void red_channel_client_default_peer_on_error(RedChannelClient *rcc);
|
||||
|
||||
/* when preparing send_data: should call init and then use marshaller */
|
||||
void red_channel_init_send_data(RedChannel *channel, uint16_t msg_type, PipeItem *item);
|
||||
void red_channel_client_init_send_data(RedChannelClient *rcc, uint16_t msg_type, PipeItem *item);
|
||||
|
||||
uint64_t red_channel_get_message_serial(RedChannel *channel);
|
||||
void red_channel_set_message_serial(RedChannel *channel, uint64_t);
|
||||
uint64_t red_channel_client_get_message_serial(RedChannelClient *channel);
|
||||
void red_channel_client_set_message_serial(RedChannelClient *channel, uint64_t);
|
||||
|
||||
/* when sending a msg. should first call red_channel_begin_send_message */
|
||||
void red_channel_begin_send_message(RedChannel *channel);
|
||||
/* when sending a msg. should first call red_channel_client_begin_send_message */
|
||||
void red_channel_client_begin_send_message(RedChannelClient *rcc);
|
||||
|
||||
void red_channel_pipe_item_init(RedChannel *channel, PipeItem *item, int type);
|
||||
void red_channel_pipe_add_push(RedChannel *channel, PipeItem *item);
|
||||
@ -253,14 +263,19 @@ void red_channel_pipe_add(RedChannel *channel, PipeItem *item);
|
||||
void red_channel_pipe_add_after(RedChannel *channel, PipeItem *item, PipeItem *pos);
|
||||
int red_channel_pipe_item_is_linked(RedChannel *channel, PipeItem *item);
|
||||
void red_channel_pipe_item_remove(RedChannel *channel, PipeItem *item);
|
||||
void red_channel_client_pipe_remove_and_release(RedChannelClient *rcc, PipeItem *item);
|
||||
void red_channel_pipe_add_tail(RedChannel *channel, PipeItem *item);
|
||||
/* for types that use this routine -> the pipe item should be freed */
|
||||
void red_channel_pipe_add_type(RedChannel *channel, int pipe_item_type);
|
||||
|
||||
void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc);
|
||||
void red_channel_client_ack_set_client_window(RedChannelClient *rcc, int client_window);
|
||||
void red_channel_client_push_set_ack(RedChannelClient *rcc);
|
||||
void red_channel_ack_zero_messages_window(RedChannel *channel);
|
||||
void red_channel_ack_set_client_window(RedChannel *channel, int client_window);
|
||||
void red_channel_push_set_ack(RedChannel *channel);
|
||||
|
||||
/* TODO: This sets all clients to shut state - probably we want to close per channel */
|
||||
void red_channel_shutdown(RedChannel *channel);
|
||||
|
||||
int red_channel_get_first_socket(RedChannel *channel);
|
||||
@ -271,8 +286,10 @@ int red_channel_all_blocked(RedChannel *channel);
|
||||
/* return TRUE if any of the connected clients to this channel are blocked */
|
||||
int red_channel_any_blocked(RedChannel *channel);
|
||||
|
||||
int red_channel_client_blocked(RedChannelClient *rcc);
|
||||
|
||||
/* helper for channels that have complex logic that can possibly ready a send */
|
||||
int red_channel_send_message_pending(RedChannel *channel);
|
||||
int red_channel_client_send_message_pending(RedChannelClient *rcc);
|
||||
|
||||
/* returns TRUE if item is being sent by one of the channel clients. This will
|
||||
* be true if someone called init_send_data but send has not completed (or perhaps
|
||||
@ -281,6 +298,7 @@ int red_channel_send_message_pending(RedChannel *channel);
|
||||
int red_channel_item_being_sent(RedChannel *channel, PipeItem *item);
|
||||
|
||||
int red_channel_no_item_being_sent(RedChannel *channel);
|
||||
int red_channel_client_no_item_being_sent(RedChannelClient *rcc);
|
||||
|
||||
// TODO: unstaticed for display/cursor channels. they do some specific pushes not through
|
||||
// adding elements or on events. but not sure if this is actually required (only result
|
||||
@ -299,14 +317,18 @@ void red_channel_pipe_clear(RedChannel *channel);
|
||||
// red_wait_pipe_item_sent
|
||||
// handle_channel_events - this is the only one that was used before, and was in red_channel.c
|
||||
void red_channel_receive(RedChannel *channel);
|
||||
void red_channel_client_receive(RedChannelClient *rcc);
|
||||
// For red_worker
|
||||
void red_channel_send(RedChannel *channel);
|
||||
void red_channel_client_send(RedChannelClient *rcc);
|
||||
// For red_worker
|
||||
void red_channel_disconnect(RedChannel *channel);
|
||||
void red_channel_client_disconnect(RedChannelClient *rcc);
|
||||
|
||||
/* accessors for RedChannel */
|
||||
/* accessors for RedChannelClient */
|
||||
/* Note: the valid times to call red_channel_get_marshaller are just during send_item callback. */
|
||||
SpiceMarshaller *red_channel_get_marshaller(RedChannel *channel);
|
||||
RedsStream *red_channel_get_stream(RedChannel *channel);
|
||||
SpiceMarshaller *red_channel_client_get_marshaller(RedChannelClient *rcc);
|
||||
RedsStream *red_channel_client_get_stream(RedChannelClient *rcc);
|
||||
|
||||
/* this is a convenience function for sending messages, sometimes (migration only?)
|
||||
* the serial from the header needs to be available for sending. Note that the header
|
||||
@ -314,5 +336,12 @@ RedsStream *red_channel_get_stream(RedChannel *channel);
|
||||
* red_channel_begin_send_message. red_channel_init_send_data changes the header (sets
|
||||
* the type in it) as a convenience function. It is preffered to do that through it and
|
||||
* not via the below accessor and direct header manipulation. */
|
||||
SpiceDataHeader *red_channel_get_header(RedChannel *channel);
|
||||
SpiceDataHeader *red_channel_client_get_header(RedChannelClient *rcc);
|
||||
|
||||
/* apply given function to all connected clients */
|
||||
typedef void (*channel_client_visitor)(RedChannelClient *rcc);
|
||||
typedef void (*channel_client_visitor_data)(RedChannelClient *rcc, void *data);
|
||||
void red_channel_apply_clients(RedChannel *channel, channel_client_visitor v);
|
||||
void red_channel_apply_clients_data(RedChannel *channel, channel_client_visitor_data v, void *data);
|
||||
|
||||
#endif
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#define FUNC_NAME(name) pixmap_cache_##name
|
||||
#define PRIVATE_FUNC_NAME(name) __pixmap_cache_##name
|
||||
#define CHANNEL DisplayChannel
|
||||
#define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF(rcc->channel, CHANNEL, common.base);
|
||||
#define CACH_GENERATION pixmap_cache_generation
|
||||
#define INVAL_ALL_VERB SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS
|
||||
#else
|
||||
@ -35,12 +36,13 @@
|
||||
#endif
|
||||
|
||||
|
||||
static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, CHANNEL *channel)
|
||||
static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, RedChannelClient *rcc)
|
||||
{
|
||||
CHANNEL *channel = CHANNEL_FROM_RCC(rcc);
|
||||
NewCacheItem *item;
|
||||
uint64_t serial;
|
||||
|
||||
serial = red_channel_get_message_serial((RedChannel *)channel);
|
||||
serial = red_channel_client_get_message_serial(rcc);
|
||||
pthread_mutex_lock(&cache->lock);
|
||||
item = cache->hash_table[CACHE_HASH_KEY(id)];
|
||||
|
||||
@ -79,8 +81,9 @@ static int FUNC_NAME(set_lossy)(CACHE *cache, uint64_t id, int lossy)
|
||||
return !!item;
|
||||
}
|
||||
|
||||
static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, CHANNEL *channel)
|
||||
static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, RedChannelClient *rcc)
|
||||
{
|
||||
CHANNEL *channel = CHANNEL_FROM_RCC(rcc);
|
||||
NewCacheItem *item;
|
||||
uint64_t serial;
|
||||
int key;
|
||||
@ -88,7 +91,7 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, C
|
||||
ASSERT(size > 0);
|
||||
|
||||
item = spice_new(NewCacheItem, 1);
|
||||
serial = red_channel_get_message_serial((RedChannel *)channel);
|
||||
serial = red_channel_client_get_message_serial(rcc);
|
||||
|
||||
pthread_mutex_lock(&cache->lock);
|
||||
|
||||
@ -166,13 +169,14 @@ static void PRIVATE_FUNC_NAME(clear)(CACHE *cache)
|
||||
cache->items = 0;
|
||||
}
|
||||
|
||||
static void FUNC_NAME(reset)(CACHE *cache, CHANNEL *channel, SpiceMsgWaitForChannels* sync_data)
|
||||
static void FUNC_NAME(reset)(CACHE *cache, RedChannelClient *rcc, SpiceMsgWaitForChannels* sync_data)
|
||||
{
|
||||
CHANNEL *channel = CHANNEL_FROM_RCC(rcc);
|
||||
uint8_t wait_count;
|
||||
uint64_t serial;
|
||||
uint32_t i;
|
||||
|
||||
serial = red_channel_get_message_serial((RedChannel *)channel);
|
||||
serial = red_channel_client_get_message_serial(rcc);
|
||||
pthread_mutex_lock(&cache->lock);
|
||||
PRIVATE_FUNC_NAME(clear)(cache);
|
||||
|
||||
@ -230,4 +234,5 @@ static void FUNC_NAME(destroy)(CACHE *cache)
|
||||
#undef FUNC_NAME
|
||||
#undef VAR_NAME
|
||||
#undef CHANNEL
|
||||
#undef CHANNEL_FROM_RCC
|
||||
|
||||
|
||||
@ -1645,9 +1645,11 @@ static int tunnel_channel_handle_socket_token(TunnelChannel *channel, RedSocket
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static uint8_t *tunnel_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header)
|
||||
static uint8_t *tunnel_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
|
||||
SpiceDataHeader *msg_header)
|
||||
{
|
||||
TunnelChannel *tunnel_channel = (TunnelChannel *)channel;
|
||||
TunnelChannel *tunnel_channel = (TunnelChannel *)rcc->channel;
|
||||
|
||||
if (msg_header->type == SPICE_MSGC_TUNNEL_SOCKET_DATA) {
|
||||
return (__tunnel_worker_alloc_socket_rcv_buf(tunnel_channel->worker)->buf);
|
||||
} else if ((msg_header->type == SPICE_MSGC_MIGRATE_DATA) ||
|
||||
@ -1659,10 +1661,11 @@ static uint8_t *tunnel_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataH
|
||||
}
|
||||
|
||||
// called by the receive routine of the channel, before the buffer was assigned to a socket
|
||||
static void tunnel_channel_release_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header,
|
||||
static void tunnel_channel_release_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header,
|
||||
uint8_t *msg)
|
||||
{
|
||||
TunnelChannel *tunnel_channel = (TunnelChannel *)channel;
|
||||
TunnelChannel *tunnel_channel = (TunnelChannel *)rcc->channel;
|
||||
|
||||
if (msg_header->type == SPICE_MSGC_TUNNEL_SOCKET_DATA) {
|
||||
ASSERT(!(SPICE_CONTAINEROF(msg, RedSocketRawRcvBuf, buf)->base.usr_opaque));
|
||||
__tunnel_worker_free_socket_rcv_buf(tunnel_channel->worker,
|
||||
@ -1744,9 +1747,9 @@ static void __tunnel_channel_fill_socket_migrate_item(TunnelChannel *channel, Re
|
||||
}
|
||||
|
||||
static void release_migrate_item(TunnelMigrateItem *item);
|
||||
static int tunnel_channel_handle_migrate_mark(RedChannel *base)
|
||||
static int tunnel_channel_handle_migrate_mark(RedChannelClient *rcc)
|
||||
{
|
||||
TunnelChannel *channel = SPICE_CONTAINEROF(base, TunnelChannel, base);
|
||||
TunnelChannel *channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
|
||||
TunnelMigrateItem *migrate_item = NULL;
|
||||
TunnelService *service;
|
||||
TunnelMigrateServiceItem *mig_service;
|
||||
@ -2159,7 +2162,7 @@ static inline void tunnel_channel_activate_migrated_sockets(TunnelChannel *chann
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t tunnel_channel_handle_migrate_data_get_serial(RedChannel *base,
|
||||
static uint64_t tunnel_channel_handle_migrate_data_get_serial(RedChannelClient *rcc,
|
||||
uint32_t size, void *msg)
|
||||
{
|
||||
TunnelMigrateData *migrate_data = msg;
|
||||
@ -2172,10 +2175,10 @@ static uint64_t tunnel_channel_handle_migrate_data_get_serial(RedChannel *base,
|
||||
return migrate_data->message_serial;
|
||||
}
|
||||
|
||||
static uint64_t tunnel_channel_handle_migrate_data(RedChannel *base,
|
||||
static uint64_t tunnel_channel_handle_migrate_data(RedChannelClient *rcc,
|
||||
uint32_t size, void *msg)
|
||||
{
|
||||
TunnelChannel *channel = SPICE_CONTAINEROF(base, TunnelChannel, base);
|
||||
TunnelChannel *channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
|
||||
TunnelMigrateSocketList *sockets_list;
|
||||
TunnelMigrateServicesList *services_list;
|
||||
TunnelMigrateData *migrate_data = msg;
|
||||
@ -2242,9 +2245,9 @@ error:
|
||||
}
|
||||
|
||||
// msg was allocated by tunnel_channel_alloc_msg_rcv_buf
|
||||
static int tunnel_channel_handle_message(RedChannel *channel, SpiceDataHeader *header, uint8_t *msg)
|
||||
static int tunnel_channel_handle_message(RedChannelClient *rcc, SpiceDataHeader *header, uint8_t *msg)
|
||||
{
|
||||
TunnelChannel *tunnel_channel = (TunnelChannel *)channel;
|
||||
TunnelChannel *tunnel_channel = (TunnelChannel *)rcc->channel;
|
||||
RedSocket *sckt = NULL;
|
||||
// retrieve the sckt
|
||||
switch (header->type) {
|
||||
@ -2268,7 +2271,7 @@ static int tunnel_channel_handle_message(RedChannel *channel, SpiceDataHeader *h
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return red_channel_handle_message(channel, header->size, header->type, msg);
|
||||
return red_channel_client_handle_message(rcc, header->size, header->type, msg);
|
||||
}
|
||||
|
||||
switch (header->type) {
|
||||
@ -2337,7 +2340,7 @@ static int tunnel_channel_handle_message(RedChannel *channel, SpiceDataHeader *h
|
||||
return tunnel_channel_handle_socket_token(tunnel_channel, sckt,
|
||||
(SpiceMsgcTunnelSocketTokens *)msg);
|
||||
default:
|
||||
return red_channel_handle_message(channel, header->size, header->type, msg);
|
||||
return red_channel_client_handle_message(rcc, header->size, header->type, msg);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@ -2346,13 +2349,16 @@ static int tunnel_channel_handle_message(RedChannel *channel, SpiceDataHeader *h
|
||||
/* outgoing msgs
|
||||
********************************/
|
||||
|
||||
static void tunnel_channel_marshall_migrate(TunnelChannel *tunnel_channel, SpiceMarshaller *m, PipeItem *item)
|
||||
static void tunnel_channel_marshall_migrate(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
|
||||
{
|
||||
ASSERT(tunnel_channel);
|
||||
TunnelChannel *tunnel_channel;
|
||||
|
||||
ASSERT(rcc);
|
||||
tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
|
||||
tunnel_channel->send_data.u.migrate.flags =
|
||||
SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
|
||||
tunnel_channel->expect_migrate_mark = TRUE;
|
||||
red_channel_init_send_data(&tunnel_channel->base, SPICE_MSG_MIGRATE, item);
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE, item);
|
||||
spice_marshaller_add_ref(m,
|
||||
(uint8_t*)&tunnel_channel->send_data.u.migrate,
|
||||
sizeof(SpiceMsgMigrate));
|
||||
@ -2492,20 +2498,23 @@ static int __tunnel_channel_marshall_socket_migrate_data(TunnelChannel *channel,
|
||||
return (cur_offset - offset);
|
||||
}
|
||||
|
||||
static void tunnel_channel_marshall_migrate_data(TunnelChannel *channel,
|
||||
static void tunnel_channel_marshall_migrate_data(RedChannelClient *rcc,
|
||||
SpiceMarshaller *m, PipeItem *item)
|
||||
{
|
||||
TunnelMigrateData *migrate_data = &channel->send_data.u.migrate_data;
|
||||
TunnelChannel *tunnel_channel;
|
||||
TunnelMigrateData *migrate_data;
|
||||
TunnelMigrateItem *migrate_item = (TunnelMigrateItem *)item;
|
||||
int i;
|
||||
|
||||
uint32_t data_buf_offset = 0; // current location in data[0] field
|
||||
ASSERT(channel);
|
||||
ASSERT(rcc);
|
||||
tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
|
||||
migrate_data = &tunnel_channel->send_data.u.migrate_data;
|
||||
|
||||
migrate_data->magic = TUNNEL_MIGRATE_DATA_MAGIC;
|
||||
migrate_data->version = TUNNEL_MIGRATE_DATA_VERSION;
|
||||
migrate_data->message_serial = red_channel_get_message_serial(&channel->base);
|
||||
red_channel_init_send_data(&channel->base, SPICE_MSG_MIGRATE_DATA, item);
|
||||
migrate_data->message_serial = red_channel_client_get_message_serial(rcc);
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)migrate_data, sizeof(*migrate_data));
|
||||
|
||||
migrate_data->slirp_state = data_buf_offset;
|
||||
@ -2519,7 +2528,7 @@ static void tunnel_channel_marshall_migrate_data(TunnelChannel *channel,
|
||||
|
||||
for (i = 0; i < migrate_item->services_list->num_services; i++) {
|
||||
migrate_item->services_list->services[i] = data_buf_offset;
|
||||
data_buf_offset += __tunnel_channel_marshall_service_migrate_data(channel, m,
|
||||
data_buf_offset += __tunnel_channel_marshall_service_migrate_data(tunnel_channel, m,
|
||||
migrate_item->services + i,
|
||||
data_buf_offset);
|
||||
}
|
||||
@ -2532,83 +2541,93 @@ static void tunnel_channel_marshall_migrate_data(TunnelChannel *channel,
|
||||
|
||||
for (i = 0; i < migrate_item->sockets_list->num_sockets; i++) {
|
||||
migrate_item->sockets_list->sockets[i] = data_buf_offset;
|
||||
data_buf_offset += __tunnel_channel_marshall_socket_migrate_data(channel, m,
|
||||
data_buf_offset += __tunnel_channel_marshall_socket_migrate_data(tunnel_channel, m,
|
||||
migrate_item->sockets_data + i,
|
||||
data_buf_offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void tunnel_channel_marshall_init(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
|
||||
static void tunnel_channel_marshall_init(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
|
||||
{
|
||||
ASSERT(channel);
|
||||
TunnelChannel *channel;
|
||||
|
||||
ASSERT(rcc);
|
||||
channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
|
||||
channel->send_data.u.init.max_socket_data_size = MAX_SOCKET_DATA_SIZE;
|
||||
channel->send_data.u.init.max_num_of_sockets = MAX_SOCKETS_NUM;
|
||||
|
||||
red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_INIT, item);
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_INIT, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.init, sizeof(SpiceMsgTunnelInit));
|
||||
}
|
||||
|
||||
static void tunnel_channel_marshall_service_ip_map(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
|
||||
static void tunnel_channel_marshall_service_ip_map(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
|
||||
{
|
||||
TunnelChannel *tunnel_channel;
|
||||
TunnelService *service = SPICE_CONTAINEROF(item, TunnelService, pipe_item);
|
||||
|
||||
channel->send_data.u.service_ip.service_id = service->id;
|
||||
channel->send_data.u.service_ip.virtual_ip.type = SPICE_TUNNEL_IP_TYPE_IPv4;
|
||||
tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
|
||||
tunnel_channel->send_data.u.service_ip.service_id = service->id;
|
||||
tunnel_channel->send_data.u.service_ip.virtual_ip.type = SPICE_TUNNEL_IP_TYPE_IPv4;
|
||||
|
||||
red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SERVICE_IP_MAP, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.service_ip,
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SERVICE_IP_MAP, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.service_ip,
|
||||
sizeof(SpiceMsgTunnelServiceIpMap));
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&service->virt_ip.s_addr, sizeof(SpiceTunnelIPv4));
|
||||
}
|
||||
|
||||
static void tunnel_channel_marshall_socket_open(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
|
||||
static void tunnel_channel_marshall_socket_open(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
|
||||
{
|
||||
TunnelChannel *tunnel_channel;
|
||||
RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, status_pipe_item);
|
||||
RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
|
||||
|
||||
channel->send_data.u.socket_open.connection_id = sckt->connection_id;
|
||||
channel->send_data.u.socket_open.service_id = sckt->far_service->id;
|
||||
channel->send_data.u.socket_open.tokens = SOCKET_WINDOW_SIZE;
|
||||
tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
|
||||
tunnel_channel->send_data.u.socket_open.connection_id = sckt->connection_id;
|
||||
tunnel_channel->send_data.u.socket_open.service_id = sckt->far_service->id;
|
||||
tunnel_channel->send_data.u.socket_open.tokens = SOCKET_WINDOW_SIZE;
|
||||
|
||||
sckt->in_data.client_total_num_tokens = SOCKET_WINDOW_SIZE;
|
||||
sckt->in_data.num_tokens = 0;
|
||||
red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_OPEN, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_open,
|
||||
sizeof(channel->send_data.u.socket_open));
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_OPEN, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.socket_open,
|
||||
sizeof(tunnel_channel->send_data.u.socket_open));
|
||||
#ifdef DEBUG_NETWORK
|
||||
PRINT_SCKT(sckt);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void tunnel_channel_marshall_socket_fin(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
|
||||
static void tunnel_channel_marshall_socket_fin(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
|
||||
{
|
||||
TunnelChannel *tunnel_channel;
|
||||
RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, status_pipe_item);
|
||||
RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
|
||||
|
||||
ASSERT(!sckt->out_data.ready_chunks_queue.head);
|
||||
|
||||
tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
|
||||
if (sckt->out_data.process_queue->head) {
|
||||
red_printf("socket sent FIN but there are still buffers in outgoing process queue"
|
||||
"(local_port=%d, service_id=%d)",
|
||||
ntohs(sckt->local_port), sckt->far_service->id);
|
||||
}
|
||||
|
||||
channel->send_data.u.socket_fin.connection_id = sckt->connection_id;
|
||||
tunnel_channel->send_data.u.socket_fin.connection_id = sckt->connection_id;
|
||||
|
||||
red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_FIN, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_fin,
|
||||
sizeof(channel->send_data.u.socket_fin));
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_FIN, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.socket_fin,
|
||||
sizeof(tunnel_channel->send_data.u.socket_fin));
|
||||
#ifdef DEBUG_NETWORK
|
||||
PRINT_SCKT(sckt);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void tunnel_channel_marshall_socket_close(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
|
||||
static void tunnel_channel_marshall_socket_close(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
|
||||
{
|
||||
TunnelChannel *tunnel_channel;
|
||||
RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, status_pipe_item);
|
||||
RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
|
||||
|
||||
tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
|
||||
// can happen when it is a forced close
|
||||
if (sckt->out_data.ready_chunks_queue.head) {
|
||||
red_printf("socket closed but there are still buffers in outgoing ready queue"
|
||||
@ -2623,65 +2642,71 @@ static void tunnel_channel_marshall_socket_close(TunnelChannel *channel, SpiceMa
|
||||
ntohs(sckt->local_port), sckt->far_service->id);
|
||||
}
|
||||
|
||||
channel->send_data.u.socket_close.connection_id = sckt->connection_id;
|
||||
tunnel_channel->send_data.u.socket_close.connection_id = sckt->connection_id;
|
||||
|
||||
red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_CLOSE, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_close,
|
||||
sizeof(channel->send_data.u.socket_close));
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_CLOSE, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.socket_close,
|
||||
sizeof(tunnel_channel->send_data.u.socket_close));
|
||||
#ifdef DEBUG_NETWORK
|
||||
PRINT_SCKT(sckt);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void tunnel_channel_marshall_socket_closed_ack(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
|
||||
static void tunnel_channel_marshall_socket_closed_ack(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
|
||||
{
|
||||
TunnelChannel *tunnel_channel;
|
||||
RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, status_pipe_item);
|
||||
RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
|
||||
|
||||
channel->send_data.u.socket_close_ack.connection_id = sckt->connection_id;
|
||||
tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
|
||||
tunnel_channel->send_data.u.socket_close_ack.connection_id = sckt->connection_id;
|
||||
|
||||
// pipe item is null because we free the sckt.
|
||||
red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_CLOSED_ACK, NULL);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_close_ack,
|
||||
sizeof(channel->send_data.u.socket_close_ack));
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_CLOSED_ACK, NULL);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.socket_close_ack,
|
||||
sizeof(tunnel_channel->send_data.u.socket_close_ack));
|
||||
#ifdef DEBUG_NETWORK
|
||||
PRINT_SCKT(sckt);
|
||||
#endif
|
||||
|
||||
ASSERT(sckt->client_waits_close_ack && (sckt->client_status == CLIENT_SCKT_STATUS_CLOSED));
|
||||
tunnel_worker_free_socket(channel->worker, sckt);
|
||||
if (CHECK_TUNNEL_ERROR(channel)) {
|
||||
tunnel_shutdown(channel->worker);
|
||||
tunnel_worker_free_socket(tunnel_channel->worker, sckt);
|
||||
if (CHECK_TUNNEL_ERROR(tunnel_channel)) {
|
||||
tunnel_shutdown(tunnel_channel->worker);
|
||||
}
|
||||
}
|
||||
|
||||
static void tunnel_channel_marshall_socket_token(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
|
||||
static void tunnel_channel_marshall_socket_token(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
|
||||
{
|
||||
TunnelChannel *tunnel_channel;
|
||||
RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, token_pipe_item);
|
||||
RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
|
||||
|
||||
/* notice that the num of tokens sent can be > SOCKET_TOKENS_TO_SEND, since
|
||||
the sending is performed after the pipe item was pushed */
|
||||
|
||||
channel->send_data.u.socket_token.connection_id = sckt->connection_id;
|
||||
tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
|
||||
tunnel_channel->send_data.u.socket_token.connection_id = sckt->connection_id;
|
||||
|
||||
if (sckt->in_data.num_tokens > 0) {
|
||||
channel->send_data.u.socket_token.num_tokens = sckt->in_data.num_tokens;
|
||||
tunnel_channel->send_data.u.socket_token.num_tokens = sckt->in_data.num_tokens;
|
||||
} else {
|
||||
ASSERT(!sckt->in_data.client_total_num_tokens && !sckt->in_data.ready_chunks_queue.head);
|
||||
channel->send_data.u.socket_token.num_tokens = SOCKET_TOKENS_TO_SEND_FOR_PROCESS;
|
||||
tunnel_channel->send_data.u.socket_token.num_tokens = SOCKET_TOKENS_TO_SEND_FOR_PROCESS;
|
||||
}
|
||||
sckt->in_data.num_tokens -= channel->send_data.u.socket_token.num_tokens;
|
||||
sckt->in_data.client_total_num_tokens += channel->send_data.u.socket_token.num_tokens;
|
||||
sckt->in_data.num_tokens -= tunnel_channel->send_data.u.socket_token.num_tokens;
|
||||
sckt->in_data.client_total_num_tokens += tunnel_channel->send_data.u.socket_token.num_tokens;
|
||||
ASSERT(sckt->in_data.client_total_num_tokens <= SOCKET_WINDOW_SIZE);
|
||||
|
||||
red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_TOKEN, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_token,
|
||||
sizeof(channel->send_data.u.socket_token));
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_TOKEN, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.socket_token,
|
||||
sizeof(tunnel_channel->send_data.u.socket_token));
|
||||
}
|
||||
|
||||
static void tunnel_channel_marshall_socket_out_data(TunnelChannel *channel, SpiceMarshaller *m, PipeItem *item)
|
||||
static void tunnel_channel_marshall_socket_out_data(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
|
||||
{
|
||||
TunnelChannel *tunnel_channel;
|
||||
tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannel, base);
|
||||
RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item, RedSocketOutData, data_pipe_item);
|
||||
RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
|
||||
ReadyTunneledChunk *chunk;
|
||||
@ -2701,11 +2726,11 @@ static void tunnel_channel_marshall_socket_out_data(TunnelChannel *channel, Spic
|
||||
ASSERT(!sckt->out_data.push_tail);
|
||||
ASSERT(sckt->out_data.ready_chunks_queue.head->size <= MAX_SOCKET_DATA_SIZE);
|
||||
|
||||
channel->send_data.u.socket_data.connection_id = sckt->connection_id;
|
||||
tunnel_channel->send_data.u.socket_data.connection_id = sckt->connection_id;
|
||||
|
||||
red_channel_init_send_data(&channel->base, SPICE_MSG_TUNNEL_SOCKET_DATA, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.socket_data,
|
||||
sizeof(channel->send_data.u.socket_data));
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_DATA, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)&tunnel_channel->send_data.u.socket_data,
|
||||
sizeof(tunnel_channel->send_data.u.socket_data));
|
||||
pushed_bufs_num++;
|
||||
|
||||
// the first chunk is in a valid size
|
||||
@ -2790,52 +2815,51 @@ static void tunnel_worker_release_socket_out_data(TunnelWorker *worker, PipeItem
|
||||
}
|
||||
}
|
||||
|
||||
static void tunnel_channel_send_item(RedChannel *channel, PipeItem *item)
|
||||
static void tunnel_channel_send_item(RedChannelClient *rcc, PipeItem *item)
|
||||
{
|
||||
TunnelChannel *tunnel_channel = (TunnelChannel *)channel;
|
||||
SpiceMarshaller *m = red_channel_get_marshaller(channel);
|
||||
SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
|
||||
|
||||
switch (item->type) {
|
||||
case PIPE_ITEM_TYPE_TUNNEL_INIT:
|
||||
tunnel_channel_marshall_init(tunnel_channel, m, item);
|
||||
tunnel_channel_marshall_init(rcc, m, item);
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_SERVICE_IP_MAP:
|
||||
tunnel_channel_marshall_service_ip_map(tunnel_channel, m, item);
|
||||
tunnel_channel_marshall_service_ip_map(rcc, m, item);
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_SOCKET_OPEN:
|
||||
tunnel_channel_marshall_socket_open(tunnel_channel, m, item);
|
||||
tunnel_channel_marshall_socket_open(rcc, m, item);
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_SOCKET_DATA:
|
||||
tunnel_channel_marshall_socket_out_data(tunnel_channel, m, item);
|
||||
tunnel_channel_marshall_socket_out_data(rcc, m, item);
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_SOCKET_FIN:
|
||||
tunnel_channel_marshall_socket_fin(tunnel_channel, m, item);
|
||||
tunnel_channel_marshall_socket_fin(rcc, m, item);
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_SOCKET_CLOSE:
|
||||
tunnel_channel_marshall_socket_close(tunnel_channel, m, item);
|
||||
tunnel_channel_marshall_socket_close(rcc, m, item);
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_SOCKET_CLOSED_ACK:
|
||||
tunnel_channel_marshall_socket_closed_ack(tunnel_channel, m, item);
|
||||
tunnel_channel_marshall_socket_closed_ack(rcc, m, item);
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_SOCKET_TOKEN:
|
||||
tunnel_channel_marshall_socket_token(tunnel_channel, m, item);
|
||||
tunnel_channel_marshall_socket_token(rcc, m, item);
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_MIGRATE:
|
||||
tunnel_channel_marshall_migrate(tunnel_channel, m, item);
|
||||
tunnel_channel_marshall_migrate(rcc, m, item);
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_MIGRATE_DATA:
|
||||
tunnel_channel_marshall_migrate_data(tunnel_channel, m, item);
|
||||
tunnel_channel_marshall_migrate_data(rcc, m, item);
|
||||
break;
|
||||
default:
|
||||
red_error("invalid pipe item type");
|
||||
}
|
||||
red_channel_begin_send_message(channel);
|
||||
red_channel_client_begin_send_message(rcc);
|
||||
}
|
||||
|
||||
/* param item_pushed: distinguishes between a pipe item that was pushed for sending, and
|
||||
a pipe item that is still in the pipe and is released due to disconnection.
|
||||
see red_pipe_item_clear */
|
||||
static void tunnel_channel_release_pipe_item(RedChannel *channel, PipeItem *item, int item_pushed)
|
||||
static void tunnel_channel_release_pipe_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
|
||||
{
|
||||
if (!item) { // e.g. when acking closed socket
|
||||
return;
|
||||
@ -2852,7 +2876,7 @@ static void tunnel_channel_release_pipe_item(RedChannel *channel, PipeItem *item
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_SOCKET_DATA:
|
||||
if (item_pushed) {
|
||||
tunnel_worker_release_socket_out_data(((TunnelChannel *)channel)->worker, item);
|
||||
tunnel_worker_release_socket_out_data(((TunnelChannel *)rcc->channel)->worker, item);
|
||||
}
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_MIGRATE:
|
||||
@ -3321,11 +3345,11 @@ static void arm_timer(SlirpUsrNetworkInterface *usr_interface, UserTimer *timer,
|
||||
* channel interface and other related procedures
|
||||
************************************************/
|
||||
|
||||
static int tunnel_channel_config_socket(RedChannel *channel)
|
||||
static int tunnel_channel_config_socket(RedChannelClient *rcc)
|
||||
{
|
||||
int flags;
|
||||
int delay_val;
|
||||
RedsStream *stream = red_channel_get_stream(channel);
|
||||
RedsStream *stream = red_channel_client_get_stream(rcc);
|
||||
|
||||
if ((flags = fcntl(stream->socket, F_GETFL)) == -1) {
|
||||
red_printf("accept failed, %s", strerror(errno)); // can't we just use red_error?
|
||||
@ -3386,6 +3410,12 @@ static void tunnel_channel_disconnect(RedChannel *channel)
|
||||
worker->channel = NULL;
|
||||
}
|
||||
|
||||
// TODO - not MC friendly, remove
|
||||
static void tunnel_channel_disconnect_client(RedChannelClient *rcc)
|
||||
{
|
||||
tunnel_channel_disconnect(rcc->channel);
|
||||
}
|
||||
|
||||
/* interface for reds */
|
||||
|
||||
static void on_new_tunnel_channel(TunnelChannel *channel)
|
||||
@ -3400,7 +3430,7 @@ static void on_new_tunnel_channel(TunnelChannel *channel)
|
||||
}
|
||||
}
|
||||
|
||||
static void tunnel_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
|
||||
static void tunnel_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
|
||||
{
|
||||
}
|
||||
|
||||
@ -3415,10 +3445,10 @@ static void handle_tunnel_channel_link(Channel *channel, RedsStream *stream, int
|
||||
}
|
||||
|
||||
tunnel_channel =
|
||||
(TunnelChannel *)red_channel_create(sizeof(*tunnel_channel), stream, worker->core_interface,
|
||||
(TunnelChannel *)red_channel_create(sizeof(*tunnel_channel), worker->core_interface,
|
||||
migration, TRUE,
|
||||
tunnel_channel_config_socket,
|
||||
tunnel_channel_disconnect,
|
||||
tunnel_channel_disconnect_client,
|
||||
tunnel_channel_handle_message,
|
||||
tunnel_channel_alloc_msg_rcv_buf,
|
||||
tunnel_channel_release_msg_rcv_buf,
|
||||
@ -3432,7 +3462,7 @@ static void handle_tunnel_channel_link(Channel *channel, RedsStream *stream, int
|
||||
if (!tunnel_channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
red_channel_client_create(sizeof(RedChannelClient), &tunnel_channel->base, stream);
|
||||
|
||||
tunnel_channel->worker = worker;
|
||||
tunnel_channel->worker->channel = tunnel_channel;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -36,6 +36,7 @@ typedef struct SmartCardDeviceState {
|
||||
uint32_t buf_size;
|
||||
uint8_t *buf_pos;
|
||||
uint32_t buf_used;
|
||||
RedChannelClient *rcc; // client providing the remote card
|
||||
} SmartCardDeviceState;
|
||||
|
||||
enum {
|
||||
@ -58,8 +59,6 @@ typedef struct SmartCardChannel {
|
||||
RedChannel base;
|
||||
} SmartCardChannel;
|
||||
|
||||
static SmartCardChannel *g_smartcard_channel = NULL;
|
||||
|
||||
static struct Readers {
|
||||
uint32_t num;
|
||||
SpiceCharDeviceInstance* sin[SMARTCARD_MAX_READERS];
|
||||
@ -69,16 +68,14 @@ static SpiceCharDeviceInstance* smartcard_readers_get_unattached();
|
||||
static SpiceCharDeviceInstance* smartcard_readers_get(uint32_t reader_id);
|
||||
static int smartcard_char_device_add_to_readers(SpiceCharDeviceInstance *sin);
|
||||
static void smartcard_char_device_attach(
|
||||
SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel);
|
||||
static void smartcard_char_device_detach(
|
||||
SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel);
|
||||
static void smartcard_channel_write_to_reader(
|
||||
SmartCardChannel *smartcard_channel, VSCMsgHeader *vheader);
|
||||
SpiceCharDeviceInstance *char_device, RedChannelClient *rcc);
|
||||
static void smartcard_char_device_detach(SpiceCharDeviceInstance *char_device);
|
||||
static void smartcard_channel_write_to_reader(VSCMsgHeader *vheader);
|
||||
|
||||
static void smartcard_char_device_on_message_from_device(
|
||||
SmartCardDeviceState *state, VSCMsgHeader *header);
|
||||
static void smartcard_on_message_from_device(
|
||||
SmartCardChannel *smartcard_channel, VSCMsgHeader *vheader);
|
||||
RedChannelClient *rcc, VSCMsgHeader *vheader);
|
||||
static SmartCardDeviceState* smartcard_device_state_new();
|
||||
static void smartcard_device_state_free(SmartCardDeviceState* st);
|
||||
static void smartcard_register_channel(void);
|
||||
@ -139,12 +136,13 @@ void smartcard_char_device_on_message_from_device(
|
||||
if (state->reader_id == VSCARD_UNDEFINED_READER_ID && vheader->type != VSC_Init) {
|
||||
red_printf("error: reader_id not assigned for message of type %d", vheader->type);
|
||||
}
|
||||
ASSERT(g_smartcard_channel != NULL);
|
||||
sent_header = spice_memdup(vheader, sizeof(*vheader) + vheader->length);
|
||||
/* We patch the reader_id, since the device only knows about itself, and
|
||||
* we know about the sum of readers. */
|
||||
sent_header->reader_id = state->reader_id;
|
||||
smartcard_on_message_from_device(g_smartcard_channel, sent_header);
|
||||
if (state->rcc) {
|
||||
smartcard_on_message_from_device(state->rcc, sent_header);
|
||||
}
|
||||
}
|
||||
|
||||
static void smartcard_readers_detach_all(SmartCardChannel *smartcard_channel)
|
||||
@ -152,8 +150,7 @@ static void smartcard_readers_detach_all(SmartCardChannel *smartcard_channel)
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < g_smartcard_readers.num; ++i) {
|
||||
smartcard_char_device_detach(g_smartcard_readers.sin[i],
|
||||
smartcard_channel);
|
||||
smartcard_char_device_detach(g_smartcard_readers.sin[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -204,6 +201,7 @@ static SmartCardDeviceState* smartcard_device_state_new()
|
||||
st->buf = spice_malloc(st->buf_size);
|
||||
st->buf_pos = st->buf;
|
||||
st->buf_used = 0;
|
||||
st->rcc = NULL;
|
||||
return st;
|
||||
}
|
||||
|
||||
@ -235,7 +233,7 @@ int smartcard_device_connect(SpiceCharDeviceInstance *char_device)
|
||||
}
|
||||
|
||||
static void smartcard_char_device_attach(
|
||||
SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel)
|
||||
SpiceCharDeviceInstance *char_device, RedChannelClient *rcc)
|
||||
{
|
||||
SmartCardDeviceState *st = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base);
|
||||
|
||||
@ -243,13 +241,13 @@ static void smartcard_char_device_attach(
|
||||
return;
|
||||
}
|
||||
st->attached = TRUE;
|
||||
st->rcc = rcc;
|
||||
VSCMsgHeader vheader = {.type = VSC_ReaderAdd, .reader_id=st->reader_id,
|
||||
.length=0};
|
||||
smartcard_channel_write_to_reader(smartcard_channel, &vheader);
|
||||
smartcard_channel_write_to_reader(&vheader);
|
||||
}
|
||||
|
||||
static void smartcard_char_device_detach(
|
||||
SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel)
|
||||
static void smartcard_char_device_detach(SpiceCharDeviceInstance *char_device)
|
||||
{
|
||||
SmartCardDeviceState *st = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base);
|
||||
|
||||
@ -257,75 +255,75 @@ static void smartcard_char_device_detach(
|
||||
return;
|
||||
}
|
||||
st->attached = FALSE;
|
||||
st->rcc = NULL;
|
||||
VSCMsgHeader vheader = {.type = VSC_ReaderRemove, .reader_id=st->reader_id,
|
||||
.length=0};
|
||||
smartcard_channel_write_to_reader(smartcard_channel, &vheader);
|
||||
smartcard_channel_write_to_reader(&vheader);
|
||||
}
|
||||
|
||||
static int smartcard_channel_config_socket(RedChannel *channel)
|
||||
static int smartcard_channel_config_socket(RedChannelClient *rcc)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static uint8_t *smartcard_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header)
|
||||
static uint8_t *smartcard_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
|
||||
SpiceDataHeader *msg_header)
|
||||
{
|
||||
//red_printf("allocing %d bytes", msg_header->size);
|
||||
return spice_malloc(msg_header->size);
|
||||
}
|
||||
|
||||
static void smartcard_channel_release_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header,
|
||||
uint8_t *msg)
|
||||
static void smartcard_channel_release_msg_rcv_buf(RedChannelClient *rcc,
|
||||
SpiceDataHeader *msg_header, uint8_t *msg)
|
||||
{
|
||||
red_printf("freeing %d bytes", msg_header->size);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
static void smartcard_channel_send_data(RedChannel *channel, SpiceMarshaller *m,
|
||||
static void smartcard_channel_send_data(RedChannelClient *rcc, SpiceMarshaller *m,
|
||||
PipeItem *item, VSCMsgHeader *vheader)
|
||||
{
|
||||
ASSERT(channel);
|
||||
ASSERT(rcc);
|
||||
ASSERT(vheader);
|
||||
red_channel_init_send_data(channel, SPICE_MSG_SMARTCARD_DATA, item);
|
||||
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_SMARTCARD_DATA, item);
|
||||
spice_marshaller_add_ref(m, (uint8_t*)vheader, sizeof(VSCMsgHeader));
|
||||
if (vheader->length > 0) {
|
||||
spice_marshaller_add_ref(m, (uint8_t*)(vheader+1), vheader->length);
|
||||
}
|
||||
red_channel_begin_send_message(channel);
|
||||
red_channel_client_begin_send_message(rcc);
|
||||
}
|
||||
|
||||
static void smartcard_channel_send_error(
|
||||
SmartCardChannel *smartcard_channel, SpiceMarshaller *m, PipeItem *item)
|
||||
RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item)
|
||||
{
|
||||
ErrorItem* error_item = (ErrorItem*)item;
|
||||
|
||||
smartcard_channel_send_data(&smartcard_channel->base, m, item, &error_item->vheader);
|
||||
smartcard_channel_send_data(rcc, m, item, &error_item->vheader);
|
||||
}
|
||||
|
||||
static void smartcard_channel_send_msg(
|
||||
SmartCardChannel *smartcard_channel, SpiceMarshaller *m, PipeItem *item)
|
||||
static void smartcard_channel_send_msg(RedChannelClient *rcc,
|
||||
SpiceMarshaller *m, PipeItem *item)
|
||||
{
|
||||
MsgItem* msg_item = (MsgItem*)item;
|
||||
|
||||
smartcard_channel_send_data(&smartcard_channel->base, m, item, msg_item->vheader);
|
||||
smartcard_channel_send_data(rcc, m, item, msg_item->vheader);
|
||||
}
|
||||
|
||||
static void smartcard_channel_send_item(RedChannel *channel, PipeItem *item)
|
||||
static void smartcard_channel_send_item(RedChannelClient *rcc, PipeItem *item)
|
||||
{
|
||||
SmartCardChannel *smartcard_channel = (SmartCardChannel *)channel;
|
||||
SpiceMarshaller *m = red_channel_get_marshaller(channel);
|
||||
SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
|
||||
|
||||
switch (item->type) {
|
||||
case PIPE_ITEM_TYPE_ERROR:
|
||||
smartcard_channel_send_error(smartcard_channel, m, item);
|
||||
smartcard_channel_send_error(rcc, m, item);
|
||||
break;
|
||||
case PIPE_ITEM_TYPE_MSG:
|
||||
smartcard_channel_send_msg(smartcard_channel, m, item);
|
||||
smartcard_channel_send_msg(rcc, m, item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void smartcard_channel_release_pipe_item(RedChannel *channel, PipeItem *item, int item_pushed)
|
||||
static void smartcard_channel_release_pipe_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
|
||||
{
|
||||
if (item->type == PIPE_ITEM_TYPE_MSG) {
|
||||
free(((MsgItem*)item)->vheader);
|
||||
@ -333,22 +331,21 @@ static void smartcard_channel_release_pipe_item(RedChannel *channel, PipeItem *i
|
||||
free(item);
|
||||
}
|
||||
|
||||
static void smartcard_channel_disconnect(RedChannel *channel)
|
||||
static void smartcard_channel_disconnect(RedChannelClient *rcc)
|
||||
{
|
||||
smartcard_readers_detach_all((SmartCardChannel*)channel);
|
||||
red_channel_destroy(channel);
|
||||
g_smartcard_channel = NULL;
|
||||
smartcard_readers_detach_all((SmartCardChannel*)(rcc->channel));
|
||||
red_channel_client_destroy(rcc);
|
||||
}
|
||||
|
||||
/* this is called from both device input and client input. since the device is
|
||||
* a usb device, the context is still the main thread (kvm_main_loop, timers)
|
||||
* so no mutex is required. */
|
||||
static void smartcard_channel_pipe_add_push(SmartCardChannel *channel, PipeItem *item)
|
||||
static void smartcard_channel_pipe_add_push(RedChannelClient *rcc, PipeItem *item)
|
||||
{
|
||||
red_channel_pipe_add_push(&channel->base, item);
|
||||
red_channel_pipe_add_push(rcc->channel, item);
|
||||
}
|
||||
|
||||
static void smartcard_push_error(SmartCardChannel* channel, uint32_t reader_id, VSCErrorCode error)
|
||||
static void smartcard_push_error(RedChannelClient *rcc, uint32_t reader_id, VSCErrorCode error)
|
||||
{
|
||||
ErrorItem *error_item = spice_new0(ErrorItem, 1);
|
||||
|
||||
@ -357,63 +354,61 @@ static void smartcard_push_error(SmartCardChannel* channel, uint32_t reader_id,
|
||||
error_item->vheader.type = VSC_Error;
|
||||
error_item->vheader.length = sizeof(error_item->error);
|
||||
error_item->error.code = error;
|
||||
smartcard_channel_pipe_add_push(channel, &error_item->base);
|
||||
smartcard_channel_pipe_add_push(rcc, &error_item->base);
|
||||
}
|
||||
|
||||
static void smartcard_push_vscmsg(SmartCardChannel *channel, VSCMsgHeader *vheader)
|
||||
static void smartcard_push_vscmsg(RedChannelClient *rcc, VSCMsgHeader *vheader)
|
||||
{
|
||||
MsgItem *msg_item = spice_new0(MsgItem, 1);
|
||||
|
||||
msg_item->base.type = PIPE_ITEM_TYPE_MSG;
|
||||
msg_item->vheader = vheader;
|
||||
smartcard_channel_pipe_add_push(channel, &msg_item->base);
|
||||
smartcard_channel_pipe_add_push(rcc, &msg_item->base);
|
||||
}
|
||||
|
||||
void smartcard_on_message_from_device(SmartCardChannel *smartcard_channel,
|
||||
VSCMsgHeader* vheader)
|
||||
void smartcard_on_message_from_device(RedChannelClient *rcc, VSCMsgHeader* vheader)
|
||||
{
|
||||
smartcard_push_vscmsg(smartcard_channel, vheader);
|
||||
smartcard_push_vscmsg(rcc, vheader);
|
||||
}
|
||||
|
||||
static void smartcard_remove_reader(SmartCardChannel *smartcard_channel, uint32_t reader_id)
|
||||
static void smartcard_remove_reader(RedChannelClient *rcc, uint32_t reader_id)
|
||||
{
|
||||
SpiceCharDeviceInstance *char_device = smartcard_readers_get(reader_id);
|
||||
SmartCardDeviceState *state;
|
||||
|
||||
if (char_device == NULL) {
|
||||
smartcard_push_error(smartcard_channel, reader_id,
|
||||
smartcard_push_error(rcc, reader_id,
|
||||
VSC_GENERAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
state = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base);
|
||||
if (state->attached == FALSE) {
|
||||
smartcard_push_error(smartcard_channel, reader_id,
|
||||
smartcard_push_error(rcc, reader_id,
|
||||
VSC_GENERAL_ERROR);
|
||||
return;
|
||||
}
|
||||
smartcard_char_device_detach(char_device, smartcard_channel);
|
||||
smartcard_char_device_detach(char_device);
|
||||
}
|
||||
|
||||
static void smartcard_add_reader(SmartCardChannel *smartcard_channel, uint8_t *name)
|
||||
static void smartcard_add_reader(RedChannelClient *rcc, uint8_t *name)
|
||||
{
|
||||
// TODO - save name somewhere
|
||||
SpiceCharDeviceInstance *char_device =
|
||||
smartcard_readers_get_unattached();
|
||||
|
||||
if (char_device != NULL) {
|
||||
smartcard_char_device_attach(char_device, smartcard_channel);
|
||||
smartcard_char_device_attach(char_device, rcc);
|
||||
// The device sends a VSC_Error message, we will let it through, no
|
||||
// need to send our own. We already set the correct reader_id, from
|
||||
// our SmartCardDeviceState.
|
||||
} else {
|
||||
smartcard_push_error(smartcard_channel, VSCARD_UNDEFINED_READER_ID,
|
||||
smartcard_push_error(rcc, VSCARD_UNDEFINED_READER_ID,
|
||||
VSC_CANNOT_ADD_MORE_READERS);
|
||||
}
|
||||
}
|
||||
|
||||
static void smartcard_channel_write_to_reader(
|
||||
SmartCardChannel *smartcard_channel, VSCMsgHeader *vheader)
|
||||
static void smartcard_channel_write_to_reader(VSCMsgHeader *vheader)
|
||||
{
|
||||
SpiceCharDeviceInstance *sin;
|
||||
SpiceCharDeviceInterface *sif;
|
||||
@ -434,25 +429,25 @@ static void smartcard_channel_write_to_reader(
|
||||
ASSERT(n == actual_length + sizeof(VSCMsgHeader));
|
||||
}
|
||||
|
||||
static int smartcard_channel_handle_message(RedChannel *channel, SpiceDataHeader *header, uint8_t *msg)
|
||||
static int smartcard_channel_handle_message(RedChannelClient *rcc,
|
||||
SpiceDataHeader *header,
|
||||
uint8_t *msg)
|
||||
{
|
||||
VSCMsgHeader* vheader = (VSCMsgHeader*)msg;
|
||||
SmartCardChannel* smartcard_channel = (SmartCardChannel*)channel;
|
||||
|
||||
if (header->type != SPICE_MSGC_SMARTCARD_DATA) {
|
||||
/* handle ack's, spicy sends them while spicec does not */
|
||||
return red_channel_handle_message(channel, header->size, header->type,
|
||||
msg);
|
||||
return red_channel_client_handle_message(rcc, header->size, header->type, msg);
|
||||
}
|
||||
|
||||
ASSERT(header->size == vheader->length + sizeof(VSCMsgHeader));
|
||||
switch (vheader->type) {
|
||||
case VSC_ReaderAdd:
|
||||
smartcard_add_reader(smartcard_channel, msg + sizeof(VSCMsgHeader));
|
||||
smartcard_add_reader(rcc, msg + sizeof(VSCMsgHeader));
|
||||
return TRUE;
|
||||
break;
|
||||
case VSC_ReaderRemove:
|
||||
smartcard_remove_reader(smartcard_channel, vheader->reader_id);
|
||||
smartcard_remove_reader(rcc, vheader->reader_id);
|
||||
return TRUE;
|
||||
break;
|
||||
case VSC_Init:
|
||||
@ -474,11 +469,11 @@ static int smartcard_channel_handle_message(RedChannel *channel, SpiceDataHeader
|
||||
vheader->type, vheader->length);
|
||||
return FALSE;
|
||||
}
|
||||
smartcard_channel_write_to_reader(smartcard_channel, vheader);
|
||||
smartcard_channel_write_to_reader(vheader);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void smartcard_channel_hold_pipe_item(RedChannel *channel, PipeItem *item)
|
||||
static void smartcard_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
|
||||
{
|
||||
}
|
||||
|
||||
@ -487,12 +482,13 @@ static void smartcard_link(Channel *channel, RedsStream *stream,
|
||||
uint32_t *common_caps, int num_caps,
|
||||
uint32_t *caps)
|
||||
{
|
||||
if (g_smartcard_channel) {
|
||||
red_channel_destroy(&g_smartcard_channel->base);
|
||||
if (channel->data) {
|
||||
red_channel_destroy((RedChannel*)channel->data);
|
||||
channel->data = NULL;
|
||||
}
|
||||
g_smartcard_channel =
|
||||
(SmartCardChannel *)red_channel_create(sizeof(*g_smartcard_channel),
|
||||
stream, core,
|
||||
if (!channel->data) {
|
||||
channel->data = red_channel_create(sizeof(SmartCardChannel),
|
||||
core,
|
||||
migration, FALSE /* handle_acks */,
|
||||
smartcard_channel_config_socket,
|
||||
smartcard_channel_disconnect,
|
||||
@ -505,10 +501,13 @@ static void smartcard_link(Channel *channel, RedsStream *stream,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
if (!g_smartcard_channel) {
|
||||
}
|
||||
if (!channel->data) {
|
||||
red_printf("ERROR: smartcard channel creation failed");
|
||||
return;
|
||||
}
|
||||
red_channel_init_outgoing_messages_window(&g_smartcard_channel->base);
|
||||
red_channel_client_create(sizeof(RedChannelClient), channel->data, stream);
|
||||
red_channel_init_outgoing_messages_window((RedChannel*)channel->data);
|
||||
}
|
||||
|
||||
static void smartcard_shutdown(Channel *channel)
|
||||
|
||||
@ -38,6 +38,7 @@ typedef struct UsbRedirPipeItem {
|
||||
typedef struct UsbRedirState {
|
||||
Channel channel;
|
||||
RedChannel *red_channel;
|
||||
RedChannelClient *rcc;
|
||||
SpiceCharDeviceState chardev_st;
|
||||
SpiceCharDeviceInstance *chardev_sin;
|
||||
UsbRedirPipeItem *pipe_item;
|
||||
@ -81,46 +82,46 @@ static void usbredir_chardev_wakeup(SpiceCharDeviceInstance *sin)
|
||||
} while (n > 0);
|
||||
}
|
||||
|
||||
static int usbredir_red_channel_config_socket(RedChannel *red_channel)
|
||||
static int usbredir_red_channel_config_socket(RedChannelClient *rcc)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void usbredir_red_channel_disconnect(RedChannel *red_channel)
|
||||
static void usbredir_red_channel_disconnect(RedChannelClient *rcc)
|
||||
{
|
||||
UsbRedirState *state;
|
||||
SpiceCharDeviceInstance *sin;
|
||||
SpiceCharDeviceInterface *sif;
|
||||
|
||||
if (!red_channel) {
|
||||
if (!rcc) {
|
||||
return;
|
||||
}
|
||||
|
||||
state = SPICE_CONTAINEROF(red_channel, UsbRedirChannel, base)->state;
|
||||
state = SPICE_CONTAINEROF(rcc->channel, UsbRedirChannel, base)->state;
|
||||
sin = state->chardev_sin;
|
||||
sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base);
|
||||
|
||||
red_channel_destroy(red_channel);
|
||||
state->red_channel = NULL;
|
||||
red_channel_client_destroy(rcc);
|
||||
state->rcc = NULL;
|
||||
if (sif->state) {
|
||||
sif->state(sin, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int usbredir_red_channel_handle_message(RedChannel *red_channel,
|
||||
static int usbredir_red_channel_client_handle_message(RedChannelClient *rcc,
|
||||
SpiceDataHeader *header, uint8_t *msg)
|
||||
{
|
||||
UsbRedirState *state;
|
||||
SpiceCharDeviceInstance *sin;
|
||||
SpiceCharDeviceInterface *sif;
|
||||
|
||||
state = SPICE_CONTAINEROF(red_channel, UsbRedirChannel, base)->state;
|
||||
state = SPICE_CONTAINEROF(rcc->channel, UsbRedirChannel, base)->state;
|
||||
sin = state->chardev_sin;
|
||||
sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base);
|
||||
|
||||
if (header->type != SPICE_MSGC_USBREDIR_DATA) {
|
||||
return red_channel_handle_message(red_channel, header->size,
|
||||
header->type, msg);
|
||||
return red_channel_client_handle_message(rcc, header->size,
|
||||
header->type, msg);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -132,12 +133,12 @@ static int usbredir_red_channel_handle_message(RedChannel *red_channel,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static uint8_t *usbredir_red_channel_alloc_msg_rcv_buf(RedChannel *red_channel,
|
||||
static uint8_t *usbredir_red_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
|
||||
SpiceDataHeader *msg_header)
|
||||
{
|
||||
UsbRedirState *state;
|
||||
|
||||
state = SPICE_CONTAINEROF(red_channel, UsbRedirChannel, base)->state;
|
||||
state = SPICE_CONTAINEROF(rcc->channel, UsbRedirChannel, base)->state;
|
||||
|
||||
if (msg_header->size > state->rcv_buf_size) {
|
||||
state->rcv_buf = spice_realloc(state->rcv_buf, msg_header->size);
|
||||
@ -147,30 +148,30 @@ static uint8_t *usbredir_red_channel_alloc_msg_rcv_buf(RedChannel *red_channel,
|
||||
return state->rcv_buf;
|
||||
}
|
||||
|
||||
static void usbredir_red_channel_release_msg_rcv_buf(RedChannel *red_channel,
|
||||
static void usbredir_red_channel_release_msg_rcv_buf(RedChannelClient *rcc,
|
||||
SpiceDataHeader *msg_header, uint8_t *msg)
|
||||
{
|
||||
/* NOOP, we re-use the buffer every time and only free it on destruction */
|
||||
}
|
||||
|
||||
static void usbredir_red_channel_hold_pipe_item(RedChannel *red_channel,
|
||||
static void usbredir_red_channel_hold_pipe_item(RedChannelClient *rcc,
|
||||
PipeItem *item)
|
||||
{
|
||||
/* NOOP */
|
||||
}
|
||||
|
||||
static void usbredir_red_channel_send_item(RedChannel *red_channel,
|
||||
static void usbredir_red_channel_send_item(RedChannelClient *rcc,
|
||||
PipeItem *item)
|
||||
{
|
||||
UsbRedirPipeItem *i = SPICE_CONTAINEROF(item, UsbRedirPipeItem, base);
|
||||
SpiceMarshaller *m = red_channel_get_marshaller(red_channel);
|
||||
SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
|
||||
|
||||
red_channel_init_send_data(red_channel, SPICE_MSG_USBREDIR_DATA, item);
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_USBREDIR_DATA, item);
|
||||
spice_marshaller_add_ref(m, i->buf, i->buf_used);
|
||||
red_channel_begin_send_message(red_channel);
|
||||
red_channel_client_begin_send_message(rcc);
|
||||
}
|
||||
|
||||
static void usbredir_red_channel_release_pipe_item(RedChannel *red_channel,
|
||||
static void usbredir_red_channel_release_pipe_item(RedChannelClient *rcc,
|
||||
PipeItem *item, int item_pushed)
|
||||
{
|
||||
free(item);
|
||||
@ -188,28 +189,36 @@ static void usbredir_link(Channel *channel, RedsStream *stream, int migration,
|
||||
sin = state->chardev_sin;
|
||||
sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base);
|
||||
|
||||
if (state->red_channel) {
|
||||
WARN("channel %d:%d already connected, refusing second connection\n",
|
||||
channel->type, channel->id);
|
||||
if (state->rcc) {
|
||||
WARN("channel client %d:%d (%p) already connected, refusing second connection\n",
|
||||
channel->type, channel->id, state->rcc);
|
||||
// TODO: notify client in advance about the in use channel using
|
||||
// SPICE_MSG_MAIN_CHANNEL_IN_USE (for example)
|
||||
reds_stream_free(stream);
|
||||
return;
|
||||
}
|
||||
|
||||
state->red_channel = red_channel_create(sizeof(UsbRedirChannel),
|
||||
stream, core,
|
||||
migration, FALSE /* handle_acks */,
|
||||
usbredir_red_channel_config_socket,
|
||||
usbredir_red_channel_disconnect,
|
||||
usbredir_red_channel_handle_message,
|
||||
usbredir_red_channel_alloc_msg_rcv_buf,
|
||||
usbredir_red_channel_release_msg_rcv_buf,
|
||||
usbredir_red_channel_hold_pipe_item,
|
||||
usbredir_red_channel_send_item,
|
||||
usbredir_red_channel_release_pipe_item,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
if (!state->red_channel) {
|
||||
state->red_channel = red_channel_create(sizeof(UsbRedirChannel),
|
||||
core, migration, FALSE /* handle_acks */,
|
||||
usbredir_red_channel_config_socket,
|
||||
usbredir_red_channel_disconnect,
|
||||
usbredir_red_channel_client_handle_message,
|
||||
usbredir_red_channel_alloc_msg_rcv_buf,
|
||||
usbredir_red_channel_release_msg_rcv_buf,
|
||||
usbredir_red_channel_hold_pipe_item,
|
||||
usbredir_red_channel_send_item,
|
||||
usbredir_red_channel_release_pipe_item,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
if (!state->red_channel) {
|
||||
return;
|
||||
}
|
||||
state->rcc = red_channel_client_create(sizeof(RedChannelClient), state->red_channel, stream);
|
||||
if (!state->rcc) {
|
||||
red_printf("failed to create usbredir channel client\n");
|
||||
return;
|
||||
}
|
||||
red_channel_init_outgoing_messages_window(state->red_channel);
|
||||
@ -225,7 +234,9 @@ static void usbredir_shutdown(Channel *channel)
|
||||
{
|
||||
UsbRedirState *state = SPICE_CONTAINEROF(channel, UsbRedirState, channel);
|
||||
|
||||
usbredir_red_channel_disconnect(state->red_channel);
|
||||
usbredir_red_channel_disconnect(state->rcc);
|
||||
red_channel_destroy(state->red_channel);
|
||||
state->red_channel = NULL;
|
||||
}
|
||||
|
||||
static void usbredir_migrate(Channel *channel)
|
||||
@ -264,7 +275,7 @@ void usbredir_device_disconnect(SpiceCharDeviceInstance *sin)
|
||||
|
||||
reds_unregister_channel(&state->channel);
|
||||
|
||||
usbredir_red_channel_disconnect(state->red_channel);
|
||||
usbredir_red_channel_disconnect(state->rcc);
|
||||
|
||||
free(state->pipe_item);
|
||||
free(state->rcv_buf);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user