示例#1
0
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);
}
示例#2
0
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;
    }
}
示例#3
0
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;
    }
}
示例#4
0
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);
    }
}
示例#5
0
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;
}
示例#6
0
文件: spicevmc.c 项目: Fantu/spice
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;
}
示例#7
0
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;
}
示例#8
0
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();
    }
}
示例#9
0
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);
}
示例#10
0
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);
}
示例#11
0
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);
}
示例#12
0
文件: spicevmc.c 项目: Fantu/spice
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);
}
示例#13
0
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);

}
示例#14
0
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;
    }
}
示例#15
0
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");
    }
}
示例#16
0
文件: spicevmc.c 项目: Fantu/spice
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);
}
示例#17
0
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);
    }
}
示例#18
0
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;
}
示例#19
0
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);
}
示例#20
0
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;
        }
    }
}
示例#21
0
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;
}
示例#22
0
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);
}
示例#23
0
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;
            }
        }
    }
}
示例#24
0
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);
}
示例#25
0
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
}
示例#26
0
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);
}
示例#27
0
文件: spicevmc.c 项目: Fantu/spice
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);
}
示例#28
0
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);
}
示例#29
0
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);
    }
}
示例#30
0
文件: spicevmc.c 项目: Fantu/spice
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;
    }
}