diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/reds.c | 11 | ||||
-rw-r--r-- | server/spice-server.syms | 5 | ||||
-rw-r--r-- | server/spice.h | 5 | ||||
-rw-r--r-- | server/spicevmc.c | 152 |
4 files changed, 155 insertions, 18 deletions
diff --git a/server/reds.c b/server/reds.c index 3a8a28d4..a896cf2a 100644 --- a/server/reds.c +++ b/server/reds.c @@ -3541,6 +3541,7 @@ SPICE_GNUC_VISIBLE void spice_server_char_device_wakeup(SpiceCharDeviceInstance* #define SUBTYPE_VDAGENT "vdagent" #define SUBTYPE_SMARTCARD "smartcard" #define SUBTYPE_USBREDIR "usbredir" +#define SUBTYPE_PORT "port" const char *spice_server_char_device_recognized_subtypes_list[] = { SUBTYPE_VDAGENT, @@ -3614,6 +3615,10 @@ static int spice_server_char_device_add_interface(SpiceServer *s, else if (strcmp(char_device->subtype, SUBTYPE_USBREDIR) == 0) { dev_state = spicevmc_device_connect(char_device, SPICE_CHANNEL_USBREDIR); } + else if (strcmp(char_device->subtype, SUBTYPE_PORT) == 0) { + dev_state = spicevmc_device_connect(char_device, SPICE_CHANNEL_PORT); + } + if (dev_state) { spice_assert(char_device->st); /* setting the char_device state to "started" for backward compatibily with @@ -3645,9 +3650,13 @@ static void spice_server_char_device_remove_interface(SpiceBaseInstance *sin) smartcard_device_disconnect(char_device); } #endif - else if (strcmp(char_device->subtype, SUBTYPE_USBREDIR) == 0) { + else if (strcmp(char_device->subtype, SUBTYPE_USBREDIR) == 0 || + strcmp(char_device->subtype, SUBTYPE_PORT) == 0) { spicevmc_device_disconnect(char_device); + } else { + spice_warning("failed to remove char device %s", char_device->subtype); } + char_device->st = NULL; } diff --git a/server/spice-server.syms b/server/spice-server.syms index eadfed83..2091fe04 100644 --- a/server/spice-server.syms +++ b/server/spice-server.syms @@ -130,3 +130,8 @@ SPICE_SERVER_0.11.4 { global: spice_server_set_exit_on_disconnect; } SPICE_SERVER_0.11.2; + +SPICE_SERVER_0.12.2 { +global: + spice_server_port_event; +} SPICE_SERVER_0.11.4; diff --git a/server/spice.h b/server/spice.h index aabc9098..45b7408c 100644 --- a/server/spice.h +++ b/server/spice.h @@ -388,7 +388,7 @@ void spice_server_record_set_mute(SpiceRecordInstance *sin, uint8_t mute); #define SPICE_INTERFACE_CHAR_DEVICE "char_device" #define SPICE_INTERFACE_CHAR_DEVICE_MAJOR 1 -#define SPICE_INTERFACE_CHAR_DEVICE_MINOR 1 +#define SPICE_INTERFACE_CHAR_DEVICE_MINOR 2 typedef struct SpiceCharDeviceInterface SpiceCharDeviceInterface; typedef struct SpiceCharDeviceInstance SpiceCharDeviceInstance; typedef struct SpiceCharDeviceState SpiceCharDeviceState; @@ -399,15 +399,18 @@ struct SpiceCharDeviceInterface { void (*state)(SpiceCharDeviceInstance *sin, int connected); int (*write)(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len); int (*read)(SpiceCharDeviceInstance *sin, uint8_t *buf, int len); + void (*event)(SpiceCharDeviceInstance *sin, uint8_t event); }; struct SpiceCharDeviceInstance { SpiceBaseInstance base; const char* subtype; SpiceCharDeviceState *st; + const char* portname; }; void spice_server_char_device_wakeup(SpiceCharDeviceInstance *sin); +void spice_server_port_event(SpiceCharDeviceInstance *char_device, uint8_t event); const char** spice_server_char_device_recognized_subtypes(void); /* spice server setup */ 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); +} |