mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-26 22:48:19 +00:00
vdi port: redesign.
Pretty straight forward. One thing we should think about is if and how we are going to deal with multiple ports here? With vdi port using virtio-serial as communication channel to the guest it is easy to have multiple ports, i.e. we might want to use a second instance for clipboard data. That implies that we need support for multiple channels all the way through the stack ...
This commit is contained in:
parent
2e47435ecb
commit
ccfbbae513
@ -59,7 +59,7 @@ static MigrationInterface *mig = NULL;
|
||||
static SpiceKbdInstance *keyboard = NULL;
|
||||
static SpiceMouseInstance *mouse = NULL;
|
||||
static SpiceTabletInstance *tablet = NULL;
|
||||
static VDIPortInterface *vdagent = NULL;
|
||||
static SpiceVDIPortInstance *vdagent = NULL;
|
||||
|
||||
#define MIGRATION_NOTIFY_SPICE_KEY "spice_mig_ext"
|
||||
|
||||
@ -176,8 +176,7 @@ typedef struct __attribute__ ((__packed__)) VDIChunkHeader {
|
||||
} VDIChunkHeader;
|
||||
|
||||
typedef struct VDIPortState {
|
||||
VDIPortPlug plug;
|
||||
VDObjectRef plug_ref;
|
||||
int connected;
|
||||
uint32_t plug_generation;
|
||||
|
||||
uint32_t num_tokens;
|
||||
@ -743,10 +742,13 @@ static void reds_disconnect()
|
||||
reds->disconnecting = TRUE;
|
||||
reds_reset_outgoing();
|
||||
|
||||
if (reds->agent_state.plug_ref != INVALID_VD_OBJECT_REF) {
|
||||
ASSERT(vdagent);
|
||||
vdagent->unplug(vdagent, reds->agent_state.plug_ref);
|
||||
reds->agent_state.plug_ref = INVALID_VD_OBJECT_REF;
|
||||
if (reds->agent_state.connected) {
|
||||
SpiceVDIPortInterface *sif;
|
||||
sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceVDIPortInterface, base);
|
||||
reds->agent_state.connected = 0;
|
||||
if (sif->state) {
|
||||
sif->state(vdagent, reds->agent_state.connected);
|
||||
}
|
||||
reds_reset_vdp();
|
||||
}
|
||||
|
||||
@ -1122,18 +1124,22 @@ static void reds_send_agent_disconnected()
|
||||
|
||||
static void reds_agent_remove()
|
||||
{
|
||||
VDIPortInterface *interface = vdagent;
|
||||
SpiceVDIPortInstance *sin = vdagent;
|
||||
SpiceVDIPortInterface *sif;
|
||||
|
||||
vdagent = NULL;
|
||||
reds_update_mouse_mode();
|
||||
|
||||
if (!reds->peer || !interface) {
|
||||
if (!reds->peer || !sin) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(reds->agent_state.plug_ref != INVALID_VD_OBJECT_REF);
|
||||
interface->unplug(interface, reds->agent_state.plug_ref);
|
||||
reds->agent_state.plug_ref = INVALID_VD_OBJECT_REF;
|
||||
ASSERT(reds->agent_state.connected)
|
||||
sif = SPICE_CONTAINEROF(sin->base.sif, SpiceVDIPortInterface, base);
|
||||
reds->agent_state.connected = 0;
|
||||
if (sif->state) {
|
||||
sif->state(sin, reds->agent_state.connected);
|
||||
}
|
||||
|
||||
if (reds->mig_target) {
|
||||
return;
|
||||
@ -1164,21 +1170,23 @@ static void reds_send_tokens()
|
||||
static int write_to_vdi_port()
|
||||
{
|
||||
VDIPortState *state = &reds->agent_state;
|
||||
SpiceVDIPortInterface *sif;
|
||||
RingItem *ring_item;
|
||||
VDIPortBuf *buf;
|
||||
int total = 0;
|
||||
int n;
|
||||
|
||||
if (reds->agent_state.plug_ref == INVALID_VD_OBJECT_REF || reds->mig_target) {
|
||||
if (!reds->agent_state.connected || reds->mig_target) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceVDIPortInterface, base);
|
||||
while (reds->agent_state.connected) {
|
||||
if (!(ring_item = ring_get_tail(&state->write_queue))) {
|
||||
break;
|
||||
}
|
||||
buf = (VDIPortBuf *)ring_item;
|
||||
n = vdagent->write(vdagent, state->plug_ref, buf->now, buf->write_len);
|
||||
n = sif->write(vdagent, buf->now, buf->write_len);
|
||||
if (n == 0) {
|
||||
break;
|
||||
}
|
||||
@ -1217,18 +1225,20 @@ static void dispatch_vdi_port_data(int port, VDIReadBuf *buf)
|
||||
static int read_from_vdi_port()
|
||||
{
|
||||
VDIPortState *state = &reds->agent_state;
|
||||
SpiceVDIPortInterface *sif;
|
||||
VDIReadBuf *dispatch_buf;
|
||||
int total = 0;
|
||||
int n;
|
||||
|
||||
if (reds->mig_target) {
|
||||
if (!reds->agent_state.connected || reds->mig_target) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (reds->agent_state.plug_ref != INVALID_VD_OBJECT_REF) {
|
||||
sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceVDIPortInterface, base);
|
||||
while (reds->agent_state.connected) {
|
||||
switch (state->read_state) {
|
||||
case VDI_PORT_READ_STATE_READ_HADER:
|
||||
n = vdagent->read(vdagent, state->plug_ref, state->recive_pos, state->recive_len);
|
||||
n = sif->read(vdagent, state->recive_pos, state->recive_len);
|
||||
if (!n) {
|
||||
return total;
|
||||
}
|
||||
@ -1262,7 +1272,7 @@ static int read_from_vdi_port()
|
||||
state->read_state = VDI_PORT_READ_STATE_READ_DATA;
|
||||
}
|
||||
case VDI_PORT_READ_STATE_READ_DATA:
|
||||
n = vdagent->read(vdagent, state->plug_ref, state->recive_pos, state->recive_len);
|
||||
n = sif->read(vdagent, state->recive_pos, state->recive_len);
|
||||
if (!n) {
|
||||
return total;
|
||||
}
|
||||
@ -1287,7 +1297,7 @@ static int read_from_vdi_port()
|
||||
return total;
|
||||
}
|
||||
|
||||
static void reds_agent_wakeup(VDIPortPlug *plug)
|
||||
__visible__ void spice_server_vdi_port_wakeup(SpiceVDIPortInstance *sin)
|
||||
{
|
||||
while (write_to_vdi_port() || read_from_vdi_port());
|
||||
}
|
||||
@ -1385,7 +1395,7 @@ static void main_channel_send_migrate_data_item(RedsOutItem *in_item, struct iov
|
||||
item->data.serial = reds->serial;
|
||||
item->data.ping_id = reds->ping_id;
|
||||
|
||||
item->data.agent_connected = !!state->plug_ref;
|
||||
item->data.agent_connected = !!state->connected;
|
||||
item->data.client_agent_started = state->client_agent_started;
|
||||
item->data.num_client_tokens = state->num_client_tokens;
|
||||
item->data.send_tokens = state->send_tokens;
|
||||
@ -1634,13 +1644,13 @@ static void main_channel_recive_migrate_data(MainMigrateData *data, uint8_t *end
|
||||
|
||||
|
||||
if (!data->agent_connected) {
|
||||
if (state->plug_ref) {
|
||||
if (state->connected) {
|
||||
reds_send_agent_connected();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->plug_ref == INVALID_VD_OBJECT_REF) {
|
||||
if (!state->connected) {
|
||||
reds_send_agent_disconnected();
|
||||
return;
|
||||
}
|
||||
@ -2054,9 +2064,11 @@ static void reds_handle_main_link(RedLinkInfo *link)
|
||||
reds_show_new_channel(link);
|
||||
__reds_release_link(link);
|
||||
if (vdagent) {
|
||||
reds->agent_state.plug_ref = vdagent->plug(vdagent, &reds->agent_state.plug);
|
||||
if (reds->agent_state.plug_ref == INVALID_VD_OBJECT_REF) {
|
||||
PANIC("vdagent plug failed");
|
||||
SpiceVDIPortInterface *sif;
|
||||
sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceVDIPortInterface, base);
|
||||
reds->agent_state.connected = 1;
|
||||
if (sif->state) {
|
||||
sif->state(vdagent, reds->agent_state.connected);
|
||||
}
|
||||
reds->agent_state.plug_generation++;
|
||||
}
|
||||
@ -4017,16 +4029,21 @@ static void mm_timer_proc(void *opaque)
|
||||
core->timer_start(reds->mm_timer, MM_TIMER_GRANULARITY_MS);
|
||||
}
|
||||
|
||||
static void attach_to_red_agent(VDIPortInterface *interface)
|
||||
static void attach_to_red_agent(SpiceVDIPortInstance *sin)
|
||||
{
|
||||
VDIPortState *state = &reds->agent_state;
|
||||
SpiceVDIPortInterface *sif;
|
||||
|
||||
vdagent = interface;
|
||||
vdagent = sin;
|
||||
reds_update_mouse_mode();
|
||||
if (!reds->peer) {
|
||||
return;
|
||||
}
|
||||
state->plug_ref = vdagent->plug(vdagent, &state->plug);
|
||||
sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceVDIPortInterface, base);
|
||||
state->connected = 1;
|
||||
if (sif->state) {
|
||||
sif->state(vdagent, state->connected);
|
||||
}
|
||||
reds->agent_state.plug_generation++;
|
||||
|
||||
if (reds->mig_target) {
|
||||
@ -4144,18 +4161,18 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
|
||||
}
|
||||
snd_attach_record(SPICE_CONTAINEROF(sin, SpiceRecordInstance, base));
|
||||
|
||||
} else if (strcmp(interface->type, VD_INTERFACE_VDI_PORT) == 0) {
|
||||
red_printf("VD_INTERFACE_VDI_PORT");
|
||||
} else if (strcmp(interface->type, SPICE_INTERFACE_VDI_PORT) == 0) {
|
||||
red_printf("SPICE_INTERFACE_VDI_PORT");
|
||||
if (vdagent) {
|
||||
red_printf("vdi port already attached");
|
||||
return -1;
|
||||
}
|
||||
if (interface->major_version != VD_INTERFACE_VDI_PORT_MAJOR ||
|
||||
interface->minor_version < VD_INTERFACE_VDI_PORT_MINOR) {
|
||||
if (interface->major_version != SPICE_INTERFACE_VDI_PORT_MAJOR ||
|
||||
interface->minor_version < SPICE_INTERFACE_VDI_PORT_MINOR) {
|
||||
red_printf("unsuported vdi port interface");
|
||||
return -1;
|
||||
}
|
||||
attach_to_red_agent((VDIPortInterface *)interface);
|
||||
attach_to_red_agent(SPICE_CONTAINEROF(sin, SpiceVDIPortInstance, base));
|
||||
|
||||
} else if (strcmp(interface->type, VD_INTERFACE_NET_WIRE) == 0) {
|
||||
#ifdef HAVE_SLIRP
|
||||
@ -4199,9 +4216,9 @@ __visible__ int spice_server_remove_interface(SpiceBaseInstance *sin)
|
||||
red_printf("remove SPICE_INTERFACE_RECORD");
|
||||
snd_detach_record(SPICE_CONTAINEROF(sin, SpiceRecordInstance, base));
|
||||
|
||||
} else if (strcmp(interface->type, VD_INTERFACE_VDI_PORT) == 0) {
|
||||
red_printf("remove VD_INTERFACE_VDI_PORT");
|
||||
if (interface == (SpiceBaseInterface *)vdagent) {
|
||||
} else if (strcmp(interface->type, SPICE_INTERFACE_VDI_PORT) == 0) {
|
||||
red_printf("remove SPICE_INTERFACE_VDI_PORT");
|
||||
if (sin == &vdagent->base) {
|
||||
reds_agent_remove();
|
||||
}
|
||||
|
||||
@ -4294,10 +4311,6 @@ static void init_vd_agent_resources()
|
||||
ring_item_init(&buf->out_item.link);
|
||||
ring_add(&reds->agent_state.read_bufs, &buf->out_item.link);
|
||||
}
|
||||
|
||||
state->plug.major_version = VD_INTERFACE_VDI_PORT_MAJOR;
|
||||
state->plug.minor_version = VD_INTERFACE_VDI_PORT_MINOR;
|
||||
state->plug.wakeup = reds_agent_wakeup;
|
||||
}
|
||||
|
||||
const char *version_string = VERSION;
|
||||
|
||||
@ -367,27 +367,28 @@ void spice_server_record_stop(SpiceRecordInstance *sin);
|
||||
uint32_t spice_server_record_get_samples(SpiceRecordInstance *sin,
|
||||
uint32_t *samples, uint32_t bufsize);
|
||||
|
||||
#define VD_INTERFACE_VDI_PORT "vdi_port"
|
||||
#define VD_INTERFACE_VDI_PORT_MAJOR 1
|
||||
#define VD_INTERFACE_VDI_PORT_MINOR 1
|
||||
typedef struct VDIPortInterface VDIPortInterface;
|
||||
#define SPICE_INTERFACE_VDI_PORT "vdi_port"
|
||||
#define SPICE_INTERFACE_VDI_PORT_MAJOR 1
|
||||
#define SPICE_INTERFACE_VDI_PORT_MINOR 1
|
||||
typedef struct SpiceVDIPortInterface SpiceVDIPortInterface;
|
||||
typedef struct SpiceVDIPortInstance SpiceVDIPortInstance;
|
||||
typedef struct SpiceVDIPortState SpiceVDIPortState;
|
||||
|
||||
typedef struct VDIPortPlug VDIPortPlug;
|
||||
struct VDIPortPlug {
|
||||
uint32_t minor_version;
|
||||
uint32_t major_version;
|
||||
void (*wakeup)(VDIPortPlug *plug);
|
||||
};
|
||||
|
||||
struct VDIPortInterface {
|
||||
struct SpiceVDIPortInterface {
|
||||
SpiceBaseInterface base;
|
||||
|
||||
VDObjectRef (*plug)(VDIPortInterface *port, VDIPortPlug* plug);
|
||||
void (*unplug)(VDIPortInterface *port, VDObjectRef plug);
|
||||
int (*write)(VDIPortInterface *port, VDObjectRef plug, const uint8_t *buf, int len);
|
||||
int (*read)(VDIPortInterface *port, VDObjectRef plug, uint8_t *buf, int len);
|
||||
void (*state)(SpiceVDIPortInstance *sin, int connected);
|
||||
int (*write)(SpiceVDIPortInstance *sin, const uint8_t *buf, int len);
|
||||
int (*read)(SpiceVDIPortInstance *sin, uint8_t *buf, int len);
|
||||
};
|
||||
|
||||
struct SpiceVDIPortInstance {
|
||||
SpiceBaseInstance base;
|
||||
SpiceVDIPortState *st;
|
||||
};
|
||||
|
||||
void spice_server_vdi_port_wakeup(SpiceVDIPortInstance *sin);
|
||||
|
||||
#define VD_INTERFACE_NET_WIRE "net_wire"
|
||||
#define VD_INTERFACE_NET_WIRE_MAJOR 1
|
||||
#define VD_INTERFACE_NET_WIRE_MINOR 1
|
||||
|
||||
Loading…
Reference in New Issue
Block a user