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 uint8_t *spicevmc_red_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size) { SpiceVmcState *state; state = SPICE_CONTAINEROF(rcc->channel, SpiceVmcState, channel); switch (type) { case SPICE_MSGC_SPICEVMC_DATA: assert(!state->recv_from_client_buf); state->recv_from_client_buf = spice_char_device_write_buffer_get(state->chardev_st, rcc->client, size); if (!state->recv_from_client_buf) { spice_error("failed to allocate write buffer"); return NULL; } return state->recv_from_client_buf->buf; default: return spice_malloc(size); } }
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_device_disconnect(SpiceCharDeviceInstance *char_device) { SmartCardDeviceState *st = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base); smartcard_device_state_free(st); }
static void cursor_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item) { SpiceMarshaller *m = red_channel_client_get_marshaller(rcc); CursorChannelClient *ccc = RCC_TO_CCC(rcc); switch (pipe_item->type) { case PIPE_ITEM_TYPE_CURSOR: cursor_marshall(rcc, m, SPICE_CONTAINEROF(pipe_item, CursorPipeItem, base)); break; case PIPE_ITEM_TYPE_INVAL_ONE: red_marshall_inval(rcc, m, (CacheItem *)pipe_item); break; case PIPE_ITEM_TYPE_VERB: red_marshall_verb(rcc, (VerbItem*)pipe_item); break; case PIPE_ITEM_TYPE_CURSOR_INIT: red_reset_cursor_cache(rcc); red_marshall_cursor_init(rcc, m, pipe_item); break; case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE: red_reset_cursor_cache(rcc); red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_INVAL_ALL, NULL); break; default: spice_error("invalid pipe item type"); } cursor_channel_client_release_item_before_push(ccc, pipe_item); red_channel_client_begin_send_message(rcc); }
static void smartcard_channel_send_migrate_data(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item) { SmartCardChannelClient *scc; SmartCardDeviceState *state; SpiceMarshaller *m2; scc = SPICE_CONTAINEROF(rcc, SmartCardChannelClient, base); state = scc->smartcard_state; red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item); spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_SMARTCARD_MAGIC); spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_SMARTCARD_VERSION); if (!state) { spice_char_device_state_migrate_data_marshall_empty(m); spice_marshaller_add_uint8(m, 0); spice_marshaller_add_uint32(m, 0); spice_marshaller_add_uint32(m, 0); spice_debug("null char dev state"); } else { spice_char_device_state_migrate_data_marshall(state->chardev_st, m); spice_marshaller_add_uint8(m, state->reader_added); spice_marshaller_add_uint32(m, state->buf_used); m2 = spice_marshaller_get_ptr_submarshaller(m, 0); spice_marshaller_add_ref(m2, state->buf, state->buf_used); spice_debug("reader added %d partial read size %u", state->reader_added, state->buf_used); } }
static uint8_t *smartcard_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, uint16_t type, uint32_t 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 begin_decode(SpiceJpegDecoder *decoder, uint8_t* data, int data_size, int* out_width, int* out_height) { GlibJpegDecoder *d = SPICE_CONTAINEROF(decoder, GlibJpegDecoder, base); g_return_if_fail(data != NULL); g_return_if_fail(data_size != 0); if (d->_data) jpeg_abort_decompress(&d->_cinfo); d->_data = data; d->_data_size = data_size; d->_cinfo.src->next_input_byte = d->_data; d->_cinfo.src->bytes_in_buffer = d->_data_size; jpeg_read_header(&d->_cinfo, TRUE); d->_cinfo.out_color_space = JCS_RGB; d->_width = d->_cinfo.image_width; d->_height = d->_cinfo.image_height; *out_width = d->_width; *out_height = d->_height; }
void jpeg_decoder_destroy(SpiceJpegDecoder *decoder) { GlibJpegDecoder *d = SPICE_CONTAINEROF(decoder, GlibJpegDecoder, base); jpeg_destroy_decompress(&d->_cinfo); free(d); }
static void decode(SpiceJpegDecoder *decoder, uint8_t* dest, int stride, int format) { GlibJpegDecoder *d = SPICE_CONTAINEROF(decoder, GlibJpegDecoder, base); uint8_t* scan_line = g_alloca(d->_width * 3); converter_rgb_t converter = NULL; int row; switch (format) { case SPICE_BITMAP_FMT_24BIT: converter = convert_rgb_to_bgr; break; case SPICE_BITMAP_FMT_32BIT: converter = convert_rgb_to_bgrx; break; default: g_warning("bad bitmap format, %d", format); return; } g_return_if_fail(converter != NULL); jpeg_start_decompress(&d->_cinfo); for (row = 0; row < d->_height; row++) { jpeg_read_scanlines(&d->_cinfo, &scan_line, 1); converter(scan_line, dest, d->_width); dest += stride; } jpeg_finish_decompress(&d->_cinfo); }
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 void mjpeg_src_init(struct jpeg_decompress_struct *cinfo) { display_stream *st = SPICE_CONTAINEROF(cinfo->src, display_stream, mjpeg_src); uint8_t *data; cinfo->src->bytes_in_buffer = stream_get_current_frame(st, &data); cinfo->src->next_input_byte = data; }
static void smartcard_char_device_attach( SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel) { SmartCardDeviceState *st = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base); if (st->attached == TRUE) { return; } st->attached = TRUE; VSCMsgHeader vheader = {.type = VSC_ReaderAdd, .reader_id=st->reader_id, .length=0}; smartcard_channel_write_to_reader(smartcard_channel, &vheader); } static void smartcard_char_device_detach( SpiceCharDeviceInstance *char_device, SmartCardChannel *smartcard_channel) { SmartCardDeviceState *st = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base); if (st->attached == FALSE) { return; } st->attached = FALSE; VSCMsgHeader vheader = {.type = VSC_ReaderRemove, .reader_id=st->reader_id, .length=0}; smartcard_channel_write_to_reader(smartcard_channel, &vheader); } static int smartcard_channel_config_socket(RedChannel *channel) { return TRUE; } static uint8_t *smartcard_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header) { //red_printf("allocing %d bytes", msg_header->size); return spice_malloc(msg_header->size); } static void smartcard_channel_release_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header, uint8_t *msg) { red_printf("freeing %d bytes", msg_header->size); free(msg); }
static void spicevmc_red_channel_send_data(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item) { SpiceVmcPipeItem *i = SPICE_CONTAINEROF(item, SpiceVmcPipeItem, base); red_channel_client_init_send_data(rcc, SPICE_MSG_SPICEVMC_DATA, item); spice_marshaller_add_ref(m, i->buf, i->buf_used); }
static void cursor_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item) { CursorPipeItem *cursor_pipe_item; spice_return_if_fail(item); cursor_pipe_item = SPICE_CONTAINEROF(item, CursorPipeItem, base); cursor_pipe_item_ref(cursor_pipe_item); }
static void spicevmc_port_send_init(RedChannelClient *rcc) { SpiceVmcState *state = SPICE_CONTAINEROF(rcc->channel, SpiceVmcState, channel); SpiceCharDeviceInstance *sin = state->chardev_sin; PortInitPipeItem *item = spice_malloc(sizeof(PortInitPipeItem)); red_channel_pipe_item_init(rcc->channel, &item->base, PIPE_ITEM_TYPE_PORT_INIT); item->name = strdup(sin->portname); item->opened = state->port_opened; red_channel_client_pipe_add_push(rcc, &item->base); }
static void smartcard_channel_on_disconnect(RedChannelClient *rcc) { SmartCardChannelClient *scc = SPICE_CONTAINEROF(rcc, SmartCardChannelClient, base); if (scc->smartcard_state) { SmartCardDeviceState *st = scc->smartcard_state; smartcard_char_device_detach_client(scc); smartcard_char_device_notify_reader_remove(st); } }
static void spicevmc_red_channel_send_port_event(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item) { PortEventPipeItem *i = SPICE_CONTAINEROF(item, PortEventPipeItem, base); SpiceMsgPortEvent event; red_channel_client_init_send_data(rcc, SPICE_MSG_PORT_EVENT, item); event.event = i->event; spice_marshall_msg_port_event(m, &event); }
static int record_zlib_more_input(ZlibEncoderUsrContext *usr, uint8_t **input) { RecordEncoderData *data = SPICE_CONTAINEROF(usr, RecordEncoderData, base); if (data->buf == NULL) { fprintf(stderr, "%s: error: no more data\n", __FUNCTION__); exit(1); } *input = data->buf; data->buf = 0; return data->size; }
static int smartcard_char_device_add_to_readers(SpiceCharDeviceInstance *char_device) { SmartCardDeviceState* state = SPICE_CONTAINEROF( char_device->st, SmartCardDeviceState, base); if (g_smartcard_readers.num >= SMARTCARD_MAX_READERS) { return -1; } state->reader_id = g_smartcard_readers.num; g_smartcard_readers.sin[g_smartcard_readers.num++] = char_device; return 0; }
static void cursor_marshall(RedChannelClient *rcc, SpiceMarshaller *m, CursorPipeItem *cursor_pipe_item) { CursorChannel *cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base); CursorChannelClient *ccc = RCC_TO_CCC(rcc); CursorItem *item = cursor_pipe_item->cursor_item; PipeItem *pipe_item = &cursor_pipe_item->base; RedCursorCmd *cmd; spice_return_if_fail(cursor_channel); cmd = item->red_cursor; switch (cmd->type) { case QXL_CURSOR_MOVE: { SpiceMsgCursorMove cursor_move; red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_MOVE, pipe_item); cursor_move.position = cmd->u.position; spice_marshall_msg_cursor_move(m, &cursor_move); break; } case QXL_CURSOR_SET: { SpiceMsgCursorSet cursor_set; AddBufInfo info; red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_SET, pipe_item); cursor_set.position = cmd->u.set.position; cursor_set.visible = cursor_channel->cursor_visible; cursor_fill(ccc, &cursor_set.cursor, item, &info); spice_marshall_msg_cursor_set(m, &cursor_set); add_buf_from_info(m, &info); break; } case QXL_CURSOR_HIDE: red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_HIDE, pipe_item); break; case QXL_CURSOR_TRAIL: { SpiceMsgCursorTrail cursor_trail; red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_TRAIL, pipe_item); cursor_trail.length = cmd->u.trail.length; cursor_trail.frequency = cmd->u.trail.frequency; spice_marshall_msg_cursor_trail(m, &cursor_trail); } break; default: spice_error("bad cursor command %d", cmd->type); } }
static void spicevmc_red_channel_send_migrate_data(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item) { SpiceVmcState *state; state = SPICE_CONTAINEROF(rcc->channel, SpiceVmcState, channel); red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item); spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_SPICEVMC_MAGIC); spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_SPICEVMC_VERSION); spice_char_device_state_migrate_data_marshall(state->chardev_st, m); }
static void cursor_channel_client_release_item_after_push(CursorChannelClient *ccc, PipeItem *item) { switch (item->type) { case PIPE_ITEM_TYPE_CURSOR: { CursorPipeItem *cursor_pipe_item = SPICE_CONTAINEROF(item, CursorPipeItem, base); put_cursor_pipe_item(ccc, cursor_pipe_item); break; } default: spice_critical("invalid item type"); } }
static void spicevmc_red_channel_send_port_init(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item) { PortInitPipeItem *i = SPICE_CONTAINEROF(item, PortInitPipeItem, base); SpiceMsgPortInit init; red_channel_client_init_send_data(rcc, SPICE_MSG_PORT_INIT, item); init.name = (uint8_t *)i->name; init.name_size = strlen(i->name) + 1; init.opened = i->opened; spice_marshall_msg_port_init(m, &init); }
static SpiceCharDeviceInstance *smartcard_readers_get_unattached() { int i; SmartCardDeviceState* state; for (i = 0; i < g_smartcard_readers.num; ++i) { state = SPICE_CONTAINEROF(g_smartcard_readers.sin[i]->st, SmartCardDeviceState, base); if (!state->attached) { return g_smartcard_readers.sin[i]; } } return NULL; }
static void set_client_capabilities(QXLInstance *qin, uint8_t client_present, uint8_t caps[58]) { Test *test = SPICE_CONTAINEROF(qin, Test, qxl_instance); printf("%s: present %d caps %d\n", __func__, client_present, caps[0]); if (test->on_client_connected && client_present) { test->on_client_connected(test); } if (test->on_client_disconnected && !client_present) { test->on_client_disconnected(test); } }
static int smartcard_channel_handle_message(RedChannelClient *rcc, uint16_t type, uint32_t size, uint8_t *msg) { VSCMsgHeader* vheader = (VSCMsgHeader*)msg; SmartCardChannelClient *scc = SPICE_CONTAINEROF(rcc, SmartCardChannelClient, base); if (type != SPICE_MSGC_SMARTCARD_DATA) { /* Handles seamless migration protocol. Also handles ack's, * spicy sends them while spicec does not */ return red_channel_client_handle_message(rcc, size, type, msg); } spice_assert(size == vheader->length + sizeof(VSCMsgHeader)); switch (vheader->type) { case VSC_ReaderAdd: smartcard_add_reader(scc, msg + sizeof(VSCMsgHeader)); return TRUE; break; case VSC_ReaderRemove: smartcard_remove_reader(scc, vheader->reader_id); return TRUE; break; case VSC_Init: // ignore - we should never get this anyway return TRUE; break; case VSC_Error: case VSC_ATR: case VSC_CardRemove: case VSC_APDU: break; // passed on to device default: printf("ERROR: unexpected message on smartcard channel\n"); return TRUE; } /* todo: fix */ if (vheader->reader_id >= g_smartcard_readers.num) { spice_printerr("ERROR: received message for non existing reader: %d, %d, %d", vheader->reader_id, vheader->type, vheader->length); return FALSE; } spice_assert(scc->write_buf->buf == msg); smartcard_channel_write_to_reader(scc->write_buf); return TRUE; }
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 smartcard_add_reader(SmartCardChannel *smartcard_channel, uint8_t *name) { // TODO - save name somewhere SpiceCharDeviceInstance *char_device = smartcard_readers_get_unattached(); SmartCardDeviceState *state; if (char_device != NULL) { state = SPICE_CONTAINEROF(char_device->st, SmartCardDeviceState, base); smartcard_char_device_attach(char_device, smartcard_channel); smartcard_push_reader_add_response(smartcard_channel, state->reader_id); } else { smartcard_push_error(smartcard_channel, VSCARD_UNDEFINED_READER_ID, VSC_CANNOT_ADD_MORE_READERS); } }