[Spice-devel] [PATCH spice-server v2 5/7] test-stream-device: Factor out VMC emulation
Frediano Ziglio
fziglio at redhat.com
Wed Oct 9 08:31:57 UTC 2019
>
> Allows to reuse code for emulating a character device.
> It will be used for Smardcard test.
>
> Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
> Acked-by: Victor Toso <victortoso at redhat.com>
> ---
> server/tests/Makefile.am | 2 +
> server/tests/meson.build | 2 +
> server/tests/test-stream-device.c | 224 +++++++++---------------------
> server/tests/vmc-emu.c | 121 ++++++++++++++++
> server/tests/vmc-emu.h | 48 +++++++
> 5 files changed, 236 insertions(+), 161 deletions(-)
> create mode 100644 server/tests/vmc-emu.c
> create mode 100644 server/tests/vmc-emu.h
>
...
> diff --git a/server/tests/vmc-emu.c b/server/tests/vmc-emu.c
> new file mode 100644
> index 000000000..ddac5269c
> --- /dev/null
> +++ b/server/tests/vmc-emu.c
> @@ -0,0 +1,121 @@
> +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
> +/*
> + Copyright (C) 2019 Red Hat, Inc.
> +
> + This library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + This library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with this library; if not, see
> <http://www.gnu.org/licenses/>.
> +*/
> +
> +#include <config.h>
> +#include <glib.h>
> +
> +#include "vmc-emu.h"
> +
> +// handle writes to the device
> +static int vmc_write(SpiceCharDeviceInstance *sin,
> + const uint8_t *buf, int len)
> +{
> + VmcEmu *const vmc = SPICE_CONTAINEROF(sin, VmcEmu, instance);
> +
> + // just copy into the buffer
> + unsigned copy = MIN(sizeof(vmc->write_buf) - vmc->write_pos, len);
> + memcpy(vmc->write_buf+vmc->write_pos, buf, copy);
> + vmc->write_pos += copy;
> + return len;
> +}
> +
> +static int vmc_read(SpiceCharDeviceInstance *sin,
> + uint8_t *buf, int len)
> +{
> + VmcEmu *const vmc = SPICE_CONTAINEROF(sin, VmcEmu, instance);
> + int ret;
> +
> + if (vmc->pos >= *vmc->message_sizes_curr && vmc->message_sizes_curr <
> vmc->message_sizes_end) {
> + ++vmc->message_sizes_curr;
> + }
> + if (vmc->message_sizes_curr >= vmc->message_sizes_end || vmc->pos >=
> *vmc->message_sizes_curr) {
> + return 0;
> + }
> + ret = MIN(*vmc->message_sizes_curr - vmc->pos, len);
> + memcpy(buf, &vmc->message[vmc->pos], ret);
> + vmc->pos += ret;
> + // kick off next message read
> + // currently Qemu kicks the device so we need to do it manually
> + // here. If not all data are read, the device goes into blocking
> + // state and we get the wake only when we read from the device
> + // again
> + if (vmc->pos >= *vmc->message_sizes_curr) {
> + spice_server_char_device_wakeup(&vmc->instance);
> + }
> + return ret;
> +}
> +
> +static void vmc_state(SpiceCharDeviceInstance *sin,
> + int connected)
> +{
> + VmcEmu *const vmc = SPICE_CONTAINEROF(sin, VmcEmu, instance);
> + vmc->device_enabled = !!connected;
> +}
> +
> +static const SpiceCharDeviceInterface vmc_interface = {
> + .base = {
> + .type = SPICE_INTERFACE_CHAR_DEVICE,
> + .description = "test spice virtual channel char device",
> + .major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
> + .minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
> + },
> + .state = vmc_state,
> + .write = vmc_write,
> + .read = vmc_read,
> +};
> +
> +VmcEmu *vmc_emu_new(const char *subtype, const char *portname)
> +{
> + VmcEmu *vmc = g_new0(VmcEmu, 1);
> + vmc->interface = vmc_interface;
> + vmc->instance.base.sif = &vmc->interface.base;
> + vmc->instance.subtype = g_strdup(subtype);
> + if (portname) {
> + vmc->instance.portname = g_strdup(portname);
> + }
> + vmc_emu_reset(vmc);
> + return vmc;
> +}
> +
> +void vmc_emu_destroy(VmcEmu *vmc)
> +{
> + g_free((char *) vmc->instance.portname);
> + g_free((char *) vmc->instance.subtype);
> + g_free(vmc);
> +}
> +
> +void vmc_emu_reset(VmcEmu *vmc)
> +{
> + vmc->pos = 0;
> + vmc->write_pos = 0;
> + vmc->message_sizes_curr = vmc->message_sizes;
> + vmc->message_sizes_end = vmc->message_sizes;
> +}
> +
> +void vmc_emu_add_read_till(VmcEmu *vmc, uint8_t *end)
> +{
> + g_assert(vmc->message_sizes_end - vmc->message_sizes <
> G_N_ELEMENTS(vmc->message_sizes));
> + g_assert(end >= vmc->message);
> + g_assert(end - vmc->message <= G_N_ELEMENTS(vmc->message));
> + unsigned prev_size =
> + vmc->message_sizes_end > vmc->message_sizes ?
> vmc->message_sizes_end[-1] : 0;
> + unsigned size = end - vmc->message;
> + g_assert(size >= prev_size);
> + *vmc->message_sizes_end = size;
> + ++vmc->message_sizes_end;
> +}
> diff --git a/server/tests/vmc-emu.h b/server/tests/vmc-emu.h
> new file mode 100644
> index 000000000..6fcea69d2
> --- /dev/null
> +++ b/server/tests/vmc-emu.h
> @@ -0,0 +1,48 @@
> +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
> +/*
> + Copyright (C) 2019 Red Hat, Inc.
> +
> + This library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + This library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with this library; if not, see
> <http://www.gnu.org/licenses/>.
> +*/
> +#pragma once
> +
> +#include "char-device.h"
> +
> +typedef struct VmcEmu VmcEmu;
> +
> +struct VmcEmu {
> + SpiceCharDeviceInterface interface;
Locally I renamed this field to vmc_interface to avoid collision on Windows
(detected by Gitlab CI)
> + SpiceCharDeviceInstance instance;
> +
> + // device buffer to read from
> + uint8_t message[2048];
> + // position to read from
> + unsigned pos;
> +
> + // array of limits when the read should return
> + // the array is defined as [message_sizes_curr, message_sizes_end)
> + // then the size is reach we move on next one till exausted
> + unsigned message_sizes[16];
> + unsigned *message_sizes_end, *message_sizes_curr;
> +
> + bool device_enabled;
> +
> + unsigned write_pos;
> + uint8_t write_buf[2048];
> +};
> +
> +VmcEmu *vmc_emu_new(const char *subtype, const char *portname);
> +void vmc_emu_destroy(VmcEmu *vmc);
> +void vmc_emu_reset(VmcEmu *vmc);
> +void vmc_emu_add_read_till(VmcEmu *vmc, uint8_t *end);
Frediano
More information about the Spice-devel
mailing list