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

U盘重定向读取文件流程

U_disk.drawio.png

U盘的重定向流程如上图所示:

  1. 首先由服务端发送读取的控制指令,该指令只包含要读取逻辑块和长度信息,不做实际读取
  2. 之后物理机回复服务端,不包含内容。
  3. 服务端发送真读取的控制指令,读取上一次指定逻辑块和长度信息。(物理机执行耗时1.7ms)
  4. 物理机将读取的64kb数据发送到服务端。
  5. 服务端再次发送真读取的控制指令。
  6. 物理机回应已经读完无剩余的信息发送到服务端。

和物理机相比的耗时点

如上面所述的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:
5.jpg

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.

network.png

Previous image show the usb camera redirection whole process, to simple this process, It can be split to 3 part:

  1. Get general device descriptor (device descriptor, full configuration descriptor), this information tell host how to control this device.
  2. Get camera special config for video capture, like Gama, brightness. etc.
  3. 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.