IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [译]SPICE协议-----基本简介及普通协议定义

    jsh13417发表于 2014-12-04 10:06:41
    love 0

    1 SPICE协议简介

    SPICE协议定义了一组协议消息来访问、控制、和接收通过网络从远程计算机设备(如:键盘、视频、鼠标)的操作,并回复发送输出。控制设备既可以在客户端,也可以在服务端。另外,协议定义了一组支持远程服务器从一个网络地址迁移到另一个网络地址。加密传输数据,有一个例外,在选择加密方法上比较灵活。SPICE使用简单的消息传递和不依赖于任何RPC标准或特定的传输层。

    SPICE通信会话分为多种沟通通道道(每个通道针对一个远程设备)为了有能力控制通信和执行根据通道类型的消息(如QOS加密),并在运行时添加和删除通道(支持SPICE自定义)。

    1) 主通道作为主要的SPICE会话通道

    2) 显示通道接收远程显示更新

    3) 输入通道发送鼠标和键盘事件

    4) 光标通道接收指针形状和位置

    5) 播放通道接收音频流

    6) 录音通道发送客户端音频输入。

    随着协议的发展将添加更多的通道类型,SPICE还定义了一组协议同步信道在远程站点上执行。

    2 普通协议定义

    2.1字节顺序

    除非另有规定,所有数据结构封装和字节位顺序是小端字节序格式。

    2.2协议版本

    协议版本定义为两个UINT32值,主要协议版本和次要协议版本。服务器和客户端拥有相同的主要版本,为了保持兼容性不管次要版本号。

    ▪RED_VERSION_MAJOR = 1

    ▪RED_VERSION_MINOR = 0

    2.3通道类型-UINT8

    ▪RED_CHANNEL_MAIN = 1

    ▪RED_CHANNEL_DISPLAY = 2

    ▪RED_CHANNEL_INPUTS = 3

    ▪ RED_CHANNEL_CURSOR = 4

    ▪RED_CHANNEL_PLAYBACK = 5

    ▪RED_CHANNEL_RECORD = 6

    2.4通道链接-建立一个通道连接

    2.4.1 连接过程

    通道连接过程是由客户端发起。客户端发送RedLinkMess,作为回应服务器发送RedLinkReply。当客户端接收到RedLinkReply时,它检查返回错误代码,如果没有错误它会加密公钥密码在RedLinkReply并将其发送到服务器。服务器接收密码并将链接的结果发给客户端。客户端检查连接的结果,如果结果为RED_ERROR_OK,建立一个有效的链接。除了RED_CHANNEL_MAIN以外其他的通道类型只允许在客户端主动连接RED_CHANNEL_MAIN。仅仅在RED_CHANNEL_MAIN通道被允许后,才会建立起与远程服务器的会话。

    2.4.2 Ticketing

    Ticketing是SPICE协议的一种实现机制目的是为了确保只允许有授权的来源连接。为了确保这种机制,Ticketing是一个在SPICE服务器端有密码和有效时间段的组成。时间过期后,这个Ticketing也就过期了。这个Ticketing是加密的。为了使用加密,服务器生成一个1024位的RSA密钥并向客户端发送公钥(通过RedLinkInfo)。客户端使用这个公钥加密密码并将其发回服务器(RedLinkMess之后)。服务器解密密码,比较它的ticketing和确保在允许的时间框架内。

    2.4.3 RedLinkMess定义

    typedef structSPICE_ATTR_PACKED SpiceLinkHeader {
        uint32_t magic;          //必须为RED_MAGIC
        uint32_t major_version; //客户端主版本号
        uint32_t minor_version;//客户端次版本号
        uint32_t size;                     //后续数据的大小
    }SpiceLinkHeader;
    typedef structSPICE_ATTR_PACKED SpiceLinkMess {
        uint32_t connection_id; //针对一个新的会话(例如RED_CHANNEL_MAIN)这个数值被设置为0,服务器将分配会话ID并在RedLinkMess消息中发给客户端。其他通道类型。使用分配的会话ID。
        uint8_t channel_type; //通道类型
        uint8_t channel_id;   //通道ID,同一个ID可能有多个通道。
        uint32_t num_common_caps;//普通客户端通道功能词数量
        uint32_t num_channel_caps; //特殊客户端通道功能词数量
        uint32_t caps_offset;       //这个结构体的大小。后续还有能力集数值
    } SpiceLinkMess;


    2.4.4 RedLinkReply定义

    typedef structSPICE_ATTR_PACKED SpiceLinkHeader {
       uint32_t magic;             //必须为RED_MAGIC
        uint32_t major_version; //服务器主版本号
        uint32_t minor_version;// 服务器次版本号
        uint32_t size;                     //后续数据的大小
    }SpiceLinkHeader;
    typedef structSPICE_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;


    2.4.5 加密密码

    客户端使用公钥加密密码发送回服务器

    2.4.6 验证结果

    接收验证结果

    2.5协议消息定义

    在连接建立后,所有的消息传输都遵循下面的格式。开始于RedDataHeader描述一个主要消息和一个可选的子消息。在实际传输中使用SpiceMiniDataHeader。2.5.2、2.5.3、2.5.4结构体就不再详细说明了。

    2.5.1 SpiceMiniDataHeader

    typedef structSPICE_ATTR_PACKED SpiceMiniDataHeader {
        uint16_t type; //消息类型,根据通道类型选择各自的处理函数。
        uint32_t size;//数据大小
    } SpiceMiniDataHeader;

    2.5.2 SpiceDataHeader

    在实际传输中并未用到这个数据头而使用上面的mini_header,所以不在分析这两个结构体

    typedef structSPICE_ATTR_PACKED SpiceDataHeader {
        uint64_t serial; //通道内,消息的序列号。开始于1,后续逐渐增加
        uint16_t type; //消息类型
        uint32_t size; //消息体的大小,如果sublist不是0,则sub_list为消息的实际大小
        uint32_t sub_list;//offset to SpiceSubMessageList[]//后续数据的大小
    }SpiceDataHeader;

    2.5.3 SpiceSubMessage

    typedef structSPICE_ATTR_PACKED SpiceSubMessage {
        uint16_t type;
        uint32_t size;
    }SpiceSubMessage;


    2.5.4 SpiceSubMessageList

    typedef structSPICE_ATTR_PACKED SpiceSubMessageList {
        uint16_t size;
        uint32_t sub_messages[0]; //offsets toSpicedSubMessage
    }SpiceSubMessageList;


    2.6常见消息和消息传递命名约定

    消息和消息体结构类型前缀描述了消息的来源。具体如下:

    服务器---》客户端:RED

    客户端---》服务器:REDC

    这个命名是SPICE协议文档中的描述,在实际源码中,可能是下面的定义:

    服务器---》客户端:SPICE_MSG

    客户端---》服务器:SPICE_MSGC

    2.7Ping

    SPICE协议提供了ping消息用于调试的目的。SPICE服务器发送RED_PING,客户端回应REDC_PING。服务器可以使用这个调试测试网络情况。同时也可以用来同步客户端和服务器时间的一个通道。

    2.7.1 SpiceMsgPing结构体描述

    typedef structSpiceMsgPing {
        uint32_t id; //消息的ID,服务器发给客户端,客户端回应这个ID
        uint64_t timestamp;//消息的时间戳
        void *data;    //这个数据用途不明
        uint32_t data_len;
    } SpiceMsgPing;

    2.8通道迁移

    SPICE支持SPICE服务器端的迁移。这个功能暂时不说明了。

    2.9通道同步

    SPICE协议提供了消息在客户端执行同步机制。服务器发送RED_WAIT_FOR_CHANNELS消息包含一个频道列表的消息等待(RedWaitForChannels)。SPICE客户端等待完成这个列表的所有消息在其他的所有消息执行之前。

    2.9.1 SpiceWaitForChannel结构体描述

    typedef structSpiceWaitForChannel {
        uint8_t channel_type; //通道的类别。5个
        uint8_t channel_id;   //通道ID
        uint64_t message_serial;//等待消息的序列ID号
    }SpiceWaitForChannel;


    2.9.2 SpiceMsgWaitForChannels;结构体描述

    typedef structSpiceMsgWaitForChannels {
        uint8_t wait_count; //等待消息的数量
        SpiceWaitForChannel wait_list[0];//需要等待的频道列表
    }SpiceMsgWaitForChannels;


    2.10 断开原因

    下面消息用于通知有序断开服务器或者客户端

    2.10.1 SpiceMsgDisconnect描述

    typedef structSpiceMsgDisconnect {
        uint64_t time_stamp;//服务器或客户端断开的时间戳
        uint32_t reason; // SPICE_ERR_?
    }SpiceMsgDisconnect;


    2.11 服务器通知消息

    SPICE协议定义了消息的交互通知到客户端使用RED_NOTIFY消息。消息可以划分为严重性和可见性。以后可以用做消息的方式显示给用户。

    2.11.1 SpiceMsgNotify结构体描述

    typedef structSpiceMsgNotify {
        uint64_t time_stamp; //这个消息在server端的时间戳
        uint32_t severity;    //消息的严重程度
        uint32_t visibilty;    //消息的可见程度
        uint32_t what;                     //消息的类别,错误、警告、帮助等等
        uint32_t message_len;//消息长度
        uint8_t message[0];   //消息数据
    }SpiceMsgNotify;




沪ICP备19023445号-2号
友情链接