U盘重定向读取文件流程和分析
U盘重定向读取文件流程

U盘的重定向流程如上图所示:
- 首先由服务端发送读取的控制指令,该指令只包含要读取逻辑块和长度信息,不做实际读取
- 之后物理机回复服务端,不包含内容。
- 服务端发送真读取的控制指令,读取上一次指定逻辑块和长度信息。(物理机执行耗时1.7ms)
- 物理机将读取的64kb数据发送到服务端。
- 服务端再次发送真读取的控制指令。
- 物理机回应已经读完无剩余的信息发送到服务端。
和物理机相比的耗时点
如上面所述的U盘的重定向流程,可以发现有大量的网络数据控制读取,整个一个64kb的块读取实际的读取耗时只有1.7~2ms附近,但数据控制包的收发延迟远大于实际的读取耗时,造成速度下降,假设延迟为xms。
在上图中忽略虚拟机和物理机处理数据的时间,一个64kb的块读取交互的耗时约为(6x+实际读取64kb的数据的时间),在ping值为17ms的情况下,延迟除2为8.5ms,此时读取的一个64kb的块的耗时必定大于50ms。可以发现大量的时间耗费在控制数据的传输中,导致速度变慢。
USB Camera redirection work processing
USB redirection protocol data packet header
| Data packet type | 0x code format |
|---|---|
| usb_redir_hello | 0x00 |
| usb_redir_device_connect | 0x01 |
| usb_redir_device_disconnect | 0x02 |
| usb_redir_reset | 0x03 |
| usb_redir_interface_info | 0x04 |
| usb_redir_ep_info | 0x05 |
| usb_redir_set_configuration | 0x06 |
| usb_redir_get_configuration | 0x07 |
| usb_redir_configuration_status | 0x08 |
| usb_redir_set_alt_setting | 0x09 |
| usb_redir_get_alt_setting | 0x0A |
| usb_redir_alt_setting_status | 0x0B |
| usb_redir_start_iso_stream | 0x0C |
| usb_redir_stop_iso_stream | 0x0D |
| usb_redir_iso_stream_status | 0x0E |
| usb_redir_start_interrupt_receiving | 0x0F |
| usb_redir_stop_interrupt_receiving | 0x10 |
| usb_redir_interrupt_receiving_status | 0x11 |
| usb_redir_alloc_bulk_streams | 0x12 |
| usb_redir_free_bulk_streams | 0x13 |
| usb_redir_bulk_streams_status | 0x14 |
| usb_redir_cancel_data_packet | 0x15 |
| usb_redir_filter_reject | 0x16 |
| usb_redir_filter_filter | 0x17 |
| usb_redir_device_disconnect_ack | 0x18 |
| usb_redir_start_bulk_receiving | 0x19 |
| usb_redir_stop_bulk_receiving | 0x1A |
| usb_redir_bulk_receiving_status | 0x1B |
| usb_redir_control_packet | 0x64 |
| usb_redir_bulk_packet | 0x65 |
| usb_redir_iso_packet | 0x66 |
| usb_redir_interrupt_packet | 0x67 |
| usb_redir_buffered_bulk_packet | 0x68 |
Display In Wireshark:
Previous data show this packet is usb_redir_device_connect packet and append data length was 10(0x0a) bytes, append data was struct usb_redir_device_connect_header, there are basic information about redirection device. This is a usb_redir_speed_full device, vendor_id is 0x0c45 and product_id is 0x6366 etc.
enum {
usb_redir_speed_low,
usb_redir_speed_full,
usb_redir_speed_high,
usb_redir_speed_super,
usb_redir_speed_unknown = 255
}
struct usb_redir_device_connect_header {
uint8_t speed;
uint8_t device_class;
uint8_t device_subclass;
uint8_t device_protocol;
uint16_t vendor_id;
uint16_t product_id;
uint16_t device_version_bcd;
}
USB redirection work processing
// interface info
struct usb_redir_interface_info_header {
uint32_t interface_count;
uint8_t interface[32];
uint8_t interface_class[32];
uint8_t interface_subclass[32];
uint8_t interface_protocol[32];
}
// binary
05 00 00 00
00 01 02 03 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0e 0e 0e 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 02 02 01 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// endpoint info
enum {
/* Note these 4 match the usb spec! */
usb_redir_type_control,
usb_redir_type_iso,
usb_redir_type_bulk,
usb_redir_type_interrupt,
usb_redir_type_invalid = 255
}
struct usb_redir_ep_info_header {
uint8_t type[32];
uint8_t interval[32];
uint8_t interface[32];
uint16_t max_packet_size[32];
uint32_t max_streams[32];
}
// binary
00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 ff ff 03 ff ff ff ff ff ff ff ff ff ff ff ff
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
When client receive usb redirection channel packet from server will call function spice_usb_backend_read_guest_data -> usbredirhost_read_guest_data -> usbredirparser_do_read -> usbredir_read_callback <- -> usbredirparser_call_type_func . In function usbredirparser_call_type_func will call according function by data packet type.

Previous image show the usb camera redirection whole process, to simple this process, It can be split to 3 part:
- Get general device descriptor (device descriptor, full configuration descriptor), this information tell host how to control this device.
- Get camera special config for video capture, like Gama, brightness. etc.
- Control device use Urb control.
To control a device in usb redirection need use libusb function control transfer, the usb_redir_control_packet struct is
struct usb_redir_control_packet_header {
uint8_t endpoint;
uint8_t request;
uint8_t requesttype;
uint8_t status;
uint16_t value;
uint16_t index;
uint16_t length;
}
libusb_control_setup Struct
uint8_t bmRequestType
uint8_t bRequest
uint16_t wValue
uint16_t wIndex
uint16_t wLength
bmRequestType
Bits 0:4 determine recipient, see libusb_request_recipient. Bits 5:6 determine type, see libusb_request_type. Bit 7 determines data transfer direction, see libusb_endpoint_direction.
libusb_endpoint_direction
| Enumerator | description |
|---|---|
| LIBUSB_ENDPOINT_OUT | Out: host-to-device. |
| LIBUSB_ENDPOINT_IN | In: device-to-host. |
libusb_request_type
| Enumerator | description |
|---|---|
| LIBUSB_REQUEST_TYPE_STANDARD | Standard. |
| LIBUSB_REQUEST_TYPE_CLASS | Class. |
| LIBUSB_REQUEST_TYPE_VENDOR | Vendor. |
| LIBUSB_REQUEST_TYPE_RESERVED | Reserved. |
libusb_request_recipient
| Enumerator | description |
|---|---|
| LIBUSB_RECIPIENT_DEVICE | Device. |
| LIBUSB_RECIPIENT_INTERFACE | Interface. |
| LIBUSB_RECIPIENT_ENDPOINT | Endpoint. |
| LIBUSB_RECIPIENT_OTHER | Other. |
bRequest
If the type bits of bmRequestType are equal to LIBUSB_REQUEST_TYPE_STANDARD then this field refers to libusb_standard_request. For other cases, use of this field is application-specific.
libusb_standard_request
| Enumerator | description |
|---|---|
| LIBUSB_REQUEST_GET_STATUS | Request status of the specific recipient. |
| LIBUSB_REQUEST_CLEAR_FEATURE | Clear or disable a specific feature. |
| LIBUSB_REQUEST_SET_FEATURE | Set or enable a specific feature. |
| LIBUSB_REQUEST_SET_ADDRESS | Set device address for all future accesses. |
| LIBUSB_REQUEST_GET_DESCRIPTOR | Get the specified descriptor. |
| LIBUSB_REQUEST_SET_DESCRIPTOR | Used to update existing descriptors or add new descriptors. |
| LIBUSB_REQUEST_GET_CONFIGURATION | Get the current device configuration value. |
| LIBUSB_REQUEST_SET_CONFIGURATION | Set device configuration. |
| LIBUSB_REQUEST_GET_INTERFACE | Return the selected alternate setting for the specified interface. |
| LIBUSB_REQUEST_SET_INTERFACE | Select an alternate interface for the specified interface. |
| LIBUSB_REQUEST_SYNCH_FRAME | Set then report an endpoint’s synchronization frame. |
| LIBUSB_REQUEST_SET_SEL | Sets both the U1 and U2 Exit Latency. |
| LIBUSB_SET_ISOCH_DELAY | Delay from the time a host transmits a packet to the time it is received by the device. |
