static int spicevmc_red_channel_client_handle_message(RedChannelClient *rcc, uint16_t type, uint32_t size, uint8_t *msg) { SpiceVmcState *state; SpiceCharDeviceInstance *sin; SpiceCharDeviceInterface *sif; state = spicevmc_red_channel_client_get_state(rcc); 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); } return TRUE; }
void smartcard_char_device_wakeup(SpiceCharDeviceInstance *sin) { SmartCardDeviceState* state = SPICE_CONTAINEROF( sin->st, SmartCardDeviceState, base); SpiceCharDeviceInterface *sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base); VSCMsgHeader *vheader = (VSCMsgHeader*)state->buf; int n; int remaining; while ((n = sif->read(sin, state->buf_pos, state->buf_size - state->buf_used)) > 0) { state->buf_pos += n; state->buf_used += n; if (state->buf_used < sizeof(VSCMsgHeader)) { continue; } if (vheader->length > state->buf_size) { state->buf_size = MAX(state->buf_size*2, vheader->length + sizeof(VSCMsgHeader)); state->buf = spice_realloc(state->buf, state->buf_size); ASSERT(state->buf != NULL); } if (state->buf_used - sizeof(VSCMsgHeader) < vheader->length) { continue; } smartcard_char_device_on_message_from_device(state, vheader); remaining = state->buf_used - sizeof(VSCMsgHeader) > vheader->length; if (remaining > 0) { memcpy(state->buf, state->buf_pos, remaining); } state->buf_pos = state->buf; state->buf_used = remaining; } }
static void spicevmc_red_channel_client_on_disconnect(RedChannelClient *rcc) { SpiceVmcState *state; SpiceCharDeviceInstance *sin; SpiceCharDeviceInterface *sif; if (!rcc) { return; } state = SPICE_CONTAINEROF(rcc->channel, SpiceVmcState, channel); sin = state->chardev_sin; sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base); if (state->chardev_st) { if (spice_char_device_client_exists(state->chardev_st, rcc->client)) { spice_char_device_client_remove(state->chardev_st, rcc->client); } else { spice_printerr("client %p have already been removed from char dev %p", rcc->client, state->chardev_st); } } /* Don't destroy the rcc if it is already being destroyed, as then red_client_destroy/red_channel_client_destroy will already do this! */ if (!rcc->destroying) red_channel_client_destroy(rcc); state->rcc = NULL; if (sif->state) { sif->state(sin, 0); } }
static void smartcard_channel_write_to_reader( SmartCardChannel *smartcard_channel, VSCMsgHeader *vheader) { SpiceCharDeviceInstance *sin; SpiceCharDeviceInterface *sif; uint32_t n; ASSERT(vheader->reader_id >= 0 && vheader->reader_id <= g_smartcard_readers.num); sin = g_smartcard_readers.sin[vheader->reader_id]; sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base); n = sif->write(sin, (uint8_t*)vheader, vheader->length + sizeof(VSCMsgHeader)); // TODO - add ring ASSERT(n == vheader->length + sizeof(VSCMsgHeader)); }
static void spicevmc_connect(RedChannel *channel, RedClient *client, RedsStream *stream, int migration, int num_common_caps, uint32_t *common_caps, int num_caps, uint32_t *caps) { RedChannelClient *rcc; SpiceVmcState *state; SpiceCharDeviceInstance *sin; SpiceCharDeviceInterface *sif; state = SPICE_CONTAINEROF(channel, SpiceVmcState, channel); sin = state->chardev_sin; sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base); if (state->rcc) { spice_printerr("channel client %d:%d (%p) already connected, refusing second connection", channel->type, channel->id, state->rcc); // TODO: notify client in advance about the in use channel using // SPICE_MSG_MAIN_CHANNEL_IN_USE (for example) reds_stream_free(stream); return; } rcc = red_channel_client_create(sizeof(RedChannelClient), channel, client, stream, FALSE, num_common_caps, common_caps, num_caps, caps); if (!rcc) { return; } 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"); red_channel_client_disconnect(rcc); return; } if (sif->state) { sif->state(sin, 1); } }
static SpiceCharDeviceMsgToClient *spicevmc_chardev_read_msg_from_dev(SpiceCharDeviceInstance *sin, void *opaque) { SpiceVmcState *state = opaque; SpiceCharDeviceInterface *sif; SpiceVmcPipeItem *msg_item; int n; sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base); if (!state->rcc) { return NULL; } if (!state->pipe_item) { msg_item = spice_new0(SpiceVmcPipeItem, 1); msg_item->refs = 1; red_channel_pipe_item_init(&state->channel, &msg_item->base, PIPE_ITEM_TYPE_SPICEVMC_DATA); } else { spice_assert(state->pipe_item->buf_used == 0); msg_item = state->pipe_item; state->pipe_item = NULL; } n = sif->read(sin, msg_item->buf, sizeof(msg_item->buf)); if (n > 0) { spice_debug("read from dev %d", n); msg_item->buf_used = n; return msg_item; } else { state->pipe_item = msg_item; return NULL; } }
SpiceCharDeviceMsgToClient *smartcard_read_msg_from_device(SpiceCharDeviceInstance *sin, void *opaque) { SmartCardDeviceState *state = opaque; SpiceCharDeviceInterface *sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base); VSCMsgHeader *vheader = (VSCMsgHeader*)state->buf; int n; int remaining; int actual_length; while ((n = sif->read(sin, state->buf_pos, state->buf_size - state->buf_used)) > 0) { MsgItem *msg_to_client; state->buf_pos += n; state->buf_used += n; if (state->buf_used < sizeof(VSCMsgHeader)) { continue; } smartcard_read_buf_prepare(state, vheader); actual_length = ntohl(vheader->length); if (state->buf_used - sizeof(VSCMsgHeader) < actual_length) { continue; } msg_to_client = smartcard_char_device_on_message_from_device(state, vheader); remaining = state->buf_used - sizeof(VSCMsgHeader) - actual_length; if (remaining > 0) { memcpy(state->buf, state->buf_pos, remaining); } state->buf_pos = state->buf; state->buf_used = remaining; if (msg_to_client) { return msg_to_client; } } return NULL; }