[Spice-devel] [PATCH 02/12] server: introduce inputs_channel, split from reds.c
Hans de Goede
hdegoede at redhat.com
Mon Dec 6 03:11:04 PST 2010
Ack.
On 12/06/2010 11:49 AM, Alon Levy wrote:
> ---
> server/Makefile.am | 1 +
> server/inputs_channel.c | 694 +++++++++++++++++++++++++++++++++++++++++++++++
> server/inputs_channel.h | 40 +++
> server/reds.c | 588 +++-------------------------------------
> server/reds.h | 8 +
> 5 files changed, 786 insertions(+), 545 deletions(-)
> create mode 100644 server/inputs_channel.c
> create mode 100644 server/inputs_channel.h
>
> diff --git a/server/Makefile.am b/server/Makefile.am
> index ff7b485..a7bbe15 100644
> --- a/server/Makefile.am
> +++ b/server/Makefile.am
> @@ -104,6 +104,7 @@ libspice_server_la_SOURCES = \
> red_parse_qxl.c \
> red_parse_qxl.h \
> reds.c \
> + inputs_channel.c \
> reds.h \
> stat.h \
> red_worker.c \
> diff --git a/server/inputs_channel.c b/server/inputs_channel.c
> new file mode 100644
> index 0000000..288724e
> --- /dev/null
> +++ b/server/inputs_channel.c
> @@ -0,0 +1,694 @@
> +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
> +/*
> + Copyright (C) 2009 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<netinet/in.h> // IPPROTO_TCP
> +#include<netinet/tcp.h> // TCP_NODELAY
> +#include<fcntl.h>
> +#include<stddef.h> // NULL
> +#include<errno.h>
> +#include<spice/macros.h>
> +#include<spice/vd_agent.h>
> +#include "common/marshaller.h"
> +#include "common/messages.h"
> +#include "server/demarshallers.h"
> +#include "server/generated_marshallers.h"
> +#include "spice.h"
> +#include "inputs_channel.h"
> +#include "red_common.h"
> +#include "reds.h"
> +
> +// TODO: RECEIVE_BUF_SIZE used to be the same for inputs_channel and main_channel
> +// since it was defined once in reds.c which contained both.
> +// Now that they are split we can give a more fitting value for inputs - what
> +// should it be?
> +#define REDS_AGENT_WINDOW_SIZE 10
> +#define REDS_NUM_INTERNAL_AGENT_MESSAGES 1
> +
> +// approximate max receive message size
> +#define RECEIVE_BUF_SIZE \
> + (4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
> +
> +#define SEND_BUF_SIZE 4096
> +
> +typedef struct IncomingHandler {
> + spice_parse_channel_func_t parser;
> + void *opaque;
> + int shut;
> + uint8_t buf[RECEIVE_BUF_SIZE];
> + uint32_t end_pos;
> + void (*handle_message)(void *opaque, size_t size, uint32_t type, void *message);
> +} IncomingHandler;
> +
> +typedef struct OutgoingHandler {
> + void *opaque;
> + uint8_t buf[SEND_BUF_SIZE];
> + uint8_t *now;
> + uint32_t length;
> + void (*select)(void *opaque, int select);
> + void (*may_write)(void *opaque);
> +} OutgoingHandler;
> +
> +
> +// Temporarily here to make splitting reds.c to inputs_channel.c easier,
> +// TODO - remove from here, leave private to inputs_channel.c
> +typedef struct InputsState {
> + Channel *channel;
> + RedsStreamContext *peer;
> + IncomingHandler in_handler;
> + OutgoingHandler out_handler;
> + VDAgentMouseState mouse_state;
> + uint32_t motion_count;
> + uint64_t serial; //migrate me
> +} InputsState;
> +
> +
> +// TODO: move to InputsState after InputsState lands here
> +// from reds_inputs.h
> +
> +static SpiceKbdInstance *keyboard = NULL;
> +static SpiceMouseInstance *mouse = NULL;
> +static SpiceTabletInstance *tablet = NULL;
> +
> +static SpiceTimer *key_modifiers_timer;
> +
> +static InputsState *inputs_state;
> +
> +#define KEY_MODIFIERS_TTL (1000 * 2) /*2sec*/
> +
> +#define SCROLL_LOCK_SCAN_CODE 0x46
> +#define NUM_LOCK_SCAN_CODE 0x45
> +#define CAPS_LOCK_SCAN_CODE 0x3a
> +
> +int inputs_inited(void)
> +{
> + return !!inputs_state;
> +}
> +
> +int inputs_set_keyboard(SpiceKbdInstance *_keyboard)
> +{
> + if (keyboard) {
> + red_printf("already have keyboard");
> + return -1;
> + }
> + keyboard = _keyboard;
> + keyboard->st = spice_new0(SpiceKbdState, 1);
> + return 0;
> +}
> +
> +int inputs_set_mouse(SpiceMouseInstance *_mouse)
> +{
> + if (mouse) {
> + red_printf("already have mouse");
> + return -1;
> + }
> + mouse = _mouse;
> + mouse->st = spice_new0(SpiceMouseState, 1);
> + return 0;
> +}
> +
> +int inputs_set_tablet(SpiceTabletInstance *_tablet)
> +{
> + if (tablet) {
> + red_printf("already have tablet");
> + return -1;
> + }
> + tablet = _tablet;
> + tablet->st = spice_new0(SpiceTabletState, 1);
> + return 0;
> +}
> +
> +int inputs_has_tablet(void)
> +{
> + return !!tablet;
> +}
> +
> +void inputs_detach_tablet(SpiceTabletInstance *_tablet)
> +{
> + red_printf("");
> + tablet = NULL;
> +}
> +
> +void inputs_set_tablet_logical_size(int x_res, int y_res)
> +{
> + SpiceTabletInterface *sif;
> +
> + sif = SPICE_CONTAINEROF(tablet->base.sif, SpiceTabletInterface, base);
> + sif->set_logical_size(tablet, x_res, y_res);
> +}
> +
> +const VDAgentMouseState *inputs_get_mouse_state(void)
> +{
> + ASSERT(inputs_state);
> + return&inputs_state->mouse_state;
> +}
> +
> +static int handle_incoming(RedsStreamContext *peer, IncomingHandler *handler)
> +{
> + for (;;) {
> + uint8_t *buf = handler->buf;
> + uint32_t pos = handler->end_pos;
> + uint8_t *end = buf + pos;
> + SpiceDataHeader *header;
> + int n;
> + n = peer->cb_read(peer->ctx, buf + pos, RECEIVE_BUF_SIZE - pos);
> + if (n<= 0) {
> + if (n == 0) {
> + return -1;
> + }
> + switch (errno) {
> + case EAGAIN:
> + return 0;
> + case EINTR:
> + break;
> + case EPIPE:
> + return -1;
> + default:
> + red_printf("%s", strerror(errno));
> + return -1;
> + }
> + } else {
> + pos += n;
> + end = buf + pos;
> + while (buf + sizeof(SpiceDataHeader)<= end&&
> + buf + sizeof(SpiceDataHeader) + (header = (SpiceDataHeader *)buf)->size<= end) {
> + uint8_t *data = (uint8_t *)(header+1);
> + size_t parsed_size;
> + uint8_t *parsed;
> + message_destructor_t parsed_free;
> +
> +
> + buf += sizeof(SpiceDataHeader) + header->size;
> + parsed = handler->parser(data, data + header->size, header->type,
> + SPICE_VERSION_MINOR,&parsed_size,&parsed_free);
> + if (parsed == NULL) {
> + red_printf("failed to parse message type %d", header->type);
> + return -1;
> + }
> + handler->handle_message(handler->opaque, parsed_size, header->type, parsed);
> + parsed_free(parsed);
> + if (handler->shut) {
> + return -1;
> + }
> + }
> + memmove(handler->buf, buf, (handler->end_pos = end - buf));
> + }
> + }
> +}
> +
> +static int handle_outgoing(RedsStreamContext *peer, OutgoingHandler *handler)
> +{
> + if (!handler->length) {
> + return 0;
> + }
> +
> + while (handler->length) {
> + int n;
> +
> + n = peer->cb_write(peer->ctx, handler->now, handler->length);
> + if (n<= 0) {
> + if (n == 0) {
> + return -1;
> + }
> + switch (errno) {
> + case EAGAIN:
> + return 0;
> + case EINTR:
> + break;
> + case EPIPE:
> + return -1;
> + default:
> + red_printf("%s", strerror(errno));
> + return -1;
> + }
> + } else {
> + handler->now += n;
> + handler->length -= n;
> + }
> + }
> + handler->select(handler->opaque, FALSE);
> + handler->may_write(handler->opaque);
> + return 0;
> +}
> +
> +#define OUTGOING_OK 0
> +#define OUTGOING_FAILED -1
> +#define OUTGOING_BLOCKED 1
> +
> +static int outgoing_write(RedsStreamContext *peer, OutgoingHandler *handler, void *in_data,
> + int length)
> +{
> + uint8_t *data = in_data;
> + ASSERT(length<= SEND_BUF_SIZE);
> + if (handler->length) {
> + return OUTGOING_BLOCKED;
> + }
> +
> + while (length) {
> + int n = peer->cb_write(peer->ctx, data, length);
> + if (n< 0) {
> + switch (errno) {
> + case EAGAIN:
> + handler->length = length;
> + memcpy(handler->buf, data, length);
> + handler->select(handler->opaque, TRUE);
> + return OUTGOING_OK;
> + case EINTR:
> + break;
> + case EPIPE:
> + return OUTGOING_FAILED;
> + default:
> + red_printf("%s", strerror(errno));
> + return OUTGOING_FAILED;
> + }
> + } else {
> + data += n;
> + length -= n;
> + }
> + }
> + return OUTGOING_OK;
> +}
> +
> +#define RED_MOUSE_STATE_TO_LOCAL(state) \
> + ((state& SPICE_MOUSE_BUTTON_MASK_LEFT) | \
> + ((state& SPICE_MOUSE_BUTTON_MASK_MIDDLE)<< 1) | \
> + ((state& SPICE_MOUSE_BUTTON_MASK_RIGHT)>> 1))
> +
> +#define RED_MOUSE_BUTTON_STATE_TO_AGENT(state) \
> + (((state& SPICE_MOUSE_BUTTON_MASK_LEFT) ? VD_AGENT_LBUTTON_MASK : 0) | \
> + ((state& SPICE_MOUSE_BUTTON_MASK_MIDDLE) ? VD_AGENT_MBUTTON_MASK : 0) | \
> + ((state& SPICE_MOUSE_BUTTON_MASK_RIGHT) ? VD_AGENT_RBUTTON_MASK : 0))
> +
> +static void activate_modifiers_watch()
> +{
> + core->timer_start(key_modifiers_timer, KEY_MODIFIERS_TTL);
> +}
> +
> +static void kbd_push_scan(SpiceKbdInstance *sin, uint8_t scan)
> +{
> + SpiceKbdInterface *sif;
> +
> + if (!sin) {
> + return;
> + }
> + sif = SPICE_CONTAINEROF(sin->base.sif, SpiceKbdInterface, base);
> + sif->push_scan_freg(sin, scan);
> +}
> +
> +static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
> +{
> + SpiceKbdInterface *sif;
> +
> + if (!sin) {
> + return 0;
> + }
> + sif = SPICE_CONTAINEROF(sin->base.sif, SpiceKbdInterface, base);
> + return sif->get_leds(sin);
> +}
> +
> +static SpiceMarshaller *marshaller_new_for_outgoing(InputsState *state, int type)
> +{
> + SpiceMarshaller *m;
> + SpiceDataHeader *header;
> +
> + m = spice_marshaller_new();
> + header = (SpiceDataHeader *)
> + spice_marshaller_reserve_space(m, sizeof(SpiceDataHeader));
> + header->serial = ++state->serial;
> + header->type = type;
> + header->sub_list = 0;
> +
> + return m;
> +}
> +
> +static int marshaller_outgoing_write(SpiceMarshaller *m,
> + InputsState *state)
> +{
> + SpiceDataHeader *header = (SpiceDataHeader *)spice_marshaller_get_ptr(m);
> + uint8_t *data;
> + size_t len;
> + int free_data;
> +
> + spice_marshaller_flush(m);
> + header->size = spice_marshaller_get_total_size(m) - sizeof(SpiceDataHeader);
> +
> + data = spice_marshaller_linearize(m, 0,&len,&free_data);
> +
> + if (outgoing_write(state->peer,&state->out_handler, data, len) != OUTGOING_OK) {
> + return FALSE;
> + }
> +
> + if (free_data) {
> + free(data);
> + }
> +
> + return TRUE;
> +}
> +
> +
> +static void inputs_handle_input(void *opaque, size_t size, uint32_t type, void *message)
> +{
> + InputsState *state = (InputsState *)opaque;
> + uint8_t *buf = (uint8_t *)message;
> + SpiceMarshaller *m;
> +
> + switch (type) {
> + case SPICE_MSGC_INPUTS_KEY_DOWN: {
> + SpiceMsgcKeyDown *key_up = (SpiceMsgcKeyDown *)buf;
> + if (key_up->code == CAPS_LOCK_SCAN_CODE || key_up->code == NUM_LOCK_SCAN_CODE ||
> + key_up->code == SCROLL_LOCK_SCAN_CODE) {
> + activate_modifiers_watch();
> + }
> + }
> + case SPICE_MSGC_INPUTS_KEY_UP: {
> + SpiceMsgcKeyDown *key_down = (SpiceMsgcKeyDown *)buf;
> + uint8_t *now = (uint8_t *)&key_down->code;
> + uint8_t *end = now + sizeof(key_down->code);
> + for (; now< end&& *now; now++) {
> + kbd_push_scan(keyboard, *now);
> + }
> + break;
> + }
> + case SPICE_MSGC_INPUTS_MOUSE_MOTION: {
> + SpiceMsgcMouseMotion *mouse_motion = (SpiceMsgcMouseMotion *)buf;
> +
> + if (++state->motion_count % SPICE_INPUT_MOTION_ACK_BUNCH == 0) {
> + m = marshaller_new_for_outgoing(state, SPICE_MSG_INPUTS_MOUSE_MOTION_ACK);
> + if (!marshaller_outgoing_write(m, state)) {
> + red_printf("motion ack failed");
> + reds_disconnect();
> + }
> + spice_marshaller_destroy(m);
> + }
> + if (mouse&& reds_get_mouse_mode() == SPICE_MOUSE_MODE_SERVER) {
> + SpiceMouseInterface *sif;
> + sif = SPICE_CONTAINEROF(mouse->base.sif, SpiceMouseInterface, base);
> + sif->motion(mouse,
> + mouse_motion->dx, mouse_motion->dy, 0,
> + RED_MOUSE_STATE_TO_LOCAL(mouse_motion->buttons_state));
> + }
> + break;
> + }
> + case SPICE_MSGC_INPUTS_MOUSE_POSITION: {
> + SpiceMsgcMousePosition *pos = (SpiceMsgcMousePosition *)buf;
> +
> + if (++state->motion_count % SPICE_INPUT_MOTION_ACK_BUNCH == 0) {
> + m = marshaller_new_for_outgoing(state, SPICE_MSG_INPUTS_MOUSE_MOTION_ACK);
> + if (!marshaller_outgoing_write(m, state)) {
> + red_printf("position ack failed");
> + reds_disconnect();
> + }
> + spice_marshaller_destroy(m);
> + }
> + if (reds_get_mouse_mode() != SPICE_MOUSE_MODE_CLIENT) {
> + break;
> + }
> + ASSERT((reds_get_agent_mouse()&& reds_has_vdagent()) || tablet);
> + if (!reds_get_agent_mouse() || !reds_has_vdagent()) {
> + SpiceTabletInterface *sif;
> + sif = SPICE_CONTAINEROF(tablet->base.sif, SpiceTabletInterface, base);
> + sif->position(tablet, pos->x, pos->y, RED_MOUSE_STATE_TO_LOCAL(pos->buttons_state));
> + break;
> + }
> + VDAgentMouseState *mouse_state =&state->mouse_state;
> + mouse_state->x = pos->x;
> + mouse_state->y = pos->y;
> + mouse_state->buttons = RED_MOUSE_BUTTON_STATE_TO_AGENT(pos->buttons_state);
> + mouse_state->display_id = pos->display_id;
> + reds_handle_agent_mouse_event(mouse_state);
> + break;
> + }
> + case SPICE_MSGC_INPUTS_MOUSE_PRESS: {
> + SpiceMsgcMousePress *mouse_press = (SpiceMsgcMousePress *)buf;
> + int dz = 0;
> + if (mouse_press->button == SPICE_MOUSE_BUTTON_UP) {
> + dz = -1;
> + } else if (mouse_press->button == SPICE_MOUSE_BUTTON_DOWN) {
> + dz = 1;
> + }
> + if (reds_get_mouse_mode() == SPICE_MOUSE_MODE_CLIENT) {
> + if (reds_get_agent_mouse()&& reds_has_vdagent()) {
> + inputs_state->mouse_state.buttons =
> + RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_press->buttons_state) |
> + (dz == -1 ? VD_AGENT_UBUTTON_MASK : 0) |
> + (dz == 1 ? VD_AGENT_DBUTTON_MASK : 0);
> + reds_handle_agent_mouse_event(&inputs_state->mouse_state);
> + } else if (tablet) {
> + SpiceTabletInterface *sif;
> + sif = SPICE_CONTAINEROF(tablet->base.sif, SpiceTabletInterface, base);
> + sif->wheel(tablet, dz, RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state));
> + }
> + } else if (mouse) {
> + SpiceMouseInterface *sif;
> + sif = SPICE_CONTAINEROF(mouse->base.sif, SpiceMouseInterface, base);
> + sif->motion(mouse, 0, 0, dz,
> + RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state));
> + }
> + break;
> + }
> + case SPICE_MSGC_INPUTS_MOUSE_RELEASE: {
> + SpiceMsgcMouseRelease *mouse_release = (SpiceMsgcMouseRelease *)buf;
> + if (reds_get_mouse_mode() == SPICE_MOUSE_MODE_CLIENT) {
> + if (reds_get_agent_mouse()&& reds_has_vdagent()) {
> + inputs_state->mouse_state.buttons =
> + RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_release->buttons_state);
> + reds_handle_agent_mouse_event(&inputs_state->mouse_state);
> + } else if (tablet) {
> + SpiceTabletInterface *sif;
> + sif = SPICE_CONTAINEROF(tablet->base.sif, SpiceTabletInterface, base);
> + sif->buttons(tablet, RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state));
> + }
> + } else if (mouse) {
> + SpiceMouseInterface *sif;
> + sif = SPICE_CONTAINEROF(mouse->base.sif, SpiceMouseInterface, base);
> + sif->buttons(mouse,
> + RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state));
> + }
> + break;
> + }
> + case SPICE_MSGC_INPUTS_KEY_MODIFIERS: {
> + SpiceMsgcKeyModifiers *modifiers = (SpiceMsgcKeyModifiers *)buf;
> + uint8_t leds;
> +
> + if (!keyboard) {
> + break;
> + }
> + leds = kbd_get_leds(keyboard);
> + if ((modifiers->modifiers& SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK) !=
> + (leds& SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK)) {
> + kbd_push_scan(keyboard, SCROLL_LOCK_SCAN_CODE);
> + kbd_push_scan(keyboard, SCROLL_LOCK_SCAN_CODE | 0x80);
> + }
> + if ((modifiers->modifiers& SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK) !=
> + (leds& SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK)) {
> + kbd_push_scan(keyboard, NUM_LOCK_SCAN_CODE);
> + kbd_push_scan(keyboard, NUM_LOCK_SCAN_CODE | 0x80);
> + }
> + if ((modifiers->modifiers& SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK) !=
> + (leds& SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK)) {
> + kbd_push_scan(keyboard, CAPS_LOCK_SCAN_CODE);
> + kbd_push_scan(keyboard, CAPS_LOCK_SCAN_CODE | 0x80);
> + }
> + activate_modifiers_watch();
> + break;
> + }
> + case SPICE_MSGC_DISCONNECTING:
> + break;
> + default:
> + red_printf("unexpected type %d", type);
> + }
> +}
> +
> +static void inputs_relase_keys(void)
> +{
> + kbd_push_scan(keyboard, 0x2a | 0x80); //LSHIFT
> + kbd_push_scan(keyboard, 0x36 | 0x80); //RSHIFT
> + kbd_push_scan(keyboard, 0xe0); kbd_push_scan(keyboard, 0x1d | 0x80); //RCTRL
> + kbd_push_scan(keyboard, 0x1d | 0x80); //LCTRL
> + kbd_push_scan(keyboard, 0xe0); kbd_push_scan(keyboard, 0x38 | 0x80); //RALT
> + kbd_push_scan(keyboard, 0x38 | 0x80); //LALT
> +}
> +
> +static void inputs_event(int fd, int event, void *data)
> +{
> + if (data != inputs_state) {
> + return; // shutdown already happened
> + }
> +
> + if (event& SPICE_WATCH_EVENT_READ) {
> + if (handle_incoming(inputs_state->peer,&inputs_state->in_handler)) {
> + inputs_relase_keys();
> + core->watch_remove(inputs_state->peer->watch);
> + inputs_state->peer->watch = NULL;
> + if (inputs_state->channel) {
> + inputs_state->channel->data = NULL;
> + }
> + inputs_state->peer->cb_free(inputs_state->peer);
> + free(inputs_state);
> + inputs_state = NULL;
> + }
> + }
> + if (event& SPICE_WATCH_EVENT_WRITE) {
> + if (handle_outgoing(inputs_state->peer,&inputs_state->out_handler)) {
> + reds_disconnect();
> + }
> + }
> +}
> +
> +
> +static void inputs_shutdown(Channel *channel)
> +{
> + InputsState *state = (InputsState *)channel->data;
> + if (state) {
> + state->in_handler.shut = TRUE;
> + shutdown(state->peer->socket, SHUT_RDWR);
> + channel->data = NULL;
> + state->channel = NULL;
> + inputs_state = NULL;
> + }
> +}
> +
> +static void inputs_migrate(Channel *channel)
> +{
> + InputsState *state = (InputsState *)channel->data;
> + SpiceMarshaller *m;
> + SpiceMsgMigrate migrate;
> +
> + m = marshaller_new_for_outgoing(state, SPICE_MSG_MIGRATE);
> +
> + migrate.flags = 0;
> + spice_marshall_msg_migrate(m,&migrate);
> +
> + if (!marshaller_outgoing_write(m, state)) {
> + red_printf("write failed");
> + }
> + spice_marshaller_destroy(m);
> +}
> +
> +static void inputs_select(void *opaque, int select)
> +{
> + int eventmask = SPICE_WATCH_EVENT_READ;
> + red_printf("");
> +
> + ASSERT(opaque == inputs_state);
> + if (select) {
> + eventmask |= SPICE_WATCH_EVENT_WRITE;
> + }
> + core->watch_update_mask(inputs_state->peer->watch, eventmask);
> +}
> +
> +static void inputs_may_write(void *opaque)
> +{
> + red_printf("");
> +}
> +
> +static void inputs_link(Channel *channel, RedsStreamContext *peer, int migration,
> + int num_common_caps, uint32_t *common_caps, int num_caps,
> + uint32_t *caps)
> +{
> + int delay_val;
> + int flags;
> +
> + red_printf("");
> + ASSERT(channel->data == NULL);
> +
> + inputs_state = spice_new0(InputsState, 1);
> +
> + delay_val = 1;
> + if (setsockopt(peer->socket, IPPROTO_TCP, TCP_NODELAY,&delay_val, sizeof(delay_val)) == -1) {
> + red_printf("setsockopt failed, %s", strerror(errno));
> + }
> +
> + if ((flags = fcntl(peer->socket, F_GETFL)) == -1 ||
> + fcntl(peer->socket, F_SETFL, flags | O_ASYNC) == -1) {
> + red_printf("fcntl failed, %s", strerror(errno));
> + }
> +
> + inputs_state->peer = peer;
> + inputs_state->channel = channel;
> + inputs_state->in_handler.parser = spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL);
> + inputs_state->in_handler.opaque = inputs_state;
> + inputs_state->in_handler.handle_message = inputs_handle_input;
> + inputs_state->out_handler.length = 0;
> + inputs_state->out_handler.opaque = inputs_state;
> + inputs_state->out_handler.select = inputs_select;
> + inputs_state->out_handler.may_write = inputs_may_write;
> + channel->data = inputs_state;
> + peer->watch = core->watch_add(peer->socket, SPICE_WATCH_EVENT_READ,
> + inputs_event, inputs_state);
> +
> + SpiceMarshaller *m;
> + SpiceMsgInputsInit inputs_init;
> + m = marshaller_new_for_outgoing(inputs_state, SPICE_MSG_INPUTS_INIT);
> + inputs_init.keyboard_modifiers = kbd_get_leds(keyboard);
> + spice_marshall_msg_inputs_init(m,&inputs_init);
> + if (!marshaller_outgoing_write(m, inputs_state)) {
> + red_printf("failed to send modifiers state");
> + reds_disconnect();
> + }
> + spice_marshaller_destroy(m);
> +}
> +
> +void inputs_send_keyboard_modifiers(uint8_t modifiers)
> +{
> + SpiceMsgInputsKeyModifiers key_modifiers;
> + SpiceMarshaller *m;
> +
> + if (!inputs_state) {
> + return;
> + }
> + ASSERT(inputs_state->peer);
> +
> + m = marshaller_new_for_outgoing(inputs_state,
> + SPICE_MSG_INPUTS_KEY_MODIFIERS);
> +
> + key_modifiers.modifiers = modifiers;
> + spice_marshall_msg_inputs_key_modifiers(m,&key_modifiers);
> +
> + if (!marshaller_outgoing_write(m, inputs_state)) {
> + red_printf("failed to send modifiers state");
> + reds_disconnect();
> + }
> + spice_marshaller_destroy(m);
> +}
> +
> +void inputs_on_keyboard_leds_change(void *opaque, uint8_t leds)
> +{
> + inputs_send_keyboard_modifiers(leds);
> +}
> +
> +static void key_modifiers_sender(void *opaque)
> +{
> + inputs_send_keyboard_modifiers(kbd_get_leds(keyboard));
> +}
> +
> +void inputs_init(void)
> +{
> + Channel *channel;
> +
> + channel = spice_new0(Channel, 1);
> + channel->type = SPICE_CHANNEL_INPUTS;
> + channel->link = inputs_link;
> + channel->shutdown = inputs_shutdown;
> + channel->migrate = inputs_migrate;
> + reds_register_channel(channel);
> +
> + if (!(key_modifiers_timer = core->timer_add(key_modifiers_sender, NULL))) {
> + red_error("key modifiers timer create failed");
> + }
> +}
> +
> diff --git a/server/inputs_channel.h b/server/inputs_channel.h
> new file mode 100644
> index 0000000..491c8a5
> --- /dev/null
> +++ b/server/inputs_channel.h
> @@ -0,0 +1,40 @@
> +/*
> + Copyright (C) 2009 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/>.
> +*/
> +
> +#ifndef _INPUTS_CHANNEL_H_
> +#define _INPUTS_CHANNEL_H_
> +
> +// Inputs channel, dealing with keyboard, mouse, tablet.
> +// This include should only be used by reds.c and inputs_channel.c
> +
> +#include<stdint.h>
> +#include<spice/vd_agent.h>
> +
> +void inputs_init(void);
> +int inputs_inited(void);
> +int inputs_has_tablet(void);
> +const VDAgentMouseState *inputs_get_mouse_state(void);
> +void inputs_send_keyboard_modifiers(uint8_t modifiers);
> +void inputs_on_keyboard_leds_change(void *opaque, uint8_t leds);
> +int inputs_set_keyboard(SpiceKbdInstance *_keyboard);
> +int inputs_set_mouse(SpiceMouseInstance *_mouse);
> +int inputs_set_tablet(SpiceTabletInstance *_tablet);
> +void inputs_detach_tablet(SpiceTabletInstance *_tablet);
> +void inputs_set_tablet_logical_size(int x_res, int y_res);
> +
> +#endif
> +
> diff --git a/server/reds.c b/server/reds.c
> index d77b9d9..4a8f5ee 100644
> --- a/server/reds.c
> +++ b/server/reds.c
> @@ -45,6 +45,7 @@
> #include<spice/protocol.h>
> #include<spice/vd_agent.h>
>
> +#include "inputs_channel.h"
> #include "red_common.h"
> #include "red_dispatcher.h"
> #include "snd_worker.h"
> @@ -60,9 +61,6 @@
> #endif
>
> SpiceCoreInterface *core = NULL;
> -static SpiceKbdInstance *keyboard = NULL;
> -static SpiceMouseInstance *mouse = NULL;
> -static SpiceTabletInstance *tablet = NULL;
> static SpiceCharDeviceInstance *vdagent = NULL;
>
> #define MIGRATION_NOTIFY_SPICE_KEY "spice_mig_ext"
> @@ -103,21 +101,19 @@ static void openssl_init();
>
> #define MIGRATE_TIMEOUT (1000 * 10) /* 10sec */
> #define PING_INTERVAL (1000 * 10)
> -#define KEY_MODIFIERS_TTL (1000 * 2) /*2sec*/
> #define MM_TIMER_GRANULARITY_MS (1000 / 30)
> #define MM_TIME_DELTA 400 /*ms*/
> #define VDI_PORT_WRITE_RETRY_TIMEOUT 100 /*ms*/
>
> -// approximate max receive message size
> +// approximate max receive message size for main channel
> #define RECEIVE_BUF_SIZE \
> (4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
>
> -#define SEND_BUF_SIZE 4096
> -
> #define SCROLL_LOCK_SCAN_CODE 0x46
> #define NUM_LOCK_SCAN_CODE 0x45
> #define CAPS_LOCK_SCAN_CODE 0x3a
>
> +// TODO - remove and use red_channel.h
> typedef struct IncomingHandler {
> spice_parse_channel_func_t parser;
> void *opaque;
> @@ -127,14 +123,6 @@ typedef struct IncomingHandler {
> void (*handle_message)(void *opaque, size_t size, uint32_t type, void *message);
> } IncomingHandler;
>
> -typedef struct OutgoingHandler {
> - void *opaque;
> - uint8_t buf[SEND_BUF_SIZE];
> - uint8_t *now;
> - uint32_t length;
> - void (*select)(void *opaque, int select);
> - void (*may_write)(void *opaque);
> -} OutgoingHandler;
>
> typedef struct TicketAuthentication {
> char password[SPICE_MAX_PASSWORD_LENGTH];
> @@ -205,17 +193,6 @@ typedef struct VDIPortState {
> int client_agent_started;
> } VDIPortState;
>
> -typedef struct InputsState {
> - Channel *channel;
> - RedsStreamContext *peer;
> - IncomingHandler in_handler;
> - OutgoingHandler out_handler;
> - VDAgentMouseState mouse_state;
> - int pending_mouse_event;
> - uint32_t motion_count;
> - uint64_t serial; //migrate me
> -} InputsState;
> -
> typedef struct RedsOutgoingData {
> Ring pipe;
> RedsOutItem *item;
> @@ -258,7 +235,7 @@ typedef struct RedsState {
> uint32_t link_id;
> uint64_t serial; //migrate me
> VDIPortState agent_state;
> - InputsState *inputs_state;
> + int pending_mouse_event;
>
> int mig_wait_connect;
> int mig_wait_disconnect;
> @@ -274,7 +251,6 @@ typedef struct RedsState {
> int dispatcher_allows_client_mouse;
> MonitorMode monitor_mode;
> SpiceTimer *mig_timer;
> - SpiceTimer *key_modifiers_timer;
> SpiceTimer *mm_timer;
> SpiceTimer *vdi_port_write_timer;
> int vdi_port_write_timer_started;
> @@ -727,7 +703,7 @@ static void reds_reset_outgoing()
> outgoing->vec = outgoing->vec_buf;
> }
>
> -static void reds_disconnect()
> +void reds_disconnect()
> {
> if (!reds->peer || reds->disconnecting) {
> return;
> @@ -829,79 +805,6 @@ static int handle_incoming(RedsStreamContext *peer, IncomingHandler *handler)
> }
> }
>
> -static int handle_outgoing(RedsStreamContext *peer, OutgoingHandler *handler)
> -{
> - if (!handler->length) {
> - return 0;
> - }
> -
> - while (handler->length) {
> - int n;
> -
> - n = peer->cb_write(peer->ctx, handler->now, handler->length);
> - if (n<= 0) {
> - if (n == 0) {
> - return -1;
> - }
> - switch (errno) {
> - case EAGAIN:
> - return 0;
> - case EINTR:
> - break;
> - case EPIPE:
> - return -1;
> - default:
> - red_printf("%s", strerror(errno));
> - return -1;
> - }
> - } else {
> - handler->now += n;
> - handler->length -= n;
> - }
> - }
> - handler->select(handler->opaque, FALSE);
> - handler->may_write(handler->opaque);
> - return 0;
> -}
> -
> -#define OUTGOING_OK 0
> -#define OUTGOING_FAILED -1
> -#define OUTGOING_BLOCKED 1
> -
> -static int outgoing_write(RedsStreamContext *peer, OutgoingHandler *handler, void *in_data,
> - int length)
> -{
> - uint8_t *data = in_data;
> - ASSERT(length<= SEND_BUF_SIZE);
> - if (handler->length) {
> - return OUTGOING_BLOCKED;
> - }
> -
> - while (length) {
> - int n = peer->cb_write(peer->ctx, data, length);
> - if (n< 0) {
> - switch (errno) {
> - case EAGAIN:
> - handler->length = length;
> - memcpy(handler->buf, data, length);
> - handler->select(handler->opaque, TRUE);
> - return OUTGOING_OK;
> - case EINTR:
> - break;
> - case EPIPE:
> - return OUTGOING_FAILED;
> - default:
> - red_printf("%s", strerror(errno));
> - return OUTGOING_FAILED;
> - }
> - } else {
> - data += n;
> - length -= n;
> - }
> - }
> - return OUTGOING_OK;
> -}
> -
> static RedsOutItem *new_out_item(uint32_t type)
> {
> RedsOutItem *item;
> @@ -1039,6 +942,11 @@ static void reds_send_mouse_mode()
> reds_push_pipe_item(item);
> }
>
> +int reds_get_mouse_mode(void)
> +{
> + return reds->mouse_mode;
> +}
> +
> static void reds_set_mouse_mode(uint32_t mode)
> {
> if (reds->mouse_mode == mode) {
> @@ -1049,12 +957,17 @@ static void reds_set_mouse_mode(uint32_t mode)
> reds_send_mouse_mode();
> }
>
> +int reds_get_agent_mouse(void)
> +{
> + return agent_mouse;
> +}
> +
> static void reds_update_mouse_mode()
> {
> int allowed = 0;
> int qxl_count = red_dispatcher_qxl_count();
>
> - if ((agent_mouse&& vdagent) || (tablet&& qxl_count == 1)) {
> + if ((agent_mouse&& vdagent) || (inputs_has_tablet()&& qxl_count == 1)) {
> allowed = reds->dispatcher_allows_client_mouse;
> }
> if (allowed == reds->is_client_mouse_allowed) {
> @@ -1326,26 +1239,31 @@ void vdagent_char_device_wakeup(SpiceCharDeviceInstance *sin)
> while (read_from_vdi_port());
> }
>
> -static void reds_handle_agent_mouse_event()
> +int reds_has_vdagent(void)
> +{
> + return !!vdagent;
> +}
> +
> +void reds_handle_agent_mouse_event(const VDAgentMouseState *mouse_state)
> {
> RingItem *ring_item;
> VDInternalBuf *buf;
>
> - if (!reds->inputs_state) {
> + if (!inputs_inited()) {
> return;
> }
> if (reds->mig_target || !(ring_item = ring_get_head(&reds->agent_state.internal_bufs))) {
> - reds->inputs_state->pending_mouse_event = TRUE;
> + reds->pending_mouse_event = TRUE;
> vdi_port_write_timer_start();
> return;
> }
> - reds->inputs_state->pending_mouse_event = FALSE;
> + reds->pending_mouse_event = FALSE;
> ring_remove(ring_item);
> buf = (VDInternalBuf *)ring_item;
> buf->base.now = (uint8_t *)&buf->base.chunk_header;
> buf->base.write_len = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) +
> sizeof(VDAgentMouseState);
> - buf->u.mouse_state = reds->inputs_state->mouse_state;
> + buf->u.mouse_state = *mouse_state;
> ring_add(&reds->agent_state.write_queue,&buf->base.link);
> write_to_vdi_port();
> }
> @@ -2090,400 +2008,17 @@ static void reds_handle_main_link(RedLinkInfo *link)
> ((state& SPICE_MOUSE_BUTTON_MASK_MIDDLE) ? VD_AGENT_MBUTTON_MASK : 0) | \
> ((state& SPICE_MOUSE_BUTTON_MASK_RIGHT) ? VD_AGENT_RBUTTON_MASK : 0))
>
> -static void activate_modifiers_watch()
> -{
> - core->timer_start(reds->key_modifiers_timer, KEY_MODIFIERS_TTL);
> -}
> -
> -static void kbd_push_scan(SpiceKbdInstance *sin, uint8_t scan)
> -{
> - SpiceKbdInterface *sif;
> -
> - if (!sin) {
> - return;
> - }
> - sif = SPICE_CONTAINEROF(sin->base.sif, SpiceKbdInterface, base);
> - sif->push_scan_freg(sin, scan);
> -}
> -
> -static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
> -{
> - SpiceKbdInterface *sif;
> -
> - if (!sin) {
> - return 0;
> - }
> - sif = SPICE_CONTAINEROF(sin->base.sif, SpiceKbdInterface, base);
> - return sif->get_leds(sin);
> -}
> -
> -static SpiceMarshaller *marshaller_new_for_outgoing(InputsState *state, int type)
> -{
> - SpiceMarshaller *m;
> - SpiceDataHeader *header;
> -
> - m = spice_marshaller_new();
> - header = (SpiceDataHeader *)
> - spice_marshaller_reserve_space(m, sizeof(SpiceDataHeader));
> - header->serial = ++state->serial;
> - header->type = type;
> - header->sub_list = 0;
> -
> - return m;
> -}
> -
> -static int marshaller_outgoing_write(SpiceMarshaller *m,
> - InputsState *state)
> -{
> - SpiceDataHeader *header = (SpiceDataHeader *)spice_marshaller_get_ptr(m);
> - uint8_t *data;
> - size_t len;
> - int free_data;
> -
> - spice_marshaller_flush(m);
> - header->size = spice_marshaller_get_total_size(m) - sizeof(SpiceDataHeader);
> -
> - data = spice_marshaller_linearize(m, 0,&len,&free_data);
> -
> - if (outgoing_write(state->peer,&state->out_handler, data, len) != OUTGOING_OK) {
> - return FALSE;
> - }
> -
> - if (free_data) {
> - free(data);
> - }
> -
> - return TRUE;
> -}
> -
> -
> -static void inputs_handle_input(void *opaque, size_t size, uint32_t type, void *message)
> -{
> - InputsState *state = (InputsState *)opaque;
> - uint8_t *buf = (uint8_t *)message;
> - SpiceMarshaller *m;
> -
> - switch (type) {
> - case SPICE_MSGC_INPUTS_KEY_DOWN: {
> - SpiceMsgcKeyDown *key_up = (SpiceMsgcKeyDown *)buf;
> - if (key_up->code == CAPS_LOCK_SCAN_CODE || key_up->code == NUM_LOCK_SCAN_CODE ||
> - key_up->code == SCROLL_LOCK_SCAN_CODE) {
> - activate_modifiers_watch();
> - }
> - }
> - case SPICE_MSGC_INPUTS_KEY_UP: {
> - SpiceMsgcKeyDown *key_down = (SpiceMsgcKeyDown *)buf;
> - uint8_t *now = (uint8_t *)&key_down->code;
> - uint8_t *end = now + sizeof(key_down->code);
> - for (; now< end&& *now; now++) {
> - kbd_push_scan(keyboard, *now);
> - }
> - break;
> - }
> - case SPICE_MSGC_INPUTS_MOUSE_MOTION: {
> - SpiceMsgcMouseMotion *mouse_motion = (SpiceMsgcMouseMotion *)buf;
> -
> - if (++state->motion_count % SPICE_INPUT_MOTION_ACK_BUNCH == 0) {
> - m = marshaller_new_for_outgoing(state, SPICE_MSG_INPUTS_MOUSE_MOTION_ACK);
> - if (!marshaller_outgoing_write(m, state)) {
> - red_printf("motion ack failed");
> - reds_disconnect();
> - }
> - spice_marshaller_destroy(m);
> - }
> - if (mouse&& reds->mouse_mode == SPICE_MOUSE_MODE_SERVER) {
> - SpiceMouseInterface *sif;
> - sif = SPICE_CONTAINEROF(mouse->base.sif, SpiceMouseInterface, base);
> - sif->motion(mouse,
> - mouse_motion->dx, mouse_motion->dy, 0,
> - RED_MOUSE_STATE_TO_LOCAL(mouse_motion->buttons_state));
> - }
> - break;
> - }
> - case SPICE_MSGC_INPUTS_MOUSE_POSITION: {
> - SpiceMsgcMousePosition *pos = (SpiceMsgcMousePosition *)buf;
> -
> - if (++state->motion_count % SPICE_INPUT_MOTION_ACK_BUNCH == 0) {
> - m = marshaller_new_for_outgoing(state, SPICE_MSG_INPUTS_MOUSE_MOTION_ACK);
> - if (!marshaller_outgoing_write(m, state)) {
> - red_printf("position ack failed");
> - reds_disconnect();
> - }
> - spice_marshaller_destroy(m);
> - }
> - if (reds->mouse_mode != SPICE_MOUSE_MODE_CLIENT) {
> - break;
> - }
> - ASSERT((agent_mouse&& vdagent) || tablet);
> - if (!agent_mouse || !vdagent) {
> - SpiceTabletInterface *sif;
> - sif = SPICE_CONTAINEROF(tablet->base.sif, SpiceTabletInterface, base);
> - sif->position(tablet, pos->x, pos->y, RED_MOUSE_STATE_TO_LOCAL(pos->buttons_state));
> - break;
> - }
> - VDAgentMouseState *mouse_state =&state->mouse_state;
> - mouse_state->x = pos->x;
> - mouse_state->y = pos->y;
> - mouse_state->buttons = RED_MOUSE_BUTTON_STATE_TO_AGENT(pos->buttons_state);
> - mouse_state->display_id = pos->display_id;
> - reds_handle_agent_mouse_event();
> - break;
> - }
> - case SPICE_MSGC_INPUTS_MOUSE_PRESS: {
> - SpiceMsgcMousePress *mouse_press = (SpiceMsgcMousePress *)buf;
> - int dz = 0;
> - if (mouse_press->button == SPICE_MOUSE_BUTTON_UP) {
> - dz = -1;
> - } else if (mouse_press->button == SPICE_MOUSE_BUTTON_DOWN) {
> - dz = 1;
> - }
> - if (reds->mouse_mode == SPICE_MOUSE_MODE_CLIENT) {
> - if (agent_mouse&& vdagent) {
> - reds->inputs_state->mouse_state.buttons =
> - RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_press->buttons_state) |
> - (dz == -1 ? VD_AGENT_UBUTTON_MASK : 0) |
> - (dz == 1 ? VD_AGENT_DBUTTON_MASK : 0);
> - reds_handle_agent_mouse_event();
> - } else if (tablet) {
> - SpiceTabletInterface *sif;
> - sif = SPICE_CONTAINEROF(tablet->base.sif, SpiceTabletInterface, base);
> - sif->wheel(tablet, dz, RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state));
> - }
> - } else if (mouse) {
> - SpiceMouseInterface *sif;
> - sif = SPICE_CONTAINEROF(mouse->base.sif, SpiceMouseInterface, base);
> - sif->motion(mouse, 0, 0, dz,
> - RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state));
> - }
> - break;
> - }
> - case SPICE_MSGC_INPUTS_MOUSE_RELEASE: {
> - SpiceMsgcMouseRelease *mouse_release = (SpiceMsgcMouseRelease *)buf;
> - if (reds->mouse_mode == SPICE_MOUSE_MODE_CLIENT) {
> - if (agent_mouse&& vdagent) {
> - reds->inputs_state->mouse_state.buttons =
> - RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_release->buttons_state);
> - reds_handle_agent_mouse_event();
> - } else if (tablet) {
> - SpiceTabletInterface *sif;
> - sif = SPICE_CONTAINEROF(tablet->base.sif, SpiceTabletInterface, base);
> - sif->buttons(tablet, RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state));
> - }
> - } else if (mouse) {
> - SpiceMouseInterface *sif;
> - sif = SPICE_CONTAINEROF(mouse->base.sif, SpiceMouseInterface, base);
> - sif->buttons(mouse,
> - RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state));
> - }
> - break;
> - }
> - case SPICE_MSGC_INPUTS_KEY_MODIFIERS: {
> - SpiceMsgcKeyModifiers *modifiers = (SpiceMsgcKeyModifiers *)buf;
> - uint8_t leds;
> -
> - if (!keyboard) {
> - break;
> - }
> - leds = kbd_get_leds(keyboard);
> - if ((modifiers->modifiers& SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK) !=
> - (leds& SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK)) {
> - kbd_push_scan(keyboard, SCROLL_LOCK_SCAN_CODE);
> - kbd_push_scan(keyboard, SCROLL_LOCK_SCAN_CODE | 0x80);
> - }
> - if ((modifiers->modifiers& SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK) !=
> - (leds& SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK)) {
> - kbd_push_scan(keyboard, NUM_LOCK_SCAN_CODE);
> - kbd_push_scan(keyboard, NUM_LOCK_SCAN_CODE | 0x80);
> - }
> - if ((modifiers->modifiers& SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK) !=
> - (leds& SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK)) {
> - kbd_push_scan(keyboard, CAPS_LOCK_SCAN_CODE);
> - kbd_push_scan(keyboard, CAPS_LOCK_SCAN_CODE | 0x80);
> - }
> - activate_modifiers_watch();
> - break;
> - }
> - case SPICE_MSGC_DISCONNECTING:
> - break;
> - default:
> - red_printf("unexpected type %d", type);
> - }
> -}
> -
> void reds_set_client_mouse_allowed(int is_client_mouse_allowed, int x_res, int y_res)
> {
> reds->monitor_mode.x_res = x_res;
> reds->monitor_mode.y_res = y_res;
> reds->dispatcher_allows_client_mouse = is_client_mouse_allowed;
> reds_update_mouse_mode();
> - if (reds->is_client_mouse_allowed&& tablet) {
> - SpiceTabletInterface *sif;
> - sif = SPICE_CONTAINEROF(tablet->base.sif, SpiceTabletInterface, base);
> - sif->set_logical_size(tablet, reds->monitor_mode.x_res, reds->monitor_mode.y_res);
> + if (reds->is_client_mouse_allowed&& inputs_has_tablet()) {
> + inputs_set_tablet_logical_size(reds->monitor_mode.x_res, reds->monitor_mode.y_res);
> }
> }
>
> -static void inputs_relase_keys(void)
> -{
> - kbd_push_scan(keyboard, 0x2a | 0x80); //LSHIFT
> - kbd_push_scan(keyboard, 0x36 | 0x80); //RSHIFT
> - kbd_push_scan(keyboard, 0xe0); kbd_push_scan(keyboard, 0x1d | 0x80); //RCTRL
> - kbd_push_scan(keyboard, 0x1d | 0x80); //LCTRL
> - kbd_push_scan(keyboard, 0xe0); kbd_push_scan(keyboard, 0x38 | 0x80); //RALT
> - kbd_push_scan(keyboard, 0x38 | 0x80); //LALT
> -}
> -
> -static void inputs_event(int fd, int event, void *data)
> -{
> - InputsState *inputs_state = data;
> -
> - if (event& SPICE_WATCH_EVENT_READ) {
> - if (handle_incoming(inputs_state->peer,&inputs_state->in_handler)) {
> - inputs_relase_keys();
> - core->watch_remove(inputs_state->peer->watch);
> - inputs_state->peer->watch = NULL;
> - if (inputs_state->channel) {
> - inputs_state->channel->data = NULL;
> - reds->inputs_state = NULL;
> - }
> - inputs_state->peer->cb_free(inputs_state->peer);
> - free(inputs_state);
> - }
> - }
> - if (event& SPICE_WATCH_EVENT_WRITE) {
> - if (handle_outgoing(inputs_state->peer,&inputs_state->out_handler)) {
> - reds_disconnect();
> - }
> - }
> -}
> -
> -
> -static void inputs_shutdown(Channel *channel)
> -{
> - InputsState *state = (InputsState *)channel->data;
> - if (state) {
> - state->in_handler.shut = TRUE;
> - shutdown(state->peer->socket, SHUT_RDWR);
> - channel->data = NULL;
> - state->channel = NULL;
> - reds->inputs_state = NULL;
> - }
> -}
> -
> -static void inputs_migrate(Channel *channel)
> -{
> - InputsState *state = (InputsState *)channel->data;
> - SpiceMarshaller *m;
> - SpiceMsgMigrate migrate;
> -
> - m = marshaller_new_for_outgoing(state, SPICE_MSG_MIGRATE);
> -
> - migrate.flags = 0;
> - spice_marshall_msg_migrate(m,&migrate);
> -
> - if (!marshaller_outgoing_write(m, state)) {
> - red_printf("write failed");
> - }
> - spice_marshaller_destroy(m);
> -}
> -
> -static void inputs_select(void *opaque, int select)
> -{
> - InputsState *inputs_state;
> - int eventmask = SPICE_WATCH_EVENT_READ;
> - red_printf("");
> -
> - inputs_state = (InputsState *)opaque;
> - if (select) {
> - eventmask |= SPICE_WATCH_EVENT_WRITE;
> - }
> - core->watch_update_mask(inputs_state->peer->watch, eventmask);
> -}
> -
> -static void inputs_may_write(void *opaque)
> -{
> - red_printf("");
> -}
> -
> -static void inputs_link(Channel *channel, RedsStreamContext *peer, int migration,
> - int num_common_caps, uint32_t *common_caps, int num_caps,
> - uint32_t *caps)
> -{
> - InputsState *inputs_state;
> - int delay_val;
> - int flags;
> -
> - red_printf("");
> - ASSERT(channel->data == NULL);
> -
> - inputs_state = spice_new0(InputsState, 1);
> -
> - delay_val = 1;
> - if (setsockopt(peer->socket, IPPROTO_TCP, TCP_NODELAY,&delay_val, sizeof(delay_val)) == -1) {
> - red_printf("setsockopt failed, %s", strerror(errno));
> - }
> -
> - if ((flags = fcntl(peer->socket, F_GETFL)) == -1 ||
> - fcntl(peer->socket, F_SETFL, flags | O_ASYNC) == -1) {
> - red_printf("fcntl failed, %s", strerror(errno));
> - }
> -
> - inputs_state->peer = peer;
> - inputs_state->channel = channel;
> - inputs_state->in_handler.parser = spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL);
> - inputs_state->in_handler.opaque = inputs_state;
> - inputs_state->in_handler.handle_message = inputs_handle_input;
> - inputs_state->out_handler.length = 0;
> - inputs_state->out_handler.opaque = inputs_state;
> - inputs_state->out_handler.select = inputs_select;
> - inputs_state->out_handler.may_write = inputs_may_write;
> - inputs_state->pending_mouse_event = FALSE;
> - channel->data = inputs_state;
> - reds->inputs_state = inputs_state;
> - peer->watch = core->watch_add(peer->socket, SPICE_WATCH_EVENT_READ,
> - inputs_event, inputs_state);
> -
> - SpiceMarshaller *m;
> - SpiceMsgInputsInit inputs_init;
> - m = marshaller_new_for_outgoing(inputs_state, SPICE_MSG_INPUTS_INIT);
> - inputs_init.keyboard_modifiers = kbd_get_leds(keyboard);
> - spice_marshall_msg_inputs_init(m,&inputs_init);
> - if (!marshaller_outgoing_write(m, inputs_state)) {
> - red_printf("failed to send modifiers state");
> - reds_disconnect();
> - }
> - spice_marshaller_destroy(m);
> -}
> -
> -static void reds_send_keyboard_modifiers(uint8_t modifiers)
> -{
> - Channel *channel = reds_find_channel(SPICE_CHANNEL_INPUTS, 0);
> - InputsState *state;
> - SpiceMsgInputsKeyModifiers key_modifiers;
> - SpiceMarshaller *m;
> -
> - if (!channel || !(state = (InputsState *)channel->data)) {
> - return;
> - }
> - ASSERT(state->peer);
> -
> - m = marshaller_new_for_outgoing(state, SPICE_MSG_INPUTS_KEY_MODIFIERS);
> -
> - key_modifiers.modifiers = modifiers;
> - spice_marshall_msg_inputs_key_modifiers(m,&key_modifiers);
> -
> - if (!marshaller_outgoing_write(m, state)) {
> - red_printf("failed to send modifiers state");
> - reds_disconnect();
> - }
> - spice_marshaller_destroy(m);
> -}
> -
> -static void reds_on_keyboard_leds_change(void *opaque, uint8_t leds)
> -{
> - reds_send_keyboard_modifiers(leds);
> -}
> -
> static void openssl_init(RedLinkInfo *link)
> {
> unsigned long f4 = RSA_F4;
> @@ -2496,18 +2031,6 @@ static void openssl_init(RedLinkInfo *link)
> BN_set_word(link->tiTicketing.bn, f4);
> }
>
> -static void inputs_init()
> -{
> - Channel *channel;
> -
> - channel = spice_new0(Channel, 1);
> - channel->type = SPICE_CHANNEL_INPUTS;
> - channel->link = inputs_link;
> - channel->shutdown = inputs_shutdown;
> - channel->migrate = inputs_migrate;
> - reds_register_channel(channel);
> -}
> -
> static void reds_handle_other_links(RedLinkInfo *link)
> {
> Channel *channel;
> @@ -3354,11 +2877,6 @@ static void migrate_timout(void *opaque)
> reds_mig_disconnect();
> }
>
> -static void key_modifiers_sender(void *opaque)
> -{
> - reds_send_keyboard_modifiers(kbd_get_leds(keyboard));
> -}
> -
> uint32_t reds_get_mm_time()
> {
> struct timespec time_space;
> @@ -3467,32 +2985,24 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
>
> if (strcmp(interface->type, SPICE_INTERFACE_KEYBOARD) == 0) {
> red_printf("SPICE_INTERFACE_KEYBOARD");
> - if (keyboard) {
> - red_printf("already have keyboard");
> - return -1;
> - }
> if (interface->major_version != SPICE_INTERFACE_KEYBOARD_MAJOR ||
> interface->minor_version< SPICE_INTERFACE_KEYBOARD_MINOR) {
> red_printf("unsupported keyboard interface");
> return -1;
> }
> - keyboard = SPICE_CONTAINEROF(sin, SpiceKbdInstance, base);
> - keyboard->st = spice_new0(SpiceKbdState, 1);
> -
> - } else if (strcmp(interface->type, SPICE_INTERFACE_MOUSE) == 0) {
> - red_printf("SPICE_INTERFACE_MOUSE");
> - if (mouse) {
> - red_printf("already have mouse");
> + if (inputs_set_keyboard(SPICE_CONTAINEROF(sin, SpiceKbdInstance, base)) != 0) {
> return -1;
> }
> + } else if (strcmp(interface->type, SPICE_INTERFACE_MOUSE) == 0) {
> + red_printf("SPICE_INTERFACE_MOUSE");
> if (interface->major_version != SPICE_INTERFACE_MOUSE_MAJOR ||
> interface->minor_version< SPICE_INTERFACE_MOUSE_MINOR) {
> red_printf("unsupported mouse interface");
> return -1;
> }
> - mouse = SPICE_CONTAINEROF(sin, SpiceMouseInstance, base);
> - mouse->st = spice_new0(SpiceMouseState, 1);
> -
> + if (inputs_set_mouse(SPICE_CONTAINEROF(sin, SpiceMouseInstance, base)) != 0) {
> + return -1;
> + }
> } else if (strcmp(interface->type, SPICE_INTERFACE_QXL) == 0) {
> QXLInstance *qxl;
>
> @@ -3510,23 +3020,17 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
>
> } else if (strcmp(interface->type, SPICE_INTERFACE_TABLET) == 0) {
> red_printf("SPICE_INTERFACE_TABLET");
> - if (tablet) {
> - red_printf("already have tablet");
> - return -1;
> - }
> if (interface->major_version != SPICE_INTERFACE_TABLET_MAJOR ||
> interface->minor_version< SPICE_INTERFACE_TABLET_MINOR) {
> red_printf("unsupported tablet interface");
> return -1;
> }
> - tablet = SPICE_CONTAINEROF(sin, SpiceTabletInstance, base);
> - tablet->st = spice_new0(SpiceTabletState, 1);
> + if (inputs_set_tablet(SPICE_CONTAINEROF(sin, SpiceTabletInstance, base)) != 0) {
> + return -1;
> + }
> reds_update_mouse_mode();
> if (reds->is_client_mouse_allowed) {
> - SpiceTabletInterface *sif;
> - sif = SPICE_CONTAINEROF(tablet->base.sif, SpiceTabletInterface, base);
> - sif->set_logical_size(tablet, reds->monitor_mode.x_res,
> - reds->monitor_mode.y_res);
> + inputs_set_tablet_logical_size(reds->monitor_mode.x_res, reds->monitor_mode.y_res);
> }
>
> } else if (strcmp(interface->type, SPICE_INTERFACE_PLAYBACK) == 0) {
> @@ -3587,11 +3091,8 @@ __visible__ int spice_server_remove_interface(SpiceBaseInstance *sin)
>
> if (strcmp(interface->type, SPICE_INTERFACE_TABLET) == 0) {
> red_printf("remove SPICE_INTERFACE_TABLET");
> - if (sin ==&tablet->base) {
> - tablet = NULL;
> - reds_update_mouse_mode();
> - }
> -
> + inputs_detach_tablet(SPICE_CONTAINEROF(sin, SpiceTabletInstance, base));
> + reds_update_mouse_mode();
> } else if (strcmp(interface->type, SPICE_INTERFACE_PLAYBACK) == 0) {
> red_printf("remove SPICE_INTERFACE_PLAYBACK");
> snd_detach_playback(SPICE_CONTAINEROF(sin, SpicePlaybackInstance, base));
> @@ -3627,8 +3128,8 @@ static void free_internal_agent_buff(VDIPortBuf *in_buf)
> VDIPortState *state =&reds->agent_state;
>
> ring_add(&state->internal_bufs,&in_buf->link);
> - if (reds->inputs_state&& reds->inputs_state->pending_mouse_event) {
> - reds_handle_agent_mouse_event();
> + if (inputs_inited()&& reds->pending_mouse_event) {
> + reds_handle_agent_mouse_event(inputs_get_mouse_state());
> }
> }
>
> @@ -3697,9 +3198,6 @@ static void do_spice_init(SpiceCoreInterface *core_interface)
> if (!(reds->mig_timer = core->timer_add(migrate_timout, NULL))) {
> red_error("migration timer create failed");
> }
> - if (!(reds->key_modifiers_timer = core->timer_add(key_modifiers_sender, NULL))) {
> - red_error("key modifiers timer create failed");
> - }
> if (!(reds->vdi_port_write_timer = core->timer_add(vdi_port_write_retry, NULL)))
> {
> red_error("vdi port write timer create failed");
> @@ -3999,7 +3497,7 @@ __visible__ int spice_server_add_renderer(SpiceServer *s, const char *name)
>
> __visible__ int spice_server_kbd_leds(SpiceKbdInstance *sin, int leds)
> {
> - reds_on_keyboard_leds_change(NULL, leds);
> + inputs_on_keyboard_leds_change(NULL, leds);
> return 0;
> }
>
> diff --git a/server/reds.h b/server/reds.h
> index e95aea5..7f656e3 100644
> --- a/server/reds.h
> +++ b/server/reds.h
> @@ -21,6 +21,7 @@
> #include<stdint.h>
> #include<openssl/ssl.h>
> #include<sys/uio.h>
> +#include<spice/vd_agent.h>
>
> #define __visible__ __attribute__ ((visibility ("default")))
>
> @@ -90,11 +91,18 @@ void reds_set_client_mouse_allowed(int is_client_mouse_allowed,
> int x_res, int y_res);
> void reds_register_channel(Channel *channel);
> void reds_unregister_channel(Channel *channel);
> +int reds_get_mouse_mode(void); // used by inputs_channel
> +int reds_get_agent_mouse(void); // used by inputs_channel
> +int reds_has_vdagent(void); // used by inputs channel
> +void reds_handle_agent_mouse_event(const VDAgentMouseState *mouse_state); // used by inputs_channel
>
> extern struct SpiceCoreInterface *core;
> extern uint64_t bitrate_per_sec;
>
> #define IS_LOW_BANDWIDTH() (bitrate_per_sec< 10 * 1024 * 1024)
>
> +// Temporary measures to make splitting reds.c to inputs_channel.c easier
> +void reds_disconnect(void);
> +
> #endif
>
More information about the Spice-devel
mailing list