一、客户端发起link message消息
Client link message
协议分析:
1、Link Header
抓包协议:服务器和客户端共用 4x4=16Byte
{
SPICE MAGIC: REDQ
Protocol major version: 2
Protocol minor version: 2
Message size:26
}
代码结构体
typedef struct SPICE_ATTR_PACKED SpiceLinkHeader {
uint32_t magic;
uint32_t major_version;
uint32_t minor_version;
uint32_t size;
} SpiceLinkHeader;
2、LinkMess
抓包协议:Main主通道类型为1 ,Session ID: 4B,Channel type: 1B,Channel ID: 1B, common number: 4B, channel number: 4B, offset: 4B = total: 18B
{
Session ID: 0x00000000
Channel type: Main(1)
Channel ID: 0
Number of common capabilities: 1
Number of channel capabilities: 1
Capabilities offset (bytes): 18
}
代码结构体
typedef struct SPICE_ATTR_PACKED SpiceLinkMess {
uint32_t connection_id;
uint8_t channel_type;
uint8_t channel_id;
uint32_t num_common_caps;
uint32_t num_channel_caps;
uint32_t caps_offset;
} SpiceLinkMess;
3、以spicy为例,通道发送spice send client link
int main(int argc, char *argv[])
connection_connect(conn);
spice_session_connect(conn->session);
s->cmain = spice_channel_new(session, SPICE_CHANNEL_MAIN, 0);
return spice_channel_connect(s->cmain);
return channel_connect(channel, FALSE);
c->connect_delayed_id = g_idle_add(connect_delayed, channel);
co->stack_size = 16 << 20; /* 16Mb */
co->entry = spice_channel_coroutine;
spice_channel_send_link(channel);
if (!spice_channel_recv_link_hdr(channel) || !spice_channel_recv_link_msg(channel) || !spice_channel_recv_auth(channel))
//接收link回复,并解析link header,解析msg,解析auth
while (spice_channel_iterate(channel));
if (!c->has_error)SPICE_CHANNEL_GET_CLASS(channel)->iterate_write(channel); //klass->iterate_write = spice_channel_iterate_write;
if (!c->has_error)SPICE_CHANNEL_GET_CLASS(channel)->iterate_read(channel);//klass->iterate_read = spice_channel_iterate_read;
klass->handle_msg = spice_channel_handle_msg;
4、能力集
{
Client Common Capabilities(4 Byte)
...1 = Auth Selection: Set
..0. = Auth Spice : Not Set
.0.. = Auth SASL: Not Set
1... = Mini Header: Set
Client Channel-specific Capabilities (4 Byte)
...1 = Semi-seamless migration capability: Set
..1. = VM name and UUID messages capability: Set
.1.. = Agent connected tokens capability: Set
1... = Seamless migration capability : Set
}
二、服务器回复Server link message消息
协议分析:
1、link header与客户端一样
2、SpiceLinkReply
抓捕分析
{
spice ERROR: OK(0)
X.509 SubjectPublicKeyInfo(ASN.1)
Number of common capabilities: 1
Number of channel capabilities: 1
Capabilities offset (bytes): 178
}
代码分析
#define SPICE_TICKET_KEY_PAIR_LENGTH 1024
#define SPICE_TICKET_PUBKEY_BYTES (SPICE_TICKET_KEY_PAIR_LENGTH / 8 + 34)
typedef struct SPICE_ATTR_PACKED SpiceLinkReply {
uint32_t error;
uint8_t pub_key[SPICE_TICKET_PUBKEY_BYTES];
uint32_t num_common_caps;
uint32_t num_channel_caps;
uint32_t caps_offset;
} SpiceLinkReply;
3、能力
Common Capabilities (4 bytes)
...1 = Auth Selection: Set
..1. = Auth Spice: Set
.0.. = Auth SASL: Set
1... = Mini Header: Set
Channel Capabilities (4 bytes)
...1 = Semi-seamless migration capability: Set
..1. = VM name and UUID messages capability: Set
.1.. = Agent connected tokens capability: Set
1... = Seamless migration capability : Set
4、spice-server代码分析
int spice_server_init(SpiceServer *reds, SpiceCoreInterface *core) //qemu调用初始化spice库,位于spice-server.h头文件
ret = do_spice_init(reds, core);
reds_init_net(reds)
reds->listen_watch = reds_core_watch_add(reds, reds->listen_socket,SPICE_WATCH_EVENT_READ,reds_accept, reds);
if (spice_server_add_client(reds, socket, 0) < 0) {
reds_handle_new_link(link);
red_stream_set_async_error_handler(link->stream, reds_handle_link_error);
red_stream_async_read(link->stream, ...,sizeof(link->link_header.magic), reds_handle_read_magic_done, link);
red_stream_async_read(link->stream,reinterpret_cast<uint8_t *>(&link->link_header) + sizeof(header->magic),sizeof(SpiceLinkHeader) - sizeof(header->magic),reds_handle_read_header_done, link);
red_stream_async_read(link->stream, reinterpret_cast<uint8_t *>(link->link_mess), header->size,reds_handle_read_link_done, link);