Beispiel #1
0
void dispatcher_send_message(Dispatcher *dispatcher, uint32_t message_type,
                             void *payload)
{
    DispatcherMessage *msg;
    uint32_t ack;
    int send_fd = dispatcher->send_fd;

    assert(dispatcher->max_message_type > message_type);
    assert(dispatcher->messages[message_type].handler);
    msg = &dispatcher->messages[message_type];
    pthread_mutex_lock(&dispatcher->lock);
    if (write_safe(send_fd, (uint8_t*)&message_type, sizeof(message_type)) == -1) {
        spice_printerr("error: failed to send message type for message %d",
                   message_type);
        goto unlock;
    }
    if (write_safe(send_fd, payload, msg->size) == -1) {
        spice_printerr("error: failed to send message body for message %d",
                   message_type);
        goto unlock;
    }
    if (msg->ack == DISPATCHER_ACK) {
        if (read_safe(send_fd, (uint8_t*)&ack, sizeof(ack), 1) == -1) {
            spice_printerr("error: failed to read ack");
        } else if (ack != ACK) {
            spice_printerr("error: got wrong ack value in dispatcher "
                       "for message %d\n", message_type);
            /* TODO handling error? */
        }
    }
unlock:
    pthread_mutex_unlock(&dispatcher->lock);
}
Beispiel #2
0
MsgItem *smartcard_char_device_on_message_from_device(SmartCardDeviceState *state,
                                                      VSCMsgHeader *vheader)
{
    VSCMsgHeader *sent_header;

    vheader->type = ntohl(vheader->type);
    vheader->length = ntohl(vheader->length);
    vheader->reader_id = ntohl(vheader->reader_id);

    switch (vheader->type) {
        case VSC_Init:
            return NULL;
        default:
            break;
    }
    /* We pass any VSC_Error right now - might need to ignore some? */
    if (state->reader_id == VSCARD_UNDEFINED_READER_ID && vheader->type != VSC_Init) {
        spice_printerr("error: reader_id not assigned for message of type %d", vheader->type);
    }
    if (state->scc) {
        sent_header = spice_memdup(vheader, sizeof(*vheader) + vheader->length);
        /* We patch the reader_id, since the device only knows about itself, and
         * we know about the sum of readers. */
        sent_header->reader_id = state->reader_id;
        return smartcard_get_vsc_msg_item(&state->scc->base, sent_header);
    }
    return NULL;
}
Beispiel #3
0
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);
    }
}
Beispiel #4
0
static void smartcard_connect_client(RedChannel *channel, RedClient *client,
                                     RedsStream *stream, int migration,
                                     int num_common_caps, uint32_t *common_caps,
                                     int num_caps, uint32_t *caps)
{
    SpiceCharDeviceInstance *char_device =
            smartcard_readers_get_unattached();

    SmartCardChannelClient *scc;

    scc = (SmartCardChannelClient *)red_channel_client_create(sizeof(SmartCardChannelClient),
                                                              channel,
                                                              client,
                                                              stream,
                                                              num_common_caps, common_caps,
                                                              num_caps, caps);

    if (!scc) {
        return;
    }
    red_channel_client_ack_zero_messages_window(&scc->base);

    if (char_device) {
        smartcard_char_device_attach_client(char_device, scc);
    } else {
        spice_printerr("char dev unavailable");
    }
}
Beispiel #5
0
static int snd_record_handle_write(RecordChannel *record_channel, size_t size, void *message)
{
    SpiceMsgcRecordPacket *packet;
    uint32_t write_pos;
    uint32_t* data;
    uint32_t len;
    uint32_t now;

    if (!record_channel) {
        return FALSE;
    }

    packet = (SpiceMsgcRecordPacket *)message;
    size = packet->data_size;

    if (record_channel->mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) {
        int celt_err = celt051_decode(record_channel->celt_decoder, packet->data, size,
                                      (celt_int16_t *)record_channel->celt_buf);
        if (celt_err != CELT_OK) {
            spice_printerr("celt decode failed (%d)", celt_err);
            return FALSE;
        }
        data = record_channel->celt_buf;
        size = FRAME_SIZE;
    } else if (record_channel->mode == SPICE_AUDIO_DATA_MODE_RAW) {
        data = (uint32_t *)packet->data;
        size = size >> 2;
        size = MIN(size, RECORD_SAMPLES_SIZE);
    } else {
Beispiel #6
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);
}
Beispiel #7
0
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);
}
Beispiel #8
0
static SndChannel *snd_channel_put(SndChannel *channel)
{
    if (!--channel->refs) {
        free(channel);
        spice_printerr("sound channel freed");
        return NULL;
    }
    return channel;
}
Beispiel #9
0
static int dispatcher_handle_single_read(Dispatcher *dispatcher)
{
    int ret;
    uint32_t type;
    DispatcherMessage *msg = NULL;
    uint8_t *payload = dispatcher->priv->payload;
    uint32_t ack = ACK;

    if ((ret = read_safe(dispatcher->priv->recv_fd, (uint8_t*)&type, sizeof(type), 0)) == -1) {
        spice_printerr("error reading from dispatcher: %d", errno);
        return 0;
    }
    if (ret == 0) {
        /* no messsage */
        return 0;
    }
    msg = &dispatcher->priv->messages[type];
    if (read_safe(dispatcher->priv->recv_fd, payload, msg->size, 1) == -1) {
        spice_printerr("error reading from dispatcher: %d", errno);
        /* TODO: close socketpair? */
        return 0;
    }
    if (dispatcher->priv->any_handler) {
        dispatcher->priv->any_handler(dispatcher->priv->opaque, type, payload);
    }
    if (msg->handler) {
        msg->handler(dispatcher->priv->opaque, payload);
    } else {
        spice_printerr("error: no handler for message type %d", type);
    }
    if (msg->ack == DISPATCHER_ACK) {
        if (write_safe(dispatcher->priv->recv_fd,
                       (uint8_t*)&ack, sizeof(ack)) == -1) {
            spice_printerr("error writing ack for message %d", type);
            /* TODO: close socketpair? */
        }
    } else if (msg->ack == DISPATCHER_ASYNC && dispatcher->priv->handle_async_done) {
        dispatcher->priv->handle_async_done(dispatcher->priv->opaque, type,
                                      (void *)payload);
    }
    return 1;
}
Beispiel #10
0
static int snd_send_data(SndChannel *channel)
{
    uint32_t n;

    if (!channel) {
        return FALSE;
    }

    if (!(n = channel->send_data.size - channel->send_data.pos)) {
        return TRUE;
    }

    for (;;) {
        struct iovec vec[IOV_MAX];
        int vec_size;

        if (!n) {
            channel->on_message_done(channel);

            if (channel->blocked) {
                channel->blocked = FALSE;
                core->watch_update_mask(channel->stream->watch, SPICE_WATCH_EVENT_READ);
            }
            break;
        }

        vec_size = spice_marshaller_fill_iovec(channel->send_data.marshaller,
                                               vec, IOV_MAX, channel->send_data.pos);
        n = reds_stream_writev(channel->stream, vec, vec_size);
        if (n == -1) {
            switch (errno) {
            case EAGAIN:
                channel->blocked = TRUE;
                core->watch_update_mask(channel->stream->watch, SPICE_WATCH_EVENT_READ |
                                        SPICE_WATCH_EVENT_WRITE);
                return FALSE;
            case EINTR:
                break;
            case EPIPE:
                snd_disconnect_channel(channel);
                return FALSE;
            default:
                spice_printerr("%s", strerror(errno));
                snd_disconnect_channel(channel);
                return FALSE;
            }
        } else {
            channel->send_data.pos += n;
        }
        n = channel->send_data.size - channel->send_data.pos;
    }
    return TRUE;
}
Beispiel #11
0
    void add(uint64_t id, T* data)
    {
        Item** item = &_hash[key(id)];

        while (*item) {
            if ((*item)->id == id) {
                spice_printerr("%s id %" PRIu64 ", double insert", Treat::name(), id);
                return;
            }
            item = &(*item)->next;
        }
        *item = new Item(id, data);
    }
Beispiel #12
0
static void red_dispatcher_loadvm_commands(RedDispatcher *dispatcher,
                                           struct QXLCommandExt *ext,
                                           uint32_t count)
{
    RedWorkerMessageLoadvmCommands payload;

    spice_printerr("");
    payload.count = count;
    payload.ext = ext;
    dispatcher_send_message(&dispatcher->dispatcher,
                            RED_WORKER_MESSAGE_LOADVM_COMMANDS,
                            &payload);
}
Beispiel #13
0
static void red_dispatcher_display_migrate(RedChannelClient *rcc)
{
    RedWorkerMessageDisplayMigrate payload;
    RedDispatcher *dispatcher;
    if (!rcc->channel) {
        return;
    }
    dispatcher = (RedDispatcher *)rcc->channel->data;
    spice_printerr("channel type %u id %u", rcc->channel->type, rcc->channel->id);
    payload.rcc = rcc;
    dispatcher_send_message(&dispatcher->dispatcher,
                            RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
                            &payload);
}
Beispiel #14
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;
}
Beispiel #15
0
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);
    }
}
Beispiel #16
0
static void red_dispatcher_disconnect_cursor_peer(RedChannelClient *rcc)
{
    RedWorkerMessageCursorDisconnect payload;
    RedDispatcher *dispatcher;

    if (!rcc->channel) {
        return;
    }

    dispatcher = (RedDispatcher *)rcc->channel->data;
    spice_printerr("");
    payload.rcc = rcc;

    dispatcher_send_message(&dispatcher->dispatcher,
                            RED_WORKER_MESSAGE_CURSOR_DISCONNECT,
                            &payload);
}
Beispiel #17
0
static int spicevmc_red_channel_client_config_socket(RedChannelClient *rcc)
{
    int delay_val = 1;
    RedsStream *stream = red_channel_client_get_stream(rcc);

    if (rcc->channel->type == SPICE_CHANNEL_USBREDIR) {
        if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY,
                &delay_val, sizeof(delay_val)) != 0) {
            if (errno != ENOTSUP && errno != ENOPROTOOPT) {
                spice_printerr("setsockopt failed, %s", strerror(errno));
                return FALSE;
            }
        }
    }

    return TRUE;
}
Beispiel #18
0
static void red_dispatcher_disconnect_display_peer(RedChannelClient *rcc)
{
    RedWorkerMessageDisplayDisconnect payload;
    RedDispatcher *dispatcher;

    if (!rcc->channel) {
        return;
    }

    dispatcher = (RedDispatcher *)rcc->channel->data;

    spice_printerr("");
    payload.rcc = rcc;

    // TODO: we turned it to be sync, due to client_destroy . Should we support async? - for this we will need ref count
    // for channels
    dispatcher_send_message(&dispatcher->dispatcher,
                            RED_WORKER_MESSAGE_DISPLAY_DISCONNECT,
                            &payload);
}
Beispiel #19
0
static void red_dispatcher_set_cursor_peer(RedChannel *channel, RedClient *client, RedsStream *stream,
                                           int migration, int num_common_caps,
                                           uint32_t *common_caps, int num_caps,
                                           uint32_t *caps)
{
    RedWorkerMessageCursorConnect payload;
    RedDispatcher *dispatcher = (RedDispatcher *)channel->data;
    spice_printerr("");
    payload.client = client;
    payload.stream = stream;
    payload.migration = migration;
    payload.num_common_caps = num_common_caps;
    payload.common_caps = spice_malloc(sizeof(uint32_t)*num_common_caps);
    payload.num_caps = num_caps;
    payload.caps = spice_malloc(sizeof(uint32_t)*num_caps);

    memcpy(payload.common_caps, common_caps, sizeof(uint32_t)*num_common_caps);
    memcpy(payload.caps, caps, sizeof(uint32_t)*num_caps);

    dispatcher_send_message(&dispatcher->dispatcher,
                            RED_WORKER_MESSAGE_CURSOR_CONNECT,
                            &payload);
}
Beispiel #20
0
static void spicevmc_char_dev_send_tokens_to_client(RedClient *client,
                                                    uint32_t tokens,
                                                    void *opaque)
{
    spice_printerr("Not implemented!");
}