[Spice-devel] [PATCH spice] server: add "port" channel support
Alon Levy
alevy at redhat.com
Tue Dec 4 07:22:08 PST 2012
> 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 at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
>
More information about the Spice-devel
mailing list