spice協(xié)議——vdagent

spice vdagent是怎么與server和client交互的

虛擬串口

vdagent運行在guest os(虛擬機)中玻募,用于確保特性功能能正常運行坤学。guest中所有 vdagent 通信都通過單個管道運行通殃,該管道作為 virtio 串行端口呈現(xiàn)給guest操作系統(tǒng)咱枉。

\\\\.\\Global\\com.redhat.spice.0       //widnows下
/dev/virtio-ports/com.redhat.spice.0    //linux下  

qemu可以使用以下參數(shù)啟用 virtio 串口

-device virtio-serial-pci,id = virtio-serial0,max_ports = 16 ,bus = pci.0,addr = 0x5 -chardev spicevmc,name = vdagent,id = vdagent -device virtserialport,nr = 1 ,bus = virtio- serial0.0,chardev = vdagent,name = com.redhat.spice.0

數(shù)據(jù)塊

vdagent可以通過virtio串口給spice-server發(fā)送數(shù)據(jù)冤灾,但是可以同時接收來自spice-server和spice-client的數(shù)據(jù),為了區(qū)別數(shù)據(jù)來源烤蜕,所以定義了如下數(shù)據(jù)頭:

enum {
    VDP_CLIENT_PORT = 1,
    VDP_SERVER_PORT,
};
typedef struct SPICE_ATTR_PACKED VDIChunkHeader {
  uint32_t port;  //上面的枚舉值
  uint32_t size;  //sizeof(VDIChunkHeader)+后續(xù)數(shù)據(jù)大小
} VDIChunkHeader;

當vdagent接收消息時封孙,port字段標識數(shù)據(jù)來自何方,當發(fā)送數(shù)據(jù)時讽营,port字段標識數(shù)據(jù)發(fā)送給誰虎忌。spice-server會在收到消息時解析VDIChunkHeader,根據(jù)port字段來決定處理橱鹏、轉(zhuǎn)發(fā)或丟棄膜蠢,值得注意的是,目前spice中沒有vdagent給server發(fā)送的消息莉兰,所以來自vdagent的port=VDP_SERVER_PORT的消息將被丟棄挑围。

消息結(jié)構(gòu)體

vdagent發(fā)送和接收的消息用VDAgentMessage結(jié)構(gòu)體封裝

enum {
  VD_AGENT_MOUSE_STATE = 1,  //鼠標模式
  VD_AGENT_MONITORS_CONFIG,  //顯示器信息
  VD_AGENT_REPLY,            //回復消息
  VD_AGENT_CLIPBOARD,        //剪切板消息
  VD_AGENT_DISPLAY_CONFIG,   //顯示性能相關(guān)配置
  VD_AGENT_ANNOUNCE_CAPABILITIES, //能力同步
  .... //可以自定義類型
  VD_AGENT_END_MESSAGE,
};

typedef struct SPICE_ATTR_PACKED VDAgentMessage {
  uint32_t protocol;  //始終是VD_AGENT_PROTOCOL
  uint32_t type;      //上述枚舉值,標識message類型
  uint64_t opaque;    
  uint32_t size;
  uint8_t data[0];
} VDAgentMessage;

opaque字段是一個占位符贮勃,當只需要發(fā)送一個int值時使用贪惹,如果有payload數(shù)據(jù)則為0苏章,數(shù)據(jù)用data字段發(fā)送寂嘉。
size字段是data的大小。注意VDIChunkHeader 的size = sizeof(VDIChunkHeader) + 后續(xù)數(shù)據(jù)大小 = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) + variable_data_len枫绅。
data 是可變長度數(shù)據(jù)的開始泉孩,它的內(nèi)容取決于type字段 ,對于大多數(shù)消息來說并淋,它是一個消息類型特定的結(jié)構(gòu)寓搬,例如 VDAgentMouseState。請注意县耽,數(shù)據(jù)被聲明為 0 大小的數(shù)組句喷,這意味著它在結(jié)構(gòu)中不占用任何大小,它只是為了能夠輕松確定數(shù)據(jù)的起始地址兔毙。
消息類型

鼠標模式(VD_AGENT_MOUSE_STATE)

spice支持兩種鼠標模式唾琼,客戶端模式和服務端模式。
在服務端模式下澎剥,當用戶在 Spice 客戶端窗口內(nèi)點擊時,客戶端鼠標被捕獲,然后將增量坐標發(fā)送給server端敛腌,鼠標通過QEMU ps/2 仿真,guest內(nèi)不會收到消息芜茵。
在客戶端模式下,客戶端發(fā)送鼠標絕對坐標給guest倡蝙,這個坐標可以使用 USB 模擬九串,或直接發(fā)送到 vdagent,來告知guest操作系統(tǒng)鼠標位置(和按鈕點擊)寺鸥。
spice-server處理所有的的鼠標操作蒸辆,只有在客戶端模式下,server才會向client發(fā)送VD_AGENT_MOUSE_STATE消息析既,消息結(jié)構(gòu)體如下:

typedef struct SPICE_ATTR_PACKED VDAgentMouseState {
  uint32_t x;
  uint32_t y;
  uint32_t buttons;
  uint8_t display_id;
} VDAgentMouseState;

顯示器配置(VD_AGENT_MONITORS_CONFIG)

當client運行在全屏自適應模式下時躬贡,客戶端發(fā)送連接到客戶端機器上的顯示器信息給vdagent,當 vdagent收到消息時眼坏,將重新配置qxl設備的outputs拂玻,并盡可能匹配消息給出的配置。

typedef struct SPICE_ATTR_PACKED VDAgentMonitorsConfig {
  uint32_t num_of_monitors; //顯示器數(shù)量
  uint32_t flags;  //宰译?檐蚜??
  VDAgentMonConfig monitors[0];  //每個顯示器的配置沿侈,如下述結(jié)構(gòu)體
} VDAgentMonitorsConfig;

typedef struct SPICE_ATTR_PACKED VDAgentMonConfig {
  uint32_t height;
  uint32_t width;
  uint32_t depth;
  int32_t x;
  int32_t y;
} VDAgentMonConfig;

當代理完成輸出配置后闯第,它應該在給客戶端回復 VD_AGENT_REPLY 消息來通知配置結(jié)果,類型設置為 VD_AGENT_MONITORS_CONFIG 缀拭,錯誤設置為 VD_AGENT_SUCCESS 或 VD_AGENT_ERROR 咳短。

顯示效果配置(VD_AGENT_DISPLAY_CONFIG)

顯示效果消息由 spice 客戶端發(fā)送到 vdagent,以通知它任何與性能相關(guān)的特殊設置蛛淋×茫客戶端可以要求 vdagent 禁用來賓操作系統(tǒng)的各種功能,例如字體抗鋸齒以提高性能褐荷。vdagent 應該盡可能滿足勾效。因為大多數(shù)設置都是以 Windows 為中心的,除非真的出了問題叛甫,否則應該使用 VD_AGENT_REPLY 返回成功狀態(tài)层宫。

enum {
  VD_AGENT_DISPLAY_CONFIG_FLAG_DISABLE_WALLPAPER = (1 << 0),
  VD_AGENT_DISPLAY_CONFIG_FLAG_DISABLE_FONT_SMOOTH = (1 << 1),
  VD_AGENT_DISPLAY_CONFIG_FLAG_DISABLE_ANIMATION = (1 << 2),
  VD_AGENT_DISPLAY_CONFIG_FLAG_SET_COLOR_DEPTH = (1 << 3),
};
typedef struct SPICE_ATTR_PACKED VDAgentDisplayConfig {
  uint32_t flags;  //??
  uint32_t depth;  //??
} VDAgentDisplayConfig;

回復消息(VD_AGENT_REPLY)

該消息由vdagent回復給client,以指示消息VD_AGENT_MONITORS_CONFIG 或者VD_AGENT_DISPLAY_CONFIG配置成功與否其监。

typedef struct SPICE_ATTR_PACKED VDAgentReply {
  uint32_t type;
  uint32_t error;
} VDAgentReply;
enum {
  VD_AGENT_SUCCESS = 1,
  VD_AGENT_ERROR,
};

能力同步(VD_AGENT_ANNOUNCE_CAPABILITIES)

能力同步消息萌腿,有client和vdagent相互發(fā)送給對方,用于通知雙方已實現(xiàn)的功能棠赛,此消息的目的是允許不同的客戶端和 vdagent 版本一起工作哮奇。

enum {
    VD_AGENT_CAP_MOUSE_STATE = 0,
    VD_AGENT_CAP_MONITORS_CONFIG,
    VD_AGENT_CAP_REPLY,
    VD_AGENT_CAP_CLIPBOARD,
    VD_AGENT_CAP_DISPLAY_CONFIG,
    VD_AGENT_CAP_CLIPBOARD_BY_DEMAND,
    VD_AGENT_CAP_CLIPBOARD_SELECTION,
    VD_AGENT_CAP_SPARSE_MONITORS_CONFIG,
    VD_AGENT_CAP_GUEST_LINEEND_LF,
    VD_AGENT_CAP_GUEST_LINEEND_CRLF,
    VD_AGENT_CAP_MAX_CLIPBOARD,
    VD_AGENT_CAP_AUDIO_VOLUME_SYNC,
    VD_AGENT_CAP_MONITORS_CONFIG_POSITION,
    VD_AGENT_CAP_FILE_XFER_DISABLED,
    VD_AGENT_CAP_FILE_XFER_DETAILED_ERRORS,
    VD_AGENT_CAP_GRAPHICS_DEVICE_INFO,
    VD_AGENT_CAP_CLIPBOARD_NO_RELEASE_ON_REGRAB,
    VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL,
    VD_AGENT_END_CAP,
};

typedef struct SPICE_ATTR_PACKED VDAgentAnnounceCapabilities {
  uint32_t  request;
  uint32_t caps[0];
} VDAgentAnnounceCapabilities;

request字段是一個bool值膛腐,表示是否希望接收方回復capabilities,在初始化時應該設置為true鼎俘,在回復時應該設為false哲身。
caps 字段保存能力位的可變長度數(shù)組的開頭,該數(shù)組的長度可以使用 VDAgentMessage msg 大小成員上的 VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE 宏來確定贸伐。能力枚舉在 VD_AGENT_CAP 中定義勘天,可以使用 VD_AGENT_HAS_CAPABILITY 和 VD_AGENT_SET_CAPABILITY 宏來測試/設置陣列中的功能位。
guest或client都不應該發(fā)送對方未宣布為支持的能力相關(guān)聯(lián)的消息類型捉邢。舊版本不支持通知能力脯丝,因此在收到通知能力消息之前,假定以下能力所有版本都支持:
VD_AGENT_CAP_MOUSE_STATE
VD_AGENT_CAP_MONITORS_CONFIG
VD_AGENT_CAP_REPLY

剪切板相關(guān)消息

spice剪切板用于在guest和client之間拷貝數(shù)據(jù)伏伐,前提是guest和client都需要實現(xiàn)VD_AGENT_CAP_CLIPBOARD_SELECTION功能宠进,guest和client都能對剪切板進行如下操作,這些操作通過后面括號中的消息觸發(fā)藐翎。
申明所有權(quán)(VD_AGENT_CLIPBOARD_GRAB)
釋放所有權(quán)(VD_AGENT_CLIPBOARD_RELEASE)
請求數(shù)據(jù)(VD_AGENT_CLIPBOARD_REQUEST)
發(fā)送數(shù)據(jù)(VD_AGENT_CLIPBOARD)

接下來以guest->client拷貝文本為例材蹬,反向的邏輯是相同的:

  • 虛擬機中agent會監(jiān)聽系統(tǒng)事件,當監(jiān)聽到復制事件時吝镣,會觸發(fā)回調(diào)向client端發(fā)送VD_AGENT_CLIPBOARD_GRAB消息堤器,獲取剪切板的所有權(quán)。
  • client端接收到GRAB消息之后末贾,會發(fā)送通過信號觸發(fā)clipboard_grab回調(diào)闸溃,回調(diào)中會調(diào)用gtk的gtk_clipboard_set_with_owner接口注冊剪切板的clipboard_get和clipboard_clear操作,并設置owner用于監(jiān)聽粘貼操作拱撵。
  • 當客戶端有粘貼操作時辉川,會觸發(fā)clipboard_get回調(diào),回調(diào)中先連接VD_AGENT_CLIPBOARD消息的回調(diào)clipboard_got_from_guest裕膀,然后向guest發(fā)送VD_AGENT_CLIPBOARD_RELEASE消息员串,請求剪切板數(shù)據(jù),然后會啟動一個mainloop等待數(shù)據(jù)到來昼扛。
  • guest收到VD_AGENT_CLIPBOARD_RELEASE消息時,就會通過VD_AGENT_CLIPBOARD消息將剪切板數(shù)據(jù)發(fā)送給client欲诺。
  • client接收到消息抄谐,會調(diào)到clipboard_got_from_guest,將數(shù)據(jù)拷貝到系統(tǒng)剪切板扰法。
  • 然后在系統(tǒng)事件循環(huán)中會將系統(tǒng)剪切板的數(shù)據(jù)拷貝到目標組件蛹含。

至此完成一次粘貼操作。

VD_AGENT_CLIPBOARD_GRAB

獲取clipboard所有權(quán)

typedef struct SPICE_ATTR_PACKED VDAgentClipboardGrab {
#if 0 /* VD_AGENT_CAP_CLIPBOARD_SELECTION */
    uint8_t selection;
    uint8_t __reserved[sizeof(uint32_t) - 1 * sizeof(uint8_t)];
#endif
#if 0 /* VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL */
    uint32_t serial;
#endif
    uint32_t types[0];
} VDAgentClipboardGrab;

VD_AGENT_CLIPBOARD_RELEASE

釋放clipboard所有權(quán)塞颁。

typedef struct SPICE_ATTR_PACKED VDAgentClipboardRelease {
#if 0 /* VD_AGENT_CAP_CLIPBOARD_SELECTION */
    uint8_t selection;
    uint8_t __reserved[sizeof(uint32_t) - 1 * sizeof(uint8_t)];
#endif
    uint8_t dummy_empty_field[0]; /* C/C++ compatibility */
} VDAgentClipboardRelease;

VD_AGENT_CLIPBOARD_REQUEST

請求clipboard數(shù)據(jù)浦箱,type指定數(shù)據(jù)格式吸耿。

enum {
  VD_AGENT_CLIPBOARD_NONE = 0,
  VD_AGENT_CLIPBOARD_UTF8_TEXT,
  VD_AGENT_CLIPBOARD_IMAGE_PNG,  /* All clients with image support should support this one */
  VD_AGENT_CLIPBOARD_IMAGE_BMP,  /* optional */
  VD_AGENT_CLIPBOARD_IMAGE_TIFF, /* optional */
  VD_AGENT_CLIPBOARD_IMAGE_JPG,  /* optional */
};

typedef struct SPICE_ATTR_PACKED VDAgentClipboardRequest {
#if 0 /* VD_AGENT_CAP_CLIPBOARD_SELECTION */
    uint8_t selection;
    uint8_t __reserved[sizeof(uint32_t) - 1 * sizeof(uint8_t)];
#endif
    uint32_t type;
} VDAgentClipboardRequest;

VD_AGENT_CLIPBOARD

發(fā)送clipboard數(shù)據(jù),type為數(shù)據(jù)格式酷窥,data是數(shù)據(jù)咽安。除非收到VD_AGENT_CLIPBOARD_REQUEST 請求數(shù)據(jù),否則不應發(fā)送數(shù)據(jù)蓬推,以避免浪費帶寬妆棒。要傳輸?shù)募糍N板數(shù)據(jù)很大是很常見的,在這種情況下沸伏,消息會被分成幾個 VD_AGENT_MESSAGE糕珊。

struct VDAgentClipboard {
if VD_AGENT_CAP_CLIPBOARD_SELECTION capability
  uint8_t selection;
  uint8_t __reserved[3];
endif
  uint32_t type;
  uint8_t data[0];
};
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市毅糟,隨后出現(xiàn)的幾起案子红选,更是在濱河造成了極大的恐慌,老刑警劉巖姆另,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纠脾,死亡現(xiàn)場離奇詭異,居然都是意外死亡蜕青,警方通過查閱死者的電腦和手機苟蹈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來右核,“玉大人慧脱,你說我怎么就攤上這事『睾龋” “怎么了菱鸥?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長躏鱼。 經(jīng)常有香客問我氮采,道長,這世上最難降的妖魔是什么染苛? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任鹊漠,我火速辦了婚禮,結(jié)果婚禮上茶行,老公的妹妹穿的比我還像新娘躯概。我一直安慰自己,他們只是感情好畔师,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布娶靡。 她就那樣靜靜地躺著,像睡著了一般看锉。 火紅的嫁衣襯著肌膚如雪姿锭。 梳的紋絲不亂的頭發(fā)上塔鳍,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天,我揣著相機與錄音呻此,去河邊找鬼轮纫。 笑死,一個胖子當著我的面吹牛趾诗,可吹牛的內(nèi)容都是我干的蜡感。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼恃泪,長吁一口氣:“原來是場噩夢啊……” “哼郑兴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起贝乎,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤情连,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后览效,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體却舀,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年锤灿,在試婚紗的時候發(fā)現(xiàn)自己被綠了挽拔。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡但校,死狀恐怖螃诅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情状囱,我是刑警寧澤术裸,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站亭枷,受9級特大地震影響袭艺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜叨粘,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一猾编、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宣鄙,春花似錦袍镀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绸吸。三九已至鼻弧,卻和暖如春设江,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背攘轩。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工叉存, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人度帮。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓歼捏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親笨篷。 傳聞我的和親對象是個殘疾皇子瞳秽,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355