static void create_primary_surface(Test *test, uint32_t width, uint32_t height) { QXLDevSurfaceCreate surface = { 0, }; spice_assert(height <= MAX_HEIGHT); spice_assert(width <= MAX_WIDTH); spice_assert(height > 0); spice_assert(width > 0); surface.format = SPICE_SURFACE_FMT_32_xRGB; surface.width = test->primary_width = width; surface.height = test->primary_height = height; surface.stride = -width * 4; /* negative? */ surface.mouse_mode = TRUE; /* unused by red_worker */ surface.flags = 0; surface.type = 0; /* unused by red_worker */ surface.position = 0; /* unused by red_worker */ surface.mem = (uint64_t)&test->primary_surface; surface.group_id = MEM_SLOT_GROUP_ID; test->width = width; test->height = height; spice_qxl_create_primary_surface(&test->qxl_instance, 0, &surface); }
static void smartcard_channel_write_to_reader(SpiceCharDeviceWriteBuffer *write_buf) { SpiceCharDeviceInstance *sin; SmartCardDeviceState *st; VSCMsgHeader *vheader; uint32_t actual_length; vheader = (VSCMsgHeader *)write_buf->buf; actual_length = vheader->length; spice_assert(vheader->reader_id <= g_smartcard_readers.num); sin = g_smartcard_readers.sin[vheader->reader_id]; st = (SmartCardDeviceState *)spice_char_device_state_opaque_get(sin->st); spice_assert(!st->scc || st == st->scc->smartcard_state); /* protocol requires messages to be in network endianess */ vheader->type = htonl(vheader->type); vheader->length = htonl(vheader->length); vheader->reader_id = htonl(vheader->reader_id); write_buf->buf_used = actual_length + sizeof(VSCMsgHeader); /* pushing the buffer to the write queue; It will be released * when it will be fully consumed by the device */ spice_char_device_write_buffer_add(sin->st, write_buf); if (st->scc && write_buf == st->scc->write_buf) { st->scc->write_buf = NULL; } }
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 smartcard_channel_send_data(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item, VSCMsgHeader *vheader) { spice_assert(rcc); spice_assert(vheader); red_channel_client_init_send_data(rcc, SPICE_MSG_SMARTCARD_DATA, item); spice_marshaller_add_ref(m, (uint8_t*)vheader, sizeof(VSCMsgHeader)); if (vheader->length > 0) { spice_marshaller_add_ref(m, (uint8_t*)(vheader+1), vheader->length); } }
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 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; }
static struct QXLCommandExt *get_simple_command(void) { struct QXLCommandExt *ret = commands[commands_start % COMMANDS_SIZE]; spice_assert(commands_start < commands_end); commands_start++; return ret; }
static void release_resource(SPICE_GNUC_UNUSED QXLInstance *qin, struct QXLReleaseInfoExt release_info) { QXLCommandExt *ext = (QXLCommandExt*)(unsigned long)release_info.info->id; //printf("%s\n", __func__); spice_assert(release_info.group_id == MEM_SLOT_GROUP_ID); switch (ext->cmd.type) { case QXL_CMD_DRAW: test_spice_destroy_update((void*)ext); break; case QXL_CMD_SURFACE: free(ext); break; case QXL_CMD_CURSOR: { QXLCursorCmd *cmd = (QXLCursorCmd *)(unsigned long)ext->cmd.data; if (cmd->type == QXL_CURSOR_SET) { free(cmd); } free(ext); break; } default: abort(); } }
static void image_cache_put(SpiceImageCache *spice_cache, uint64_t id, pixman_image_t *image) { ImageCache *cache = SPICE_UPCAST(ImageCache, spice_cache); ImageCacheItem *item; #ifndef IMAGE_CACHE_AGE if (cache->num_items == IMAGE_CACHE_MAX_ITEMS) { SPICE_VERIFY(SPICE_OFFSETOF(ImageCacheItem, lru_link) == 0); ImageCacheItem *tail = (ImageCacheItem *)ring_get_tail(&cache->lru); spice_assert(tail); image_cache_remove(cache, tail); } #endif item = spice_new(ImageCacheItem, 1); item->id = id; #ifdef IMAGE_CACHE_AGE item->age = cache->age; #else cache->num_items++; #endif item->image = pixman_image_ref(image); ring_item_init(&item->lru_link); item->next = cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE]; cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE] = item; ring_add(&cache->lru, &item->lru_link); }
static void smartcard_init(void) { ChannelCbs channel_cbs = { NULL, }; ClientCbs client_cbs = { NULL, }; uint32_t migration_flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER; spice_assert(!g_smartcard_channel); channel_cbs.config_socket = smartcard_channel_client_config_socket; channel_cbs.on_disconnect = smartcard_channel_on_disconnect; channel_cbs.send_item = smartcard_channel_send_item; channel_cbs.hold_item = smartcard_channel_hold_pipe_item; channel_cbs.release_item = smartcard_channel_release_pipe_item; channel_cbs.alloc_recv_buf = smartcard_channel_alloc_msg_rcv_buf; channel_cbs.release_recv_buf = smartcard_channel_release_msg_rcv_buf; channel_cbs.handle_migrate_flush_mark = smartcard_channel_client_handle_migrate_flush_mark; channel_cbs.handle_migrate_data = smartcard_channel_client_handle_migrate_data; g_smartcard_channel = (SmartCardChannel*)red_channel_create(sizeof(SmartCardChannel), core, SPICE_CHANNEL_SMARTCARD, 0, FALSE /* handle_acks */, smartcard_channel_handle_message, &channel_cbs, migration_flags); if (!g_smartcard_channel) { spice_error("failed to allocate Smartcard Channel"); } client_cbs.connect = smartcard_connect_client; red_channel_register_client_cbs(&g_smartcard_channel->base, &client_cbs); reds_register_channel(&g_smartcard_channel->base); }
static void smartcard_remove_client(RedClient *client, void *opaque) { SmartCardDeviceState *dev = opaque; spice_printerr("smartcard state %p, client %p", dev, client); spice_assert(dev->scc && dev->scc->base.client == client); red_channel_client_shutdown(&dev->scc->base); }
static void spicevmc_char_dev_remove_client(RedClient *client, void *opaque) { SpiceVmcState *state = opaque; spice_printerr("vmc state %p, client %p", state, client); spice_assert(state->rcc && state->rcc->client == client); red_channel_client_shutdown(state->rcc); }
static void smartcard_send_msg_to_client(SpiceCharDeviceMsgToClient *msg, RedClient *client, void *opaque) { SmartCardDeviceState *dev = opaque; spice_assert(dev->scc && dev->scc->base.client == client); smartcard_channel_client_pipe_add_push(&dev->scc->base, &((MsgItem *)msg)->base); }
static inline int calc_compression_level(void) { spice_assert(streaming_video != STREAM_VIDEO_INVALID); if ((streaming_video != STREAM_VIDEO_OFF) || (image_compression != SPICE_IMAGE_COMPRESS_QUIC)) { return 0; } else { return 1; } }
void image_cache_localize(ImageCache *cache, SpiceImage **image_ptr, SpiceImage *image_store, Drawable *drawable) { SpiceImage *image = *image_ptr; if (image == NULL) { spice_assert(drawable != NULL); spice_assert(drawable->red_drawable->self_bitmap_image != NULL); *image_ptr = drawable->red_drawable->self_bitmap_image; return; } if (image_cache_hit(cache, image->descriptor.id)) { image_store->descriptor = image->descriptor; image_store->descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE; image_store->descriptor.flags = 0; *image_ptr = image_store; return; } switch (image->descriptor.type) { case SPICE_IMAGE_TYPE_QUIC: { image_store->descriptor = image->descriptor; image_store->u.quic = image->u.quic; *image_ptr = image_store; #ifdef IMAGE_CACHE_AGE image_store->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME; #else if (image_store->descriptor.width * image->descriptor.height >= 640 * 480) { image_store->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME; } #endif break; } case SPICE_IMAGE_TYPE_BITMAP: case SPICE_IMAGE_TYPE_SURFACE: /* nothing */ break; default: spice_error("invalid image type"); } }
static void spicevmc_chardev_send_msg_to_client(SpiceCharDeviceMsgToClient *msg, RedClient *client, void *opaque) { SpiceVmcState *state = opaque; SpiceVmcPipeItem *vmc_msg = msg; spice_assert(state->rcc->client == client); spicevmc_pipe_item_ref(vmc_msg); red_channel_client_pipe_add_push(state->rcc, &vmc_msg->base); }
static void cursor_channel_release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed) { CursorChannelClient *ccc = RCC_TO_CCC(rcc); spice_assert(item); if (item_pushed) { cursor_channel_client_release_item_after_push(ccc, item); } else { spice_debug("not pushed (%d)", item->type); cursor_channel_client_release_item_before_push(ccc, item); } }
static void smartcard_char_device_detach_client(SmartCardChannelClient *scc) { SmartCardDeviceState *st; if (!scc->smartcard_state) { return; } st = scc->smartcard_state; spice_assert(st->scc == scc); spice_char_device_client_remove(st->chardev_st, scc->base.client); scc->smartcard_state = NULL; st->scc = NULL; }
static void put_cursor_pipe_item(CursorChannelClient *ccc, CursorPipeItem *pipe_item) { spice_return_if_fail(pipe_item); spice_return_if_fail(pipe_item->refs > 0); if (--pipe_item->refs) { return; } spice_assert(!pipe_item_is_linked(&pipe_item->base)); cursor_item_unref(pipe_item->cursor_item); free(pipe_item); }
static void smartcard_channel_release_msg_rcv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size, uint8_t *msg) { 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->msg_in_write_buf) { spice_assert(!scc->write_buf); free(msg); } else { SpiceCharDeviceState *dev_st; if (scc->write_buf) { /* msg hasn't been pushed to the guest */ spice_assert(scc->write_buf->buf == msg); dev_st = scc->smartcard_state ? scc->smartcard_state->chardev_st : NULL; spice_char_device_write_buffer_release(dev_st, scc->write_buf); scc->write_buf = NULL; } } }
static void smartcard_device_state_restore_partial_read(SmartCardDeviceState *state, SpiceMigrateDataSmartcard *mig_data) { uint8_t *read_data; spice_debug("read_size %u", mig_data->read_size); read_data = (uint8_t *)mig_data + mig_data->read_data_ptr - sizeof(SpiceMigrateDataHeader); if (mig_data->read_size < sizeof(VSCMsgHeader)) { spice_assert(state->buf_size >= mig_data->read_size); } else { smartcard_read_buf_prepare(state, (VSCMsgHeader *)read_data); } memcpy(state->buf, read_data, mig_data->read_size); state->buf_used = mig_data->read_size; state->buf_pos = state->buf + mig_data->read_size; }
static void red_record_string(FILE *fd, RedMemSlotInfo *slots, int group_id, QXLPHYSICAL addr) { QXLString *qxl; size_t chunk_size; int error; qxl = (QXLString *)get_virt(slots, addr, sizeof(*qxl), group_id, &error); fprintf(fd, "data_size %d\n", qxl->data_size); fprintf(fd, "length %d\n", qxl->length); fprintf(fd, "flags %d\n", qxl->flags); chunk_size = red_record_data_chunks_ptr(fd, "string", slots, group_id, get_memslot_id(slots, addr), &qxl->chunk); spice_assert(chunk_size == qxl->data_size); }
static void async_read_handler(G_GNUC_UNUSED int fd, G_GNUC_UNUSED int event, void *data) { AsyncRead *async = (AsyncRead *)data; RedsStream *stream = async->stream; RedsState *reds = stream->priv->reds; for (;;) { int n = async->end - async->now; spice_assert(n > 0); n = reds_stream_read(stream, async->now, n); if (n <= 0) { int err = n < 0 ? errno: 0; switch (err) { case EAGAIN: if (!stream->watch) { stream->watch = reds_core_watch_add(reds, stream->socket, SPICE_WATCH_EVENT_READ, async_read_handler, async); } return; case EINTR: break; default: async_read_clear_handlers(async); if (async->error) { async->error(async->opaque, err); } return; } } else { async->now += n; if (async->now == async->end) { async_read_clear_handlers(async); async->done(async->opaque); return; } } } }
static void smartcard_remove_reader(SmartCardChannelClient *scc, uint32_t reader_id) { SpiceCharDeviceInstance *char_device = smartcard_readers_get(reader_id); SmartCardDeviceState *state; if (char_device == NULL) { smartcard_push_error(&scc->base, reader_id, VSC_GENERAL_ERROR); return; } state = spice_char_device_state_opaque_get(char_device->st); if (state->reader_added == FALSE) { smartcard_push_error(&scc->base, reader_id, VSC_GENERAL_ERROR); return; } spice_assert(scc->smartcard_state == state); smartcard_char_device_notify_reader_remove(state); }
static void image_cache_remove(ImageCache *cache, ImageCacheItem *item) { ImageCacheItem **now; now = &cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE]; for (;;) { spice_assert(*now); if (*now == item) { *now = item->next; break; } now = &(*now)->next; } ring_remove(&item->lru_link); pixman_image_unref(item->image); free(item); #ifndef IMAGE_CACHE_AGE cache->num_items--; #endif }
static void red_marshall_cursor_init(RedChannelClient *rcc, SpiceMarshaller *base_marshaller, PipeItem *pipe_item) { CursorChannel *cursor_channel; CursorChannelClient *ccc = RCC_TO_CCC(rcc); SpiceMsgCursorInit msg; AddBufInfo info; spice_assert(rcc); cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base); red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_INIT, NULL); msg.visible = cursor_channel->cursor_visible; msg.position = cursor_channel->cursor_position; msg.trail_length = cursor_channel->cursor_trail_length; msg.trail_frequency = cursor_channel->cursor_trail_frequency; cursor_fill(ccc, &msg.cursor, cursor_channel->item, &info); spice_marshall_msg_cursor_init(base_marshaller, &msg); add_buf_from_info(base_marshaller, &info); }
static int spicevmc_channel_client_handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message) { SpiceMigrateDataHeader *header; SpiceMigrateDataSpiceVmc *mig_data; SpiceVmcState *state; state = spicevmc_red_channel_client_get_state(rcc); header = (SpiceMigrateDataHeader *)message; mig_data = (SpiceMigrateDataSpiceVmc *)(header + 1); spice_assert(size >= sizeof(SpiceMigrateDataHeader) + sizeof(SpiceMigrateDataSpiceVmc)); if (!migration_protocol_validate_header(header, SPICE_MIGRATE_DATA_SPICEVMC_MAGIC, SPICE_MIGRATE_DATA_SPICEVMC_VERSION)) { spice_error("bad header"); return FALSE; } return spice_char_device_state_restore(state->chardev_st, &mig_data->base); }
static void red_record_stroke_ptr(FILE *fd, RedMemSlotInfo *slots, int group_id, QXLStroke *qxl, uint32_t flags) { int error; red_record_path(fd, slots, group_id, qxl->path); fprintf(fd, "attr.flags %d\n", qxl->attr.flags); if (qxl->attr.flags & SPICE_LINE_FLAGS_STYLED) { int style_nseg = qxl->attr.style_nseg; uint8_t *buf; fprintf(fd, "attr.style_nseg %d\n", qxl->attr.style_nseg); spice_assert(qxl->attr.style); buf = (uint8_t *)get_virt(slots, qxl->attr.style, style_nseg * sizeof(QXLFIXED), group_id, &error); write_binary(fd, "style", style_nseg * sizeof(QXLFIXED), buf); } red_record_brush_ptr(fd, slots, group_id, &qxl->brush, flags); fprintf(fd, "fore_mode %d\n", qxl->fore_mode); fprintf(fd, "back_mode %d\n", qxl->back_mode); }
static void smartcard_char_device_attach_client(SpiceCharDeviceInstance *char_device, SmartCardChannelClient *scc) { SmartCardDeviceState *st = spice_char_device_state_opaque_get(char_device->st); int client_added; spice_assert(!scc->smartcard_state && !st->scc); st->scc = scc; scc->smartcard_state = st; client_added = spice_char_device_client_add(st->chardev_st, scc->base.client, FALSE, /* no flow control yet */ 0, /* send queue size */ ~0, ~0, red_channel_client_waits_for_migrate_data( &scc->base)); if (!client_added) { spice_warning("failed"); st->scc = NULL; scc->smartcard_state = NULL; red_channel_client_disconnect(&scc->base); } }
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; } }