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:
Alon Levy 2010-11-13 13:23:02 +02:00
parent 75b6a305ff
commit 7e8e13593e
9 changed files with 1168 additions and 889 deletions

View File

@ -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);
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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);