Spice下命令spicy的USB重定向过程分析
在spice-gtk-0.30內部有一個spicy命令用于鏈接遠程的虛擬機,
例如spicy -h 172.16.3.4 -p 6700 這樣就可以鏈接到虛擬桌面
其客戶端有個USB 設備重定向管理功能,在spicy內有個Input選項卡,其子項有個“Select USB Devices for redirection”。選擇重定向USB 設備,點開后就會出現列有USB設備的對話礦對話框,就可以選擇USB 設備進行重定向。其如下圖所示:
彈出的對話況如下所示:
可以看到所有的USB設備都一GTK CheckButton的形式列出來了,那么當選中里面的USB設備時,本地的USB設備就會被重定向到虛擬桌面Win7下面:
其實現的流程如下:
相關源文件:spicy.c、usb-device-manager.c、channel-usbredir.c、usb-device-widget.c
在usb-device-widget.c中的代碼如下:
在對話框構建constructor內會為每個USB設備建立CheckButton控件,如下:
static void device_added_cb(SpiceUsbDeviceManager *manager,SpiceUsbDevice *device, gpointer user_data) {SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(user_data);SpiceUsbDeviceWidgetPrivate *priv = self->priv;GtkWidget *align, *check;gchar *desc; printf("device_added_cb-----usb-device-widget.c\n");desc = spice_usb_device_get_description(device,//獲取usb設備描述符priv->device_format_string);check = gtk_check_button_new_with_label(desc);//創建checkbuttong_free(desc);//創建完畢后就釋放掉if (spice_usb_device_manager_is_device_connected(priv->manager,//檢測usb設備是否鏈接狀態如果是連接的就設置checkbutton為真device))gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);//設置checkbutton為Tureg_object_set_data_full(//設置數據和回調函數G_OBJECT(check), "usb-device",g_boxed_copy(spice_usb_device_get_type(), device),checkbox_usb_device_destroy_notify);g_signal_connect(G_OBJECT(check), "clicked",//注冊點擊checkbutton事件G_CALLBACK(checkbox_clicked_cb), self);//當點擊事件觸發時調用回調函數checkbox_clicked_cbalign = gtk_alignment_new(0, 0, 0, 0);//創建對齊控件gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 0);gtk_container_add(GTK_CONTAINER(align), check);//在checkbutton中添加對齊方式gtk_box_pack_end(GTK_BOX(self), align, FALSE, FALSE, 0);spice_usb_device_widget_update_status(self);//更新usb控件狀態gtk_widget_show_all(align); }在建立成功后注冊CheckButton的選中點擊事件:
static void checkbox_clicked_cb(GtkWidget *check, gpointer user_data) {SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(user_data);SpiceUsbDeviceWidgetPrivate *priv = self->priv;SpiceUsbDevice *device;device = g_object_get_data(G_OBJECT(check), "usb-device");//獲取數據if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check))) {//獲取checkbutton的狀態,為Tureconnect_cb_data *data = g_new(connect_cb_data, 1);data->check = g_object_ref(check);data->self = g_object_ref(self);printf("checkbox_clicked_cb---true-------usb-device-widget.c\n");spice_usb_device_manager_connect_device_async(priv->manager,//重定向設備device,NULL,connect_cb,data);} else {//如果狀態為False則斷開鏈接printf("checkbox_clicked_cb---false-------usb-device-widget.c\n");spice_usb_device_manager_disconnect_device(priv->manager,//斷開channel與devicedevice);}spice_usb_device_widget_update_status(self); }到此兩個事件,一個選中事件則調用spice_usb_device_manager_connect_device_async對該USB 設備俄進行重定向
另一個取消選中,就會掉用spice_usb_device_manager_disconnect_device,斷開channel和device的鏈接,取消重定向,
一先看看簡單的取消的過程:這個函數在usb-device-manager.c文件內定義如下:
void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *self,SpiceUsbDevice *device) {g_return_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self));g_return_if_fail(device != NULL);//device為空退出SPICE_DEBUG("disconnecting device %p", device); printf("spice_usb_device_manager_disconnect_device,disconnecting device %p ------usb-device-manager.c\n",device); #ifdef USE_USBREDIRSpiceUsbredirChannel *channel;channel = spice_usb_device_manager_get_channel_for_dev(self, device);//根據device獲取channelif (channel)spice_usbredir_channel_disconnect_device(channel);//清空channel內的相關device并設置狀態#ifdef G_OS_WIN32//沒有在windows下使用,因此代碼省略注銷 #endif #endif }在這個函數內部首先根據device獲取相匹配的Channel,在對Channel內的device進行清空:
static SpiceUsbredirChannel *spice_usb_device_manager_get_channel_for_dev(SpiceUsbDeviceManager *manager, SpiceUsbDevice *device) { #ifdef USE_USBREDIRSpiceUsbDeviceManagerPrivate *priv = manager->priv;guint i;for (i = 0; i < priv->channels->len; i++) {//獲取device相對應的channelSpiceUsbredirChannel *channel = g_ptr_array_index(priv->channels, i);//獲取channellibusb_device *libdev = spice_usbredir_channel_get_device(channel);if (spice_usb_device_equal_libdev(device, libdev))//如果兩者匹配就返回channelreturn channel;//返回device對應的channel} #endifreturn NULL; }清空函數spice_usbredir_channel_disconnect_device在channel-usbredir.c內部
void spice_usbredir_channel_disconnect_device(SpiceUsbredirChannel *channel) {SpiceUsbredirChannelPrivate *priv = channel->priv;CHANNEL_DEBUG(channel, "disconnecting device from usb channel %p", channel);printf("spice_usbredir_channel_disconnect_device, priv->state=%d---------channel-usbredir.c\n",priv->state);switch (priv->state) {case STATE_DISCONNECTED:case STATE_DISCONNECTING:break; #if USE_POLKITcase STATE_WAITING_FOR_ACL_HELPER:priv->state = STATE_DISCONNECTING;/* We're still waiting for the acl helper -> cancel it */spice_usb_acl_helper_close_acl(priv->acl_helper);break; #endifcase STATE_CONNECTED://設備處于鏈接狀態/** This sets the usb event thread run condition to FALSE, therefor* it must be done before usbredirhost_set_device NULL, as* usbredirhost_set_device NULL will interrupt the* libusb_handle_events call in the thread.*/printf("STATE_CONNECTED --------channel-usbredir.c\n");{SpiceSession *session = spice_channel_get_session(SPICE_CHANNEL(channel));//從SpiceChannel中獲取sessionif (session != NULL)spice_usb_device_manager_stop_event_listening(//停止監聽spice_usb_device_manager_get(session, NULL));//獲取USBmanager即從SpiceSession獲取SpiceUsbDeviceManager}/* This also closes the libusb handle we passed from open_device */usbredirhost_set_device(priv->host, NULL);//清空usbhostlibusb_unref_device(priv->device);//去掉引用計數priv->device = NULL;//清空設備g_boxed_free(spice_usb_device_get_type(), priv->spice_device);//清空priv->spice_device = NULL;priv->state = STATE_DISCONNECTED;//設置狀態為斷開狀態break;} }可以看到在該channel內的device被清空了,首先就是要告知manager停止對該device的事件監聽,退出這個device的事件線程,
spice_usb_device_manager_stop_event_listening如下:void spice_usb_device_manager_stop_event_listening(SpiceUsbDeviceManager *self) {SpiceUsbDeviceManagerPrivate *priv = self->priv;g_return_if_fail(priv->event_listeners > 0);priv->event_listeners--;//運行監聽計數減1printf("priv->event_listeners--= %d-----usb-device-manager.c\n",priv->event_listeners);if (priv->event_listeners == 0)priv->event_thread_run = FALSE;//設置線程運行開關為FALSE用來關閉該線程 }總結
以上是生活随笔為你收集整理的Spice下命令spicy的USB重定向过程分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从智能门锁,看3D视觉的安全性突围
- 下一篇: 也谈USB重定向的方式