[client] spice: implement channel caps and initial clipboard support

This commit is contained in:
Geoffrey McRae 2019-02-22 07:40:43 +11:00
parent 00e07c0384
commit 108369414e
2 changed files with 61 additions and 14 deletions

View File

@ -138,4 +138,9 @@ SpiceMsgcMouseRelease;
#define COMMON_SET_CAPABILITY(caps, index) \ #define COMMON_SET_CAPABILITY(caps, index) \
{ (caps)[(index) / 32] |= (1 << ((index) % 32)); } { (caps)[(index) / 32] |= (1 << ((index) % 32)); }
#define MAIN_CAPS_BYTES (((SPICE_MAIN_CAP_SEAMLESS_MIGRATE + 32) / 8) & ~3)
#define MAIN_SET_CAPABILITY(caps, index) \
{ (caps)[(index) / 32] |= (1 << ((index) % 32)); }
#pragma pack(pop) #pragma pack(pop)

View File

@ -134,7 +134,7 @@ bool spice_on_main_channel_read ();
bool spice_on_inputs_channel_read(); bool spice_on_inputs_channel_read();
bool spice_agent_process (); bool spice_agent_process ();
bool spice_agent_connect (bool startup); bool spice_agent_connect ();
bool spice_agent_send_caps(bool request); bool spice_agent_send_caps(bool request);
// thread safe read/write methods // thread safe read/write methods
@ -420,8 +420,7 @@ bool spice_on_main_channel_read()
spice.agentTokens = msg.agent_tokens; spice.agentTokens = msg.agent_tokens;
spice.hasAgent = msg.agent_connected; spice.hasAgent = msg.agent_connected;
if (spice.hasAgent && !spice_agent_connect())
if (spice.hasAgent && !spice_agent_connect(true))
{ {
spice_disconnect(); spice_disconnect();
DEBUG_ERROR("failed to connect to spice agent"); DEBUG_ERROR("failed to connect to spice agent");
@ -491,8 +490,33 @@ bool spice_on_main_channel_read()
if (header.type == SPICE_MSG_MAIN_AGENT_CONNECTED) if (header.type == SPICE_MSG_MAIN_AGENT_CONNECTED)
{ {
DEBUG_PROTO("SPICE_MSG_MAIN_AGENT_CONNECTED");
spice.hasAgent = true; spice.hasAgent = true;
if (!spice_agent_connect(false)) if (!spice_agent_connect())
{
DEBUG_ERROR("failed to connect to spice agent");
spice_disconnect();
return false;
}
return true;
}
if (header.type == SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS)
{
DEBUG_PROTO("SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS");
uint32_t num_tokens;
if (!spice_read_nl(channel, &num_tokens, sizeof(num_tokens)))
{
DEBUG_ERROR("failed to read agent tokens");
spice_disconnect();
return false;
}
spice.hasAgent = true;
spice.agentTokens = num_tokens;
if (!spice_agent_connect())
{ {
DEBUG_ERROR("failed to connect to spice agent"); DEBUG_ERROR("failed to connect to spice agent");
spice_disconnect(); spice_disconnect();
@ -503,6 +527,8 @@ bool spice_on_main_channel_read()
if (header.type == SPICE_MSG_MAIN_AGENT_DISCONNECTED) if (header.type == SPICE_MSG_MAIN_AGENT_DISCONNECTED)
{ {
DEBUG_PROTO("SPICE_MSG_MAIN_AGENT_DISCONNECTED");
uint32_t error; uint32_t error;
if (!spice_read_nl(channel, &error, sizeof(error))) if (!spice_read_nl(channel, &error, sizeof(error)))
{ {
@ -516,8 +542,17 @@ bool spice_on_main_channel_read()
return true; return true;
} }
if (header.type == SPICE_MSG_MAIN_AGENT_DATA && spice.hasAgent) if (header.type == SPICE_MSG_MAIN_AGENT_DATA)
{ {
DEBUG_PROTO("SPICE_MSG_MAIN_AGENT_DATA");
if (!spice.hasAgent)
{
DEBUG_WARN("recieved agent data when the agent is yet to be started");
spice_discard_nl(channel, header.size);
return true;
}
if (!spice_agent_process()) if (!spice_agent_process())
{ {
DEBUG_ERROR("failed to process spice agent message"); DEBUG_ERROR("failed to process spice agent message");
@ -650,18 +685,26 @@ bool spice_connect_channel(struct SpiceChannel * channel)
channel->connected = true; channel->connected = true;
uint32_t supportCaps[COMMON_CAPS_BYTES / sizeof(uint32_t)]; uint32_t supportCaps[COMMON_CAPS_BYTES / sizeof(uint32_t)];
uint32_t channelCaps[MAIN_CAPS_BYTES / sizeof(uint32_t)];
memset(supportCaps, 0, sizeof(supportCaps)); memset(supportCaps, 0, sizeof(supportCaps));
memset(channelCaps, 0, sizeof(channelCaps));
COMMON_SET_CAPABILITY(supportCaps, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION); COMMON_SET_CAPABILITY(supportCaps, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION);
COMMON_SET_CAPABILITY(supportCaps, SPICE_COMMON_CAP_AUTH_SPICE ); COMMON_SET_CAPABILITY(supportCaps, SPICE_COMMON_CAP_AUTH_SPICE );
COMMON_SET_CAPABILITY(supportCaps, SPICE_COMMON_CAP_MINI_HEADER ); COMMON_SET_CAPABILITY(supportCaps, SPICE_COMMON_CAP_MINI_HEADER );
if (channel == &spice.scMain)
MAIN_SET_CAPABILITY(channelCaps, SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS);
SpiceLinkHeader header = SpiceLinkHeader header =
{ {
.magic = SPICE_MAGIC , .magic = SPICE_MAGIC ,
.major_version = SPICE_VERSION_MAJOR, .major_version = SPICE_VERSION_MAJOR,
.minor_version = SPICE_VERSION_MINOR, .minor_version = SPICE_VERSION_MINOR,
.size = sizeof(SpiceLinkMess) + sizeof(supportCaps) .size =
sizeof(SpiceLinkMess) +
sizeof(supportCaps ) +
sizeof(channelCaps )
}; };
SpiceLinkMess message = SpiceLinkMess message =
@ -670,14 +713,15 @@ bool spice_connect_channel(struct SpiceChannel * channel)
.channel_type = channel->channelType, .channel_type = channel->channelType,
.channel_id = spice.channelID, .channel_id = spice.channelID,
.num_common_caps = sizeof(supportCaps) / sizeof(uint32_t), .num_common_caps = sizeof(supportCaps) / sizeof(uint32_t),
.num_channel_caps = 0, .num_channel_caps = sizeof(channelCaps) / sizeof(uint32_t),
.caps_offset = sizeof(SpiceLinkMess) .caps_offset = sizeof(SpiceLinkMess)
}; };
if ( if (
!spice_write_nl(channel, &header , sizeof(header )) || !spice_write_nl(channel, &header , sizeof(header )) ||
!spice_write_nl(channel, &message , sizeof(message )) || !spice_write_nl(channel, &message , sizeof(message )) ||
!spice_write_nl(channel, &supportCaps, sizeof(supportCaps)) !spice_write_nl(channel, &supportCaps, sizeof(supportCaps)) ||
!spice_write_nl(channel, &channelCaps, sizeof(channelCaps))
) )
{ {
DEBUG_ERROR("failed to write the initial payload"); DEBUG_ERROR("failed to write the initial payload");
@ -801,9 +845,8 @@ void spice_disconnect_channel(struct SpiceChannel * channel)
// ============================================================================ // ============================================================================
bool spice_agent_connect(bool startup) bool spice_agent_connect()
{ {
return true;
DEBUG_INFO("Spice agent available, sending start"); DEBUG_INFO("Spice agent available, sending start");
const uint32_t tokens = SPICE_AGENT_TOKENS_MAX; const uint32_t tokens = SPICE_AGENT_TOKENS_MAX;
@ -813,11 +856,9 @@ bool spice_agent_connect(bool startup)
return false; return false;
} }
if (startup && !spice_agent_send_caps(startup)) if (!spice_agent_send_caps(true))
return false; return false;
//todo, agent setup
return true; return true;
} }
@ -881,12 +922,13 @@ bool spice_agent_process()
bool spice_agent_send_caps(bool request) bool spice_agent_send_caps(bool request)
{ {
const ssize_t capsSize = (sizeof(VDAgentAnnounceCapabilities) + VD_AGENT_CAPS_BYTES); const ssize_t capsSize = sizeof(VDAgentAnnounceCapabilities) + VD_AGENT_CAPS_BYTES;
VDAgentAnnounceCapabilities *caps = (VDAgentAnnounceCapabilities *)malloc(capsSize); VDAgentAnnounceCapabilities *caps = (VDAgentAnnounceCapabilities *)malloc(capsSize);
memset(caps, 0, capsSize); memset(caps, 0, capsSize);
caps->request = request ? 1 : 0; caps->request = request ? 1 : 0;
VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND); VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND);
VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_SELECTION);
if (!spice_agent_write_msg(VD_AGENT_ANNOUNCE_CAPABILITIES, caps, capsSize)) if (!spice_agent_write_msg(VD_AGENT_ANNOUNCE_CAPABILITIES, caps, capsSize))
{ {