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); }
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; }
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_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"); } }
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 {
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 SndChannel *snd_channel_put(SndChannel *channel) { if (!--channel->refs) { free(channel); spice_printerr("sound channel freed"); return NULL; } return channel; }
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; }
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; }
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); }
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); }
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); }
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 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 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); }
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; }
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); }
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); }
static void spicevmc_char_dev_send_tokens_to_client(RedClient *client, uint32_t tokens, void *opaque) { spice_printerr("Not implemented!"); }