diff options
Diffstat (limited to 'server/spicevmc.c')
-rw-r--r-- | server/spicevmc.c | 152 |
1 files changed, 136 insertions, 16 deletions
diff --git a/server/spicevmc.c b/server/spicevmc.c index 058a1820..aba2a5d5 100644 --- a/server/spicevmc.c +++ b/server/spicevmc.c @@ -28,6 +28,8 @@ #include <netinet/in.h> // IPPROTO_TCP #include <netinet/tcp.h> // TCP_NODELAY +#include "common/generated_server_marshallers.h" + #include "char_device.h" #include "red_channel.h" #include "reds.h" @@ -56,11 +58,25 @@ typedef struct SpiceVmcState { SpiceCharDeviceInstance *chardev_sin; SpiceVmcPipeItem *pipe_item; SpiceCharDeviceWriteBuffer *recv_from_client_buf; + uint8_t port_opened; } SpiceVmcState; +typedef struct PortInitPipeItem { + PipeItem base; + char* name; + uint8_t opened; +} PortInitPipeItem; + +typedef struct PortEventPipeItem { + PipeItem base; + uint8_t event; +} PortEventPipeItem; + enum { PIPE_ITEM_TYPE_SPICEVMC_DATA = PIPE_ITEM_TYPE_CHANNEL_BASE, PIPE_ITEM_TYPE_SPICEVMC_MIGRATE_DATA, + PIPE_ITEM_TYPE_PORT_INIT, + PIPE_ITEM_TYPE_PORT_EVENT, }; static SpiceVmcPipeItem *spicevmc_pipe_item_ref(SpiceVmcPipeItem *item) @@ -137,6 +153,27 @@ static void spicevmc_chardev_send_msg_to_client(SpiceCharDeviceMsgToClient *msg, red_channel_client_pipe_add_push(state->rcc, &vmc_msg->base); } +static void spicevmc_port_send_init(RedChannelClient *rcc) +{ + SpiceVmcState *state = SPICE_CONTAINEROF(rcc->channel, SpiceVmcState, channel); + SpiceCharDeviceInstance *sin = state->chardev_sin; + PortInitPipeItem *item = spice_malloc(sizeof(PortInitPipeItem)); + + red_channel_pipe_item_init(rcc->channel, &item->base, PIPE_ITEM_TYPE_PORT_INIT); + item->name = strdup(sin->portname); + item->opened = state->port_opened; + red_channel_client_pipe_add_push(rcc, &item->base); +} + +static void spicevmc_port_send_event(RedChannelClient *rcc, uint8_t event) +{ + PortEventPipeItem *item = spice_malloc(sizeof(PortEventPipeItem)); + + red_channel_pipe_item_init(rcc->channel, &item->base, PIPE_ITEM_TYPE_PORT_EVENT); + item->event = event; + red_channel_client_pipe_add_push(rcc, &item->base); +} + static void spicevmc_char_dev_send_tokens_to_client(RedClient *client, uint32_t tokens, void *opaque) @@ -245,16 +282,32 @@ static int spicevmc_red_channel_client_handle_message(RedChannelClient *rcc, uint8_t *msg) { SpiceVmcState *state; + SpiceCharDeviceInstance *sin; + SpiceCharDeviceInterface *sif; state = spicevmc_red_channel_client_get_state(rcc); - if (type != SPICE_MSGC_SPICEVMC_DATA) { + sin = state->chardev_sin; + sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base); + + switch (type) { + case SPICE_MSGC_SPICEVMC_DATA: + spice_assert(state->recv_from_client_buf->buf == msg); + state->recv_from_client_buf->buf_used = size; + spice_char_device_write_buffer_add(state->chardev_st, state->recv_from_client_buf); + state->recv_from_client_buf = NULL; + break; + case SPICE_MSGC_PORT_EVENT: + if (size != sizeof(uint8_t)) { + spice_warning("bad port event message size"); + return FALSE; + } + if (sif->base.minor_version >= 2 && sif->event != NULL) + sif->event(sin, *msg); + break; + default: return red_channel_client_handle_message(rcc, size, type, msg); } - spice_assert(state->recv_from_client_buf->buf == msg); - state->recv_from_client_buf->buf_used = size; - spice_char_device_write_buffer_add(state->chardev_st, state->recv_from_client_buf); - state->recv_from_client_buf = NULL; return TRUE; } @@ -266,16 +319,23 @@ static uint8_t *spicevmc_red_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, state = SPICE_CONTAINEROF(rcc->channel, SpiceVmcState, channel); - assert(!state->recv_from_client_buf); + switch (type) { + case SPICE_MSGC_SPICEVMC_DATA: + assert(!state->recv_from_client_buf); - state->recv_from_client_buf = spice_char_device_write_buffer_get(state->chardev_st, - rcc->client, - size); - if (!state->recv_from_client_buf) { - spice_error("failed to allocate write buffer"); - return NULL; + state->recv_from_client_buf = spice_char_device_write_buffer_get(state->chardev_st, + rcc->client, + size); + if (!state->recv_from_client_buf) { + spice_error("failed to allocate write buffer"); + return NULL; + } + return state->recv_from_client_buf->buf; + + default: + return spice_malloc(size); } - return state->recv_from_client_buf->buf; + } static void spicevmc_red_channel_release_msg_rcv_buf(RedChannelClient *rcc, @@ -287,9 +347,15 @@ static void spicevmc_red_channel_release_msg_rcv_buf(RedChannelClient *rcc, state = SPICE_CONTAINEROF(rcc->channel, SpiceVmcState, channel); - if (state->recv_from_client_buf) { /* buffer wasn't pushed to device */ - spice_char_device_write_buffer_release(state->chardev_st, state->recv_from_client_buf); - state->recv_from_client_buf = NULL; + switch (type) { + case SPICE_MSGC_SPICEVMC_DATA: + if (state->recv_from_client_buf) { /* buffer wasn't pushed to device */ + spice_char_device_write_buffer_release(state->chardev_st, state->recv_from_client_buf); + state->recv_from_client_buf = NULL; + } + break; + default: + free(msg); } } @@ -323,6 +389,32 @@ static void spicevmc_red_channel_send_migrate_data(RedChannelClient *rcc, spice_char_device_state_migrate_data_marshall(state->chardev_st, m); } +static void spicevmc_red_channel_send_port_init(RedChannelClient *rcc, + SpiceMarshaller *m, + PipeItem *item) +{ + PortInitPipeItem *i = SPICE_CONTAINEROF(item, PortInitPipeItem, base); + SpiceMsgPortInit init; + + red_channel_client_init_send_data(rcc, SPICE_MSG_PORT_INIT, item); + init.name = (uint8_t *)i->name; + init.name_size = strlen(i->name) + 1; + init.opened = i->opened; + spice_marshall_msg_port_init(m, &init); +} + +static void spicevmc_red_channel_send_port_event(RedChannelClient *rcc, + SpiceMarshaller *m, + PipeItem *item) +{ + PortEventPipeItem *i = SPICE_CONTAINEROF(item, PortEventPipeItem, base); + SpiceMsgPortEvent event; + + red_channel_client_init_send_data(rcc, SPICE_MSG_PORT_EVENT, item); + event.event = i->event; + spice_marshall_msg_port_event(m, &event); +} + static void spicevmc_red_channel_send_item(RedChannelClient *rcc, PipeItem *item) { @@ -335,6 +427,12 @@ static void spicevmc_red_channel_send_item(RedChannelClient *rcc, case PIPE_ITEM_TYPE_SPICEVMC_MIGRATE_DATA: spicevmc_red_channel_send_migrate_data(rcc, m, item); break; + case PIPE_ITEM_TYPE_PORT_INIT: + spicevmc_red_channel_send_port_init(rcc, m, item); + break; + case PIPE_ITEM_TYPE_PORT_EVENT: + spicevmc_red_channel_send_port_event(rcc, m, item); + break; default: spice_error("bad pipe item %d", item->type); free(item); @@ -384,6 +482,10 @@ static void spicevmc_connect(RedChannel *channel, RedClient *client, state->rcc = rcc; red_channel_client_ack_zero_messages_window(rcc); + if (strcmp(sin->subtype, "port") == 0) { + spicevmc_port_send_init(rcc); + } + if (!spice_char_device_client_add(state->chardev_st, client, FALSE, 0, ~0, ~0, red_channel_client_waits_for_migrate_data(rcc))) { spice_warning("failed to add client to spicevmc"); @@ -461,3 +563,21 @@ void spicevmc_device_disconnect(SpiceCharDeviceInstance *sin) free(state->pipe_item); red_channel_destroy(&state->channel); } + +SPICE_GNUC_VISIBLE void spice_server_port_event(SpiceCharDeviceInstance *sin, uint8_t event) +{ + SpiceVmcState *state; + + state = (SpiceVmcState *)spice_char_device_state_opaque_get(sin->st); + if (event == SPICE_PORT_EVENT_OPENED) { + state->port_opened = TRUE; + } else if (event == SPICE_PORT_EVENT_CLOSED) { + state->port_opened = FALSE; + } + + if (state->rcc == NULL) { + return; + } + + spicevmc_port_send_event(state->rcc, event); +} |