> A Spice port channel carry arbitrary data between the Spice client > and > the Spice server. It may be used to provide additional services on > top > of a Spice connection. For example, a channel can be associated with > the qemu monitor for the client to interact with it, just like any > qemu chardev. Or it may be used with various protocols, such as the > Spice Controller. > > A port kind is identified simply by its fqdn, such as > org.qemu.monitor, > org.spice.spicy.test or org.ovirt.controller... > > The channel is based on Spicevmc which simply tunnels data between > client and server, with a few additional messages. Looks good to me. > > See the description of the channel protocol in spice-common history. > --- > server/reds.c | 11 +++- > server/spice-server.syms | 5 ++ > server/spice.h | 5 +- > server/spicevmc.c | 152 > ++++++++++++++++++++++++++++++++++++++++++----- > 4 files changed, 155 insertions(+), 18 deletions(-) > > diff --git a/server/reds.c b/server/reds.c > index 1cb46f4..084620c 100644 > --- a/server/reds.c > +++ b/server/reds.c > @@ -3525,6 +3525,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, > @@ -3598,6 +3599,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 > @@ -3629,9 +3634,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 eadfed8..2091fe0 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 22f17d6..4b86f4b 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 058a182..aba2a5d 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); > +} > -- > 1.7.11.7 > > _______________________________________________ > Spice-devel mailing list > Spice-devel@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/spice-devel > _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel