/* coroutine context */ static void spice_channel_send_link(SpiceChannel *channel) { spice_channel *c = channel->priv; uint8_t *buffer, *p; int protocol, i; c->link_hdr.magic = SPICE_MAGIC; c->link_hdr.size = sizeof(c->link_msg); g_object_get(c->session, "protocol", &protocol, NULL); switch (protocol) { case 1: /* protocol 1 == major 1, old 0.4 protocol, last active minor */ c->link_hdr.major_version = 1; c->link_hdr.minor_version = 3; c->parser = spice_get_server_channel_parser1(c->channel_type, NULL); c->marshallers = spice_message_marshallers_get1(); break; case SPICE_VERSION_MAJOR: /* protocol 2 == current */ c->link_hdr.major_version = SPICE_VERSION_MAJOR; c->link_hdr.minor_version = SPICE_VERSION_MINOR; c->parser = spice_get_server_channel_parser(c->channel_type, NULL); c->marshallers = spice_message_marshallers_get(); break; default: g_critical("unknown major %d", protocol); return; } c->link_msg.connection_id = c->connection_id; c->link_msg.channel_type = c->channel_type; c->link_msg.channel_id = c->channel_id; c->link_msg.caps_offset = sizeof(c->link_msg); c->link_msg.num_common_caps = c->common_caps->len; c->link_msg.num_channel_caps = c->caps->len; c->link_hdr.size += (c->link_msg.num_common_caps + c->link_msg.num_channel_caps) * sizeof(uint32_t); buffer = spice_malloc(sizeof(c->link_hdr) + c->link_hdr.size); p = buffer; memcpy(p, &c->link_hdr, sizeof(c->link_hdr)); p += sizeof(c->link_hdr); memcpy(p, &c->link_msg, sizeof(c->link_msg)); p += sizeof(c->link_msg); for (i = 0; i < c->common_caps->len; i++) { *(uint32_t *)p = g_array_index(c->common_caps, uint32_t, i); p += sizeof(uint32_t); } for (i = 0; i < c->caps->len; i++) { *(uint32_t *)p = g_array_index(c->caps, uint32_t, i); p += sizeof(uint32_t); } spice_channel_write(channel, buffer, p - buffer); }
void RedChannel::run() { for (;;) { Lock lock(_action_lock); if (_action == WAIT_ACTION) { _action_cond.wait(lock); } int action = _action; _action = WAIT_ACTION; lock.unlock(); switch (action) { case CONNECT_ACTION: try { get_client().get_sync_info(get_type(), get_id(), _sync_info); on_connecting(); set_state(CONNECTING_STATE); ConnectionOptions con_options(_client.get_connection_options(get_type()), _client.get_port(), _client.get_sport(), _client.get_protocol(), _client.get_host_auth_options(), _client.get_connection_ciphers()); RedChannelBase::connect(con_options, _client.get_connection_id(), _client.get_host().c_str(), _client.get_password().c_str()); /* If automatic protocol, remember the first connect protocol type */ if (_client.get_protocol() == 0) { if (get_peer_major() == 1) { _client.set_protocol(1); } else { /* Major is 2 or unstable high value, use 2 */ _client.set_protocol(2); } } /* Initialize when we know the remote major version */ if (_client.get_peer_major() == 1) { _marshallers = spice_message_marshallers_get1(); } else { _marshallers = spice_message_marshallers_get(); } on_connect(); set_state(CONNECTED_STATE); _loop.add_socket(*this); _socket_in_loop = true; on_event(); _loop.run(); } catch (RedPeer::DisconnectedException&) { _error = SPICEC_ERROR_CODE_SUCCESS; } catch (Exception& e) { LOG_WARN("%s", e.what()); _error = e.get_error_code(); } catch (std::exception& e) { LOG_WARN("%s", e.what()); _error = SPICEC_ERROR_CODE_ERROR; } if (_socket_in_loop) { _socket_in_loop = false; _loop.remove_socket(*this); } if (_outgoing_message) { _outgoing_message->release(); _outgoing_message = NULL; } _incomming_header_pos = 0; if (_incomming_message) { _incomming_message->unref(); _incomming_message = NULL; } case DISCONNECT_ACTION: close(); on_disconnect(); set_state(DISCONNECTED_STATE); _client.on_channel_disconnected(*this); continue; case QUIT_ACTION: set_state(TERMINATED_STATE); return; } } }