[Spice-devel] [PATCH spice-server 13/14] smartcard: use SpiceCharDeviceState for writing to the guest device

Hans de Goede hdegoede at redhat.com
Mon Jul 2 07:16:45 PDT 2012


Looks good, ack.

Regards,

Hans



On 06/27/2012 05:16 PM, Yonit Halperin wrote:
> With SpiceCharDeviceState, the smartcard code now supports partial writes,
> and storing data that is received from the client after the device is
> stopped, instead of attempting to write it to the guest.
> ---
>   server/smartcard.c |  115 ++++++++++++++++++++++++++++++++++++++++++----------
>   1 files changed, 93 insertions(+), 22 deletions(-)
>
> diff --git a/server/smartcard.c b/server/smartcard.c
> index 0a2ab75..c844a32 100644
> --- a/server/smartcard.c
> +++ b/server/smartcard.c
> @@ -44,6 +44,12 @@ typedef struct SmartCardDeviceState SmartCardDeviceState;
>   typedef struct SmartCardChannelClient {
>       RedChannelClient base;
>       SmartCardDeviceState *smartcard_state;
> +
> +    /* read_from_client/write_to_device buffer.
> +     * The beginning of the buffer should always be VSCMsgHeader*/
> +    SpiceCharDeviceWriteBuffer *write_buf;
> +    int msg_in_write_buf; /* was the client msg received into a SpiceCharDeviceWriteBuffer
> +                           * or was it explicitly malloced */
>   } SmartCardChannelClient;
>
>   typedef struct SmartCardDeviceState {
> @@ -96,7 +102,7 @@ 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, SmartCardChannelClient *scc);
> -static void smartcard_channel_write_to_reader(VSCMsgHeader *vheader);
> +static void smartcard_channel_write_to_reader(SpiceCharDeviceWriteBuffer *write_buf);
>
>   static MsgItem *smartcard_char_device_on_message_from_device(
>       SmartCardDeviceState *state, VSCMsgHeader *header);
> @@ -306,7 +312,8 @@ static void smartcard_char_device_attach(SpiceCharDeviceInstance *char_device,
>                                            SmartCardChannelClient *scc)
>   {
>       SmartCardDeviceState *st = spice_char_device_state_opaque_get(char_device->st);
> -
> +    SpiceCharDeviceWriteBuffer *write_buf;
> +    VSCMsgHeader *vheader;
>
>       spice_assert(!scc->smartcard_state);
>       if (st->attached == TRUE) {
> @@ -321,14 +328,23 @@ static void smartcard_char_device_attach(SpiceCharDeviceInstance *char_device,
>                                    ~0,
>                                    ~0);
>       scc->smartcard_state = st;
> -    VSCMsgHeader vheader = {.type = VSC_ReaderAdd, .reader_id=st->reader_id,
> -        .length=0};
> -    smartcard_channel_write_to_reader(&vheader);
> +    write_buf = spice_char_device_write_buffer_get(st->chardev_st, NULL, sizeof(vheader));
> +    if (!write_buf) {
> +        spice_error("failed to allocate write buffer");
> +        return;
> +    }
> +    vheader = (VSCMsgHeader *)write_buf->buf;
> +    vheader->type = VSC_ReaderAdd;
> +    vheader->reader_id = st->reader_id;
> +    vheader->length = 0;
> +    smartcard_channel_write_to_reader(write_buf);
>   }
>
>   static void smartcard_char_device_detach_client(SmartCardChannelClient *scc)
>   {
>       SmartCardDeviceState *st;
> +    SpiceCharDeviceWriteBuffer *write_buf;
> +    VSCMsgHeader *vheader;
>
>       if (!scc->smartcard_state) {
>           return;
> @@ -339,9 +355,16 @@ static void smartcard_char_device_detach_client(SmartCardChannelClient *scc)
>       scc->smartcard_state = NULL;
>       st->attached = FALSE;
>       st->scc = NULL;
> -    VSCMsgHeader vheader = {.type = VSC_ReaderRemove, .reader_id=st->reader_id,
> -        .length=0};
> -    smartcard_channel_write_to_reader(&vheader);
> +    write_buf = spice_char_device_write_buffer_get(st->chardev_st, NULL, sizeof(vheader));
> +    if (!write_buf) {
> +        spice_error("failed to allocate write buffer");
> +        return;
> +    }
> +    vheader = (VSCMsgHeader *)write_buf->buf;
> +    vheader->type = VSC_ReaderRemove;
> +    vheader->reader_id = st->reader_id;
> +    vheader->length = 0;
> +    smartcard_channel_write_to_reader(write_buf);
>   }
>
>   static int smartcard_channel_client_config_socket(RedChannelClient *rcc)
> @@ -353,7 +376,30 @@ static uint8_t *smartcard_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
>                                                       uint16_t type,
>                                                       uint32_t size)
>   {
> -    return spice_malloc(size);
> +    SmartCardChannelClient *scc = SPICE_CONTAINEROF(rcc, SmartCardChannelClient, base);
> +
> +    /* todo: only one reader is actually supported. When we fix the code to support
> +     * multiple readers, we will porbably associate different devices to
> +     * differenc channels */
> +    if (!scc->smartcard_state) {
> +        scc->msg_in_write_buf = FALSE;
> +        return spice_malloc(size);
> +    } else {
> +        SmartCardDeviceState *st;
> +
> +        spice_assert(g_smartcard_readers.num == 1);
> +        st = scc->smartcard_state;
> +        spice_assert(st->scc || scc->smartcard_state);
> +        spice_assert(!scc->write_buf);
> +        scc->write_buf = spice_char_device_write_buffer_get(st->chardev_st, rcc->client, size);
> +
> +        if (!scc->write_buf) {
> +            spice_error("failed to allocate write buffer");
> +            return NULL;
> +        }
> +        scc->msg_in_write_buf = TRUE;
> +        return scc->write_buf->buf;
> +    }
>   }
>
>   static void smartcard_channel_release_msg_rcv_buf(RedChannelClient *rcc,
> @@ -361,8 +407,24 @@ static void smartcard_channel_release_msg_rcv_buf(RedChannelClient *rcc,
>                                                     uint32_t size,
>                                                     uint8_t *msg)
>   {
> -    spice_printerr("freeing %d bytes", size);
> -    free(msg);
> +    SmartCardChannelClient *scc = SPICE_CONTAINEROF(rcc, SmartCardChannelClient, base);
> +
> +    /* todo: only one reader is actually supported. When we fix the code to support
> +     * multiple readers, we will porbably associate different devices to
> +     * differenc channels */
> +
> +    if (!scc->msg_in_write_buf) {
> +        spice_assert(!scc->write_buf);
> +        free(msg);
> +    } else {
> +        SpiceCharDeviceState *dev_st;
> +        if (scc->write_buf) { /* msg hasn't been pushed to the guest */
> +            spice_assert(scc->write_buf->buf == msg);
> +            dev_st = scc->smartcard_state ? scc->smartcard_state->chardev_st : NULL;
> +            spice_char_device_write_buffer_release(dev_st, scc->write_buf);
> +            scc->write_buf = NULL;
> +        }
> +    }
>   }
>
>   static void smartcard_channel_send_data(RedChannelClient *rcc, SpiceMarshaller *m,
> @@ -407,7 +469,6 @@ static void smartcard_channel_send_item(RedChannelClient *rcc, PipeItem *item)
>       }
>   }
>
> -
>   static void smartcard_channel_release_pipe_item(RedChannelClient *rcc,
>                                         PipeItem *item, int item_pushed)
>   {
> @@ -509,24 +570,31 @@ static void smartcard_add_reader(SmartCardChannelClient *scc, uint8_t *name)
>       }
>   }
>
> -static void smartcard_channel_write_to_reader(VSCMsgHeader *vheader)
> +static void smartcard_channel_write_to_reader(SpiceCharDeviceWriteBuffer *write_buf)
>   {
>       SpiceCharDeviceInstance *sin;
> -    SpiceCharDeviceInterface *sif;
> -    uint32_t n;
> -    uint32_t actual_length = vheader->length;
> +    SmartCardDeviceState *st;
> +    VSCMsgHeader *vheader;
> +    uint32_t actual_length;
> +
> +    vheader = (VSCMsgHeader *)write_buf->buf;
> +    actual_length = vheader->length;
>
>       spice_assert(vheader->reader_id <= g_smartcard_readers.num);
>       sin = g_smartcard_readers.sin[vheader->reader_id];
> -    sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base);
> +    st = (SmartCardDeviceState *)spice_char_device_state_opaque_get(sin->st);
> +    spice_assert(!st->attached || st == st->scc->smartcard_state);
>       /* protocol requires messages to be in network endianess */
>       vheader->type = htonl(vheader->type);
>       vheader->length = htonl(vheader->length);
>       vheader->reader_id = htonl(vheader->reader_id);
> -    n = sif->write(sin, (uint8_t*)vheader,
> -                   actual_length + sizeof(VSCMsgHeader));
> -    // TODO - add ring
> -    spice_assert(n == actual_length + sizeof(VSCMsgHeader));
> +    write_buf->buf_used = actual_length + sizeof(VSCMsgHeader);
> +    /* pushing the buffer to the write queue; It will be released
> +     * when it will be fully consumed by the device */
> +    spice_char_device_write_buffer_add(sin->st, write_buf);
> +    if (st->attached && write_buf == st->scc->write_buf) {
> +        st->scc->write_buf = NULL;
> +    }
>   }
>
>   static int smartcard_channel_handle_message(RedChannelClient *rcc,
> @@ -566,12 +634,15 @@ static int smartcard_channel_handle_message(RedChannelClient *rcc,
>               return TRUE;
>       }
>
> +    /* todo: fix */
>       if (vheader->reader_id >= g_smartcard_readers.num) {
>           spice_printerr("ERROR: received message for non existent reader: %d, %d, %d", vheader->reader_id,
>               vheader->type, vheader->length);
>           return FALSE;
>       }
> -    smartcard_channel_write_to_reader(vheader);
> +    spice_assert(scc->write_buf->buf == msg);
> +    smartcard_channel_write_to_reader(scc->write_buf);
> +
>       return TRUE;
>   }
>
>



More information about the Spice-devel mailing list